Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a question for all you AngularJs gurus out there. I am attempting to create modal wherein a user can submit files for upload. I have most of the problem sorted, however, I seem to be running into issues concerning scope. The technologies I am using are Angularjs, Angular UI Bootstrap and a custom file model directive.

I have a custom fileModel directive which on file selection updates the scope:

app.directive('fileModel', ['$parse', function($parse) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var model = $parse(attrs.fileModel);
            var modelSetter = model.assign;
            element.bind('change', function() {
                scope.$apply(function() {
                    modelSetter(scope, element[0].files[0]);
                });
            });
        }
    }
}]);

I use UI bootstrap to create the modal as per the documentation (http://angular-ui.github.io/bootstrap/#/modal). Please note the file-model="file" directive in the input field, this is what I am trying to access.

<div ng-controller="ModalDemoCtrl">

    // Button to open model
    <button class="btn btn-default" data-ng-click="open()">Upload File</button>

    // Simple Form in model
    <script type="text/ng-template" id="myModalContent.html">
        <form name="form.myForm" class="form-horizontal" data-ng-submit="addFile()" role="form" novalidate>

            <div class="modal-header">
                <h3 class="modal-title">Upload File</h3>
            </div>
            <div class="modal-body">
                <div class="form-group">
                    <label for="file" class="col-sm-2 control-label">Input File</label>
                    <div class="col-sm-10">
                        <input type="file" name="file" file-model="file">               
                    </div>
                </div>  
            </div>
            <div class="modal-footer">
                <button type="submit" class="btn btn-default">Submit</button>
            </div>

       </form>
   </script>

</div>

Lastly I have the controller(s), again as per the Bootstrap UI documentation. Please note where I try to access $scope.file.

app.controller('ModalDemoCtrl', ['$scope', '$http', '$modal', function ($scope, $http, $modal) {

    $scope.open = function () {

        var modalInstance = $modal.open({
            templateUrl: 'myModalContent.html',
            controller: ModalInstanceCtrl,
            resolve: {
                $http: function () {
                    return $http;
                }
            }
        });

        modalInstance.result.then(function () {
            // do something
        }, function () {
            // do something
        });
    };

}]);

var ModalInstanceCtrl = function ($scope, $modalInstance, $http) {

$scope.addFile = function() {
    var formData = new FormData();
    formData.append('file', $scope.file);
    $http.post(            
        '/valid/ajax/url', formData, {
            transformRequest: angular.identity,
            headers: {'Content-Type': undefined}
        }).success(function(data, status, headers, config) {
            // do something on success
        });
    );
};

I know there are some issues with regards to scope within modals when using angular UI bootstrap... unfortunately I am not experienced enough to find a solution. Currently, I am unable to access the file a user selects to be sent via ajax. Please help. Thanks.

share|improve this question

1 Answer 1

up vote 2 down vote accepted

I saw that the variable "$scope.file" is not being set, it stays undefined. Therefore you can't post the file. An easy way to share data between controllers (you have two, the modal controller and you parent controller) is using a service or factory. Check documentation if you are not sure. Then you can change the save the file via service/factory and use it in both controllers.

First of all the service which just contains a getter and a setter:

app.service('fileService', function () {
    var file;
    var fileService = {};

    fileService.getFile = function () {
        return file;
    };

    fileService.setFile = function (newFile) {
        file = newFile;
    };

    return fileService;
});

You can then use the service via dependency injection on the directive and the controller:

app.directive('myFileUpload', function (fileService) {
    return function (scope, element) {
        element.bind('change', function () {
            fileService.setFile(element[0].files[0]);
        });
    }
});

app.controller('ModalInstanceCtrl', function ($scope, $modalInstance, $http, fileService) {

    $scope.addFile = function () {
        var file = fileService.getFile();
        console.log(file);
        $http.post(
            'http://posttestserver.com/post.php', file, {
                transformRequest: angular.identity,
                headers: {'Content-Type': file.type}
            }).success(function (data, status, headers, config) {
                console.log(data);
            });
    };
});

I created a fiddle so you can test it there. The file is outputted on the console. For testing the post I used http://posttestserver.com/post.php

http://jsfiddle.net/dz5FK/

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.