Horaciodev
Horaciodev

Reputation: 13

angularjs - Sharing data between controllers through service

I have a 2 controllers [FirstController,SecondController] sharing two arrays of data (myFileList,dummyList) through a service called filecomm. There is one attribute directive filesread with isolated scope that is bound to a file input in order to get the array of files from it. My problem is that myFileList array in my service never gets updated when I select the files with the input. However, dummyList array gets updated immediately in the second div (inner2). Does anybody know why is this happening? For some reason in the second ngrepeat when I switch from (fi in secondCtrl.dummyList) to (fi in secondCtrl.myFileList) it stops working. Any help would be greatly appreciated.

Markup

<div ng-app="myApp" id="outer">
<div id="inner1" ng-controller="FirstController as firstCtrl">
<input type="file" id="txtFile" name="txtFile" 
maxlength="5" multiple accept=".csv" 
filesread="firstCtrl.myFileList"
update-data="firstCtrl.updateData(firstCtrl.myFileList)"/>
    <div>
        <ul>
            <li ng-repeat="item in firstCtrl.myFileList">
                <fileuploadrow my-file="item"></fileuploadrow>
            </li>
       </ul>
    </div>
    <button  id="btnUpload" ng-click="firstCtrl.uploadFiles()"
     ng-disabled="firstCtrl.disableUpload()">Upload
     </button>     
</div>
    <div id="inner2" ng-controller="SecondController as secondCtrl">
        <ul ng-repeat="fi in secondCtrl.dummyList">
            <li>Hello</li>
        </ul>    
    </div>    
</div>

JS

angular.module('myApp', [])
.controller('FirstController',
['$scope','filecomm',function ($scope,filecomm) {
    this.myFileList = filecomm.myFileList; 

    this.disableUpload = function () {
    if (this.myFileList) {
        return (this.myFileList.length === 0);
    }
    return false;
};

    this.uploadFiles = function () {
        var numFiles = this.myFileList.length;
        var numDummies = this.dummyList.length;
        filecomm.addDummy('dummy no' + numDummies + 1);
        console.log('Files uploaded when clicked:' + numFiles);
        console.log('dummy is now:'+ this.dummyList.length);
        };

    this.updateData = function(newData){
        filecomm.updateData(newData);
        console.log('updated data first controller:' + newData.length);
    };

    this.dummyList = filecomm.dummyList;

    console.log('length at init:' + this.myFileList.length);
}]) //FirstController

.controller('SecondController', 
 ['$scope', 'filecomm', function($scope,filecomm) {
    var self = this;
    self.myFileList = filecomm.myFileList;

    self.dummyList = filecomm.dummyList;

    console.log('SecondController myFileList - length at init:' +
    self.myFileList.length);
    console.log('ProgressDialogController dummyList - length at init:' + 
    self.dummyList.length);
}])  //Second Controller

.directive('filesread',[function () {
    return {
        restrict: 'A',
        scope: {
            filesread: '=',
            updateData: '&'
        },
        link: function (scope, elm, attrs) {

            scope.$watch('filesread',function(newVal, oldVal){
                console.log('filesread changed to length:' +  
                             scope.filesread.length);

        });

            scope.dataFileChangedFunc = function(){
                scope.updateData();
                console.log('calling data update from directive:' +   
                scope.filesread.length);
            };

            elm.bind('change', function (evt) {


                scope.$apply(function () {

                    scope.filesread = evt.target.files;

                    console.log(scope.filesread.length);
                    console.log(scope.filesread); 


                });

                scope.dataFileChangedFunc();

            });



        }
    }
}])    //filesread directive

.directive('fileuploadrow', function () {
    return {
        restrict: 'E',
        scope: {
            myFile: '='
        },
        template: '{{myFile.name}} - {{myFile.size}} bytes'
    };

})  //fileuploadrow directive

.service('filecomm', function FileComm() {
    var self = this;;

    self.myFileList = [];

    self.dummyList = ["item1", "item2"];

    self.updateData = function(newData){
    self.myFileList=  newData;
    console.log('Service updating data:' + self.myFileList.length);
    };

    self.addDummy = function(newDummy){
    self.dummyList.push(newDummy);
    };

});  //filecomm service

Please see the following JSFiddle How to test:

select 1 or more .csv file(s) and see each file being listed underneath. For each file selected the ngrepeat in the second div should display Hello. That is not the case. Change the ngrepat in the second div to secondCtrl.dummyList Once you select a file and start clicking upload, you will see that for every click a new list item is added to the ul. Why does dummyList gets updated and myFileList does not?

Upvotes: 0

Views: 164

Answers (1)

Nicholas J. Markkula
Nicholas J. Markkula

Reputation: 1572

You had a couple of issues.

First, in the filecomm service updateData function you were replacing the list instead of updating it.

Second, the change wasn't updating the view immediately, I solved this by adding $rootScope.$apply which forced the view to update.

Updated JSFiddle, let me know if this isn't what you were looking for https://jsfiddle.net/bdeczqc3/76/

.service('filecomm', ["$rootScope" ,function FileComm($rootScope) {
    var self = this;
    self.myFileList = [];

    self.updateData = function(newData){
        $rootScope.$apply(function(){
            self.myFileList.length = 0;
            self.myFileList.push.apply(self.myFileList, newData);
            console.log('Service updating data:' + self.myFileList.length);
        });        
    };    

}]);  //filecomm service

Alternately you could do the $scope.$apply in the updateData function in your FirstController instead of doing $rootScope.$apply in the filecomm service.

Alternate JSFiddle: https://jsfiddle.net/bdeczqc3/77/

this.updateData = function(newData){
    $scope.$apply(function(){
        filecomm.updateData(newData);
        console.log('updated data first controller:' + newData.length);
    });
};

Upvotes: 1

Related Questions