Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

I want to upload an image file from dynamically generated HTML form using ng-repeat. I am using ng-file-upload module to upload the single image file (https://github.com/danialfarid/ng-file-upload). When I am uploading file from static HTML its working fine. But when I try to upload the file from dynamically generated HTML then it wont work as expected. The file is not uploading and also giving error in firefox console as follows :

Error: Argument 2 of FormData.append is not an object.

The form is successfully submitted if we assign ng-model of file control set to null. for example; if

<input name='img' type='file' value='' ng-model='data.imageFile' 'ngf-select' accept='image/*' />

and

$scope.data.imageFile = null;

then other parameters will submitted by HTTP service and store to database normally but file will not going to upload.

Is any way to assign file object to the input[type=file] in this case of dynamically generated HTML??

The code PLUNKER is created here

http://plnkr.co/edit/S7hnVJnuDjWUMQ6PYewk?p=preview

share|improve this question
    
Try ng-model=$parent.data.imageFile. You might be adding it to a different scope. For a workaround you can add directive ngf-change=upload($file) – danial Aug 6 '15 at 18:25
    
I drop this idea which I was using before, and go with ng-repeat in view itself. Now it just working fine, but there is another error in ng-upload plugin and I got the solution for that also. – kishor10d Aug 11 '15 at 17:50

Yes there is a way to assign input type=file to dynamically generated html. Not just dynamically generated when the page load, but also when adding new input type=file via angular. I just did this and it worked!!! and I'm so excited I post all the tricks here. All I'm asking in return is please Vote up when you get it working in your solution. Both the question and the Answer are at 0 point now, but I can prove that this is a working solution.

     <input type="file" class="form form-control" placeholder="Section Image" file-model2="fileUploadFile2[getImageIndex(c.ChapterNbr, $index)][$index]" />

Notice that have two dimension array and this input=file goes inside ng-repeat within ng-repeat, dynamically added when user presses the +Add button.

on the angular side, in getImageIndex:

        var chIndex = 0;
        var sIndex = 0;

        $scope.getImageIndex = function (chNbr, sectionNbr) {
            for (var i = 0; i < $scope.chapters.length; i++) {
                if ($scope.chapters[i].ChapterNbr == chNbr) {
                    chIndex = i;
                    sIndex = sectionNbr;
                    return i;
                };
            };
        };

This is purely to get the indexes (first and second dimension, specific to my setup). I use directive posted somewhere in StackOverflow that I'm thankful for, to actually get the file bytes and info, and it goes like this:

       .directive('fileModel2', ['$parse', function ($parse) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                element.bind('change', function (e) {
                    $parse(attrs.fileModel2)
                    .assign(scope, element[0].files[0]);
                    scope.$apply();
                    scope.getFile2(scope.$eval(attrs.indexNumber));
                });
            }
        };
    }])
    .factory('fileReaderFactory', function ($q, $log) {
        return {
            onLoad: function (reader, deferred, scope) {
                return function () {
                    scope.$apply(function () {
                        deferred.resolve(reader.result);
                    });
                };
            },
            onError: function (reader, deferred, scope) {
                return function () {
                    scope.$apply(function () {
                        deferred.reject(reader.result);
                    });
                };
            },
            onProgress: function (reader, scope) {
                return function (event) {
                    scope.$broadcast("fileProgress",
                        {
                            total: event.total,
                            loaded: event.loaded
                        });
                };
            },
            getReader: function (deferred, scope) {
                var reader = new FileReader();
                reader.onload = this.onLoad(reader, deferred, scope);
                reader.onerror = this.onError(reader, deferred, scope);
                reader.onprogress = this.onProgress(reader, scope);
                return reader;
            },

            readAsDataURL: function (file, scope) {
                var deferred = $q.defer();

                var reader = this.getReader(deferred, scope);
                reader.readAsDataURL(file);

                return deferred.promise;
            }
        }
    }
    );

The directive triggers getFile2, which executes the Filereader to read the bytes fore previewing the image. Finally, to preview the image:

         $scope.getFile2 = function () {
            console.log($scope.fileUploadFile2[chIndex][sIndex]);
            if ($scope.fileUploadFile2[chIndex][sIndex]) {
                fileReaderFactory.readAsDataURL($scope.fileUploadFile2[chIndex][sIndex], $scope)
                    .then(function (result) {
                        $scope.chapters[chIndex].Sections[sIndex].sectionImgPreview = result;
                    });
            }
        };

and here is the html to preview the image:

     <img ng-if="s.sectionImgPreview" class="img-responsive" ng-src="{{s.sectionImgPreview}}" alt="" onerror="this.src='@Url.Content("~/Content/Images/ToyApp.png")';" />

At this point, $scope.fileUploadFile2[chIndex][sIndex] is ready to post to the back end, which, in my case, is a C# Controller that accept the entire JSON containing Course Chapters and sections, image binaries and videos, text and html, into a complex class that will in turn store the information into the database schema.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.