angularjs Custom directive fileupload base64

723 Views Asked by At

I would like to write a directive handling the file upload (base64 of a file) that relies on ng-flow I was able to make the directive working without using the ngModel (binding f to scope.f :P) but since I need to use this directive inside a form it would be better to have it (and also the possibility to use ng-change is a really nice to have features)

angular.module('webappApp.common.directives',['flow','pascalprecht.translate', 'tmh.dynamicLocale']).
directive('ngBase64FileUpload',function(){
    return {
        restrict: 'A',
        templateUrl: 'common/partials/base64FileUpload.tpl.html',
        require: '^ngModel',
        scope:{
            blur:'&fieldBlur',
            focus:"&fieldFocus",
            filename:"="

        },
        link: function (scope, element, attrs, ctrl) {
            console.log(scope);
            scope.processFiles = function (files) {
                console.log(files);
                var flowFile=files[0];
                //angular.forEach(files, function (flowFile, i) {
                    var fileReader = new FileReader();
                    fileReader.onload = function (event) {
                        var f ={};
                        //var f=event.target.result;
                        f.uri=event.target.result;
                        f.size=flowFile.size;
                        f.filename=flowFile.name;
                        ctrl.$setViewValue(f);
                    };
                    fileReader.readAsDataURL(flowFile.file);
                //});
            }
        }
    }
});

the template is

<div class="input-group col-xs-12" flow-init="{singleFile:true}" flow-files-added="processFiles($files)">
 <p class="input-pos-field form-control no-border nomargin" ng-if="!f"> {{filename|translate}}</p>
 <p class="input-pos-field form-control no-border nomargin" ng-if="f"> <a ng-href="{{f.uri}}" download>{{f.filename|translate}}</a></p>
<span class="input-group-btn">
    <button type="button" class="icon_file" flow-btn><img src="images/file_icon.png" width="30"/><input ng-blur="blur($event)" ng-focus="focus($event)" type="file" class="hide"></button>
</span>

after making that directive working i have to add also the "readonly" options that simply allow only to download the file well if i understand how it would be nice also to change a little the template (button image)

I'm finding some problem about understand how use correctly the ngModel/parser/formatter/viewValue in order to write a flexible and reusable directive

---- edit directive seems to be working now but i have problem to handle correclty the template (display filename or the default if no file is uploaded) the next step that i have to do is to change the behavour if the ng-disabled is passed (or readonly but doing the first the second is almost equals) basically the directive need to use a different icon in the button (and do not allow to upload a file but only to download it) plunker

1

There are 1 best solutions below

1
kicken On

You use the ngModel.$render function to accept read the value assigned to the model and update your directives state or UI accordingly. When you have a new value you want to push to the model then you call ngModel.$setViewValue.

For example:

scope.f = null;

ctrl.$render = function(){
    scope.f = angular.copy(ctrl.$viewValue);
};

scope.processFiles = function (files) {
    console.log(files);
    var flowFile=files[0];
    //angular.forEach(files, function (flowFile, i) {
    var fileReader = new FileReader();
    fileReader.onload = function (event) {
        var f ={};
        //var f=event.target.result;
        f.uri=event.target.result;
        f.size=flowFile.size;
        f.filename=flowFile.name;

        ctrl.$setViewValue(f);
    };
    fileReader.readAsDataURL(flowFile.file);
    //});
}

I use angular.copy to create a duplicate of objects to ensure that changing a property on the object within the directive doesn't result it the change showing outside the directive. Changes should only propagate out of the directive when $setViewValue is called.