Closed SagiMedina closed 9 years ago
I tried lx-file-input
quite a while back, it seemed a bit undercooked. I've been resorting to using a raw javascript file-inputer.
Have you been able to get a working demo with lx-file-input
?
well, It seems fine here: http://ui.lumapps.com/directives/file-inputs I wonder way not use it in your template...
The file-input looks pretty, but how do you manipulate/save the loaded data? There's no example for the javascript behind the scenes.
This is what i had in mind: A watcher will call someMethod in the controller where one can manipulate/save the loaded data. The model will be fill with the url that returned from someMethod^
There are two missing pieces, One - once you choose a file it will automatically upload it - maybe we should consider a button? Two - we will need to add a small circular progress untill the model will be fill with the url - http://ui.lumapps.com/services/progress
Would you like to make a demo? You can create your own custom templates using Angular Formly.
Templates should be as flexible as possible, as users may want to make their own design choices.
In addition to the example on the website, you can also watch the newly released lesson about custom templates http://docs.angular-formly.com/v6.1.0/docs/learn-angular-formly#-custom-templates-https-egghead-io-lessons-angularjs-angular-formly-custom-templates- from egghead.io!
-Kent C. Dodds
On Tue, Apr 28, 2015 at 6:29 AM, ShMcK notifications@github.com wrote:
Would you like to make a demo? You can create your own custom templates http://angular-formly.com/#/example/custom-types/custom-templates using Angular Formly.
Templates should be as flexible as possible, as users may want to make their own design choices.
— Reply to this email directly or view it on GitHub https://github.com/formly-js/angular-formly-templates-lumx/issues/12#issuecomment-97045862 .
thanks... this is what i want to do:
<lx-file-input model="::model[options.key]"
ng-change="::to.uploadFunction(::model[options.key])"
label="{{to.label}} {{::to.required ? '*' : ''}}">
</lx-file-input>
Wow, great work @kentcdodds ! Angular-Formly is really coming along.
@SagiMedina <lx-file-input>
has a built-in attribute for change you can use.
See this LumX issue.
<lx-file-input change="to.uploadFunction"></lx-file-input>
$scope.uploadFunction(element) {
console.log(element);
}
FYI, you don't need to add an ng-change directive. Simply add templateOptions.onChange and angular-formly will add the ng-change directive for you :-)
-Kent C. Dodds
On Tue, Apr 28, 2015 at 6:46 AM, SagiMedina notifications@github.com wrote:
thanks... this is what i want to do:
<lx-file-input model="::model[options.key]" ng-change="::to.uploadFunction(::model[options.key])" label="{{to.label}} {{::to.required ? '*' : ''}}">
— Reply to this email directly or view it on GitHub https://github.com/formly-js/angular-formly-templates-lumx/issues/12#issuecomment-97049572 .
Ah hah! If you have a custom attribute, you could potentially add the ngModelAttrs to the defaultOptions of your type. See http://docs.angular-formly.com/v6.1.0/docs/ngmodelattrs
But it may be easier to just add the change directive yourself :-)
-Kent C. Dodds
On Tue, Apr 28, 2015 at 7:00 AM, ShMcK notifications@github.com wrote:
Wow, great work @kentcdodds https://github.com/kentcdodds ! Angular-Formly is really coming along.
@SagiMedina https://github.com/SagiMedina
has a built-in attribute for change you can use. See this LumX issue https://github.com/lumapps/lumX/issues/25.
$scope.uploadFunction(element) { console.log(element); }
— Reply to this email directly or view it on GitHub https://github.com/formly-js/angular-formly-templates-lumx/issues/12#issuecomment-97053155 .
@kentcdodds I think I will have to use the ngModelAttrs since I can't use braces in lx-file-input's change attribute. But I'm having a hard time with that, don't understand the example that you gave... Can you please help me?
<lx-file-input label="someLabel" change="uploadFunction(element)"></lx-file-input>
All I need is to add the change attribute, with ngModelAttrs and bind it to a uploadFunction(element) that is implemented in the controller.
Sorry for the delay. So, Here is my solution: (you get lumx file input with linear progress while the file is uploading and two buttons once its finish, one for download and one for delete or change file).
app.config.js:
(function () {
'use strict';
angular
.module('app')
.config(config);
config.$inject = ['formlyConfigProvider'];
function config(formlyConfigProvider){
formlyConfigProvider.setType({
name: 'lx-file-input',
templateUrl: '/static/app/blocks/file_input_formly/file_input_formly.html'
});
}
})();
file_input_formly.html:
<div flex-item>
<div ng-hide="model[options.key].hasFile">
<file-upload controller="{{::to.controller}}"
controller-as="{{::to.controllerAs}}"
upload-function="{{::to.uploadFunction}}"
label="{{::to.label}} {{::to.required ? '*' : ''}}">
</file-upload>
</div>
<div id="{{ this.options.key }}"></div>
<div ng-if="model[options.key].hasFile" style="padding: 25px 0 15px">
<a href="{{ ::model[options.key].url }}" target="_blank" class="btn btn--m btn--blue btn--raised" lx-ripple> {{::to.downloadBtn}} {{::to.label}}</a>
<button ng-click="model[options.key].hasFile = null" class="btn btn--m btn--blue btn--flat" lx-ripple>{{::to.replaceBtn}}</button>
</div>
</div>
file_upload_directive.js:
(function () {
'use strict';
angular
.module('app')
.directive('fileUpload', fileUpload);
fileUpload.$inject = ['$compile'];
/* @ngInject */
function fileUpload($compile) {
var directive = {
restrict: 'E',
link: link
};
return directive;
function link(scope, element, attrs) {
directive.controller = attrs.controller;
directive.controllerAs = attrs.controllerAs;
var htmlText = '<lx-file-input ' +
'change="'+attrs.controllerAs+'.'+attrs.uploadFunction+'" ' +
'label="'+attrs.label+'"></lx-file-input>';
element.replaceWith($compile(htmlText)(scope));
}
}
})();
formly input:
{
"key": "someFile",
"type": "lx-file-input",
"templateOptions": {
"controller": "worker",
"controllerAs": "workerCtrl",
"uploadFunction": "fileUpload(e, this.options)",
"downloadBtn": "Download",
"replaceBtn": "Delete/Replace",
"label": "This is some file input"
}
}
controller.js:
(function () {
'use strict';
angular
.module('app.worker')
.controller('worker', worker);
worker.$inject = ['$q', 'LxProgressService', '$scope', 's3upload'];
function worker($q, LxProgressService, $scope, 's3upload') {
var vm = this;
vm.worker = {};
vm.formData = {};
vm.fileUpload = fileUpload;
activate();
////////////////
function activate() {
$scope.$on('fileChange', function(event, data){
LxProgressService.linear.hide('#'+data.model);
vm.worker[data.model] = {};
vm.worker[data.model].url = data.value.replace(/%2F/g, '/');
vm.worker[data.model].hasFile = true;
});
}
function fileUpload(file, options){
var model = options.key;
LxProgressService.linear.show('#5fa2db', '#'+model);
$q.when(s3upload.uploadFile(file, vm.worker.id)).then(function(url){
var data = { model: model, value: url.data};
$scope.$emit('fileChange', data);
});
}
}
})();
I will provide screen shots later.
Great! Could I add this to the example demos? If so, I'll post credit underneath such as a link to your twitter, etc.
Sure! I hope it will come in use. You can add my mail for those who want help with this. SagiMedina@Gmail.com My twitter account is inactive ☺
Thanks again SagiMedina, I've posted your quite thorough example in the demos section, you can see it here: https://af-lumx.herokuapp.com/#/fileInput
Let me know if you'd rather I remove the email.
I had to comment out parts of the code in the demo, otherwise I would be saving random files to my server. Thanks again! If you come up with any more demos, send them this way.
@ShMcK I should be thanking you! Your template is awesome. Let me know if you want me to write another example, one that will fit your examples.
Thanks! Anything you come across that you wasn't clear or easy to do, an example would always help others. I'll close this issue.
Hi everyone,
I'm tryng to implement this solution using requirejs and it seems that the neither the "activate" and "fileUpload" functions inside de controller.js file are called. The value of the input field is not loaded into the model too.
Also the demo in https://af-lumx.herokuapp.com/#/fileInput seems to have the same problems.
Are you sure this solution works? Can you provide an example using requirejs?
Thank you very much!!
The solution provided requires an Amazon S3 account, which is not activated here. Any working example would require an Amazon account & some data fees, neither of which I'm currently paying for.
Take a look again at the code behind the example for an idea of how you might be able to implement it on your own server account. Actually, this solution was thankfully contributed by another user, but I've been told that it works.
The example using Webpack, but the working code should be the same as require.js.
@ciclick First you need to add your custom directive to formly:
(function () {
'use strict';
angular
.module('YOUR_MODULE')
.config(config);
config.$inject = ['formlyConfigProvider'];
function config(formlyConfigProvider){
formlyConfigProvider.setType({
name: 'lx-file-input',
templateUrl: '/static/app/blocks/file_input_formly/file_input_formly.html'
});
}
})();
Looks something like this:
<div flex-item>
<file-upload upload-function="{{::to.uploadFunction}}"
label="{{::to.label}} {{::to.required ? '*' : ''}}">
</file-upload>
</div>
The custom directive will use lumx directive and it will emit function in your controller once file has been chosen:
(function () {
'use strict';
angular
.module('YOUR_MODULE')
.directive('fileUpload', fileUpload);
fileUpload.$inject = ['$compile'];
/* @ngInject */
function fileUpload($compile) {
var directive = {
restrict: 'E',
scope: {
uploadFunction: '@',
label:'@'
},
link: link,
controller:controller
};
return directive;
function link(scope, element, attrs) {
var htmlText = '<lx-file-input ' +
'change="fileUpload(e)" ' +
'label="'+attrs.label+'"></lx-file-input>';
element.replaceWith($compile(htmlText)(scope));
}
function controller($scope){
$scope.fileUpload = function(file){
var functionToEmit = $scope.uploadFunction.toString();
var data = { file: file, scope: $scope};
$scope.$emit(functionToEmit , data);
}
}
}
})();
And in your controller you need to 'wait' for that event:
(function () {
'use strict';
angular
.module('YOUR_MODULE')
.controller('YOUR_CONTROLLER', YOUR_CONTROLLER);
YOUR_CONTROLLER.$inject = ['$scope''];
function YOUR_CONTROLLER($scope) {
var vm = this;
vm.activate = activate;
activate();
////////////////
function activate() {
$scope.$on('YOUR_CONTROLLER_EVENT', function(event, data){
fileUpload(data.file);
});
}
function fileUpload(file, options){
YOUR_UPLOAD_CODE_HERE
}
})();
Of course in your json you will need label and uploadFunction which is the YOUR_CONTROLLER_EVENT
Hope it is clear enough...
You explained it very well and it works perfect! I just have to do some little changes to adapt it to requirejs.
Thank you very much SagiMedina!!!
Hi everyone,
I've another problem now. I want to generate formly-forms dinamically with a file-upload in this forms using ng-repeat. Each form is multiplied depending on an array (in my example vm.idioms). What I want is when the user fills the input fields the model become filled like this:
vm.model = { blocks: { block0: { ca: {Image: xxx.jpg}, es: {Image: xxx.jpg}, en: {Image: xxx.jpg} }, block1: { ca: {Image: xxx.jpg}, es: {Image: xxx.jpg}, en: {Image: xxx.jpg} } }
The problem is the function fileUpload() that assigns the return value to the model doesn't have the correct path (vm.model.blocks.blockx.xx) and I can't figure out how to pass it to the function.
Can you help me?
Here a working jsbin example: http://jsbin.com/muqaqezavo/1/edit?html,js,console,output
Thank you very much!
Hi, Did you consider to add lx-file-input as a field option?