joy
joy

Reputation: 3707

Angular js data binding doesn't update view intermittently

I am using Angular js directive and bind data to display in view. I have conditional view. I am using same view to read the data as well as edit the data. I manage a flag edit=true and using ng-switch on flag "edit" i change the view.

It works well in most of time; however I realized that some how view doesn't get updated even if data behind the scene get's update. What i does basically; on click "ok" button in edit mode; using ng-click i changed flag edit=undefined and since data gets changed therefore my assumption is it will change the view. It certainly works in most time however suddenly stop working. I checked the console by printing data and I see the ng-click is actually updating flag correctly. Following are excerpt on code.

View code*[Updated]*:

<!--In case of edit render it as text box-->
                <ng:switch on="file.edit">
                <div ng:switch-when="true">

                        <input type="text" ng-model="file.name"  class="file-label" value="{{file.name}}" />   
                        <i class="icon-ok" ng-click="addFile({{$index}})"></i>
                        <i class="icon-remove" ng-click="cancelAddFile({{$index}})"></i>

                </div>          
                <div ng:switch-when="undefined">
                    <!--if it is not edit case then render as label-->


                    <!--Add file name as a label-->                                 
                    <span class="file-label" >{{file.name}}</span>                                                           




                </div>

                </ng:switch>

Following is excerpt of directive code*[Updated]*.

//project directive as element for project contents
app.directive("projectcontents", ['Contents', function (projectContents) {
    return {
        restrict: "E",
        templateUrl: "/xopus/view/projectstructure/ProjectContents.html",
        replace: true,
        scope: {
            project: '='
        },
        link: function (scope, element, attrs) {


            /*Edit file in project*/
            scope.editFile = function (fileIndex) {
                //print log for debug purpose
                console.log("Edit file at index " + fileIndex);                
                //make service call

                //update edit flag
                scope.files[fileIndex].edit = true;

            };

            /*Remove file in project*/
            scope.deleteFile = function (fileIndex) {
                //make service call
                //print log for debug purpose
                console.log("Remove file at index " + fileIndex);  
                //Remove this file entry form data model
                scope.files.splice(fileIndex, 1);

            };



            /*Add file in project*/
            scope.addFile = function (fileIndex) {
                //print log for debug purpose
                console.log("Add file at index " + fileIndex);  
                //make service call

                //update data binding to update edit=false


                //update edit flag
                scope.files[fileIndex].edit = undefined;

            };


            /*Cancel add file */
            scope.cancelAddFile = function (fileIndex) {
                //print log for debug purpose
                console.log("Cancel file at index " + fileIndex);  
                //Remove this file entry form data model
                scope.files.splice(fileIndex, 1);
            };



        }
    };
} ]);

I am still learning Angular and I am sure doing some basic mistake. Please help.

Upvotes: 2

Views: 1300

Answers (2)

joy
joy

Reputation: 3707

I have fixed this issue by using "fileId" instead of "$index" generated by Angular. It seems that the scope logic explained by callmekatootie is causing some issue to update $index. I am not sure where exactly i need to change to fix the $index issue therefore i changed my logic to use fileId (instead of $index) and now it is working fine. Following is modified addFile()

/*Add file in project*/
            scope.addFile = function (fileId) {                
                //find out index of given file ID
                var fileIndex = scope.getFileIndex(fileId);
                //update data binding to update edit=false              
                scope.files[fileIndex].edit = undefined;

            };


 /*Get Index of file in files object */
            scope.getFileIndex = function (fileId) {
                //print log for debug purpose
                console.log("Get file index for fileId " + fileId);
                //find out index of given file ID
                var fileIndex = undefined;
                for (var i = 0; i < scope.files.length; i++) {
                    if (scope.files[i]._id === fileId) {
                        fileIndex = i;
                        break;
                    }
                }

                return fileIndex;
            };

not sure if this is perfect way or not.

Upvotes: 1

callmekatootie
callmekatootie

Reputation: 11228

Why the view does not update correctly

The following is how the scope of the controller looks like initially:

//Parent scope
$scope = {
   ...
   files: [..]
   ...
}

Now when you add the ng-switch directive, this directive creates a new scope. This scope inherits all the properties of the parent scope:

//Child scope
$scope = {
    ...
    files: [...]
    ...
}

Note that it has the files property / model too - this is bound to the files property of the parent scope. However, this is a one way binding - updates to the parent will be reflected in the child but updates to the child will not be reflected in the parent.

Now, when the click happens and you wish to switch to display mode from edit mode, what happens is that you are changing the files property of the child scope and not the parent scope - the file on the parent scope is still in the "edit" mode - the ng-switch directive is still referencing the file property on the parent scope and thus the switch does not happen.

How to fix this issue
When I requested you to remove the unnecessary code, that was only for legibility and easier understanding and that was not the solution. You have updated your code well which led to the cause of the issue. However, there are still some lose ends. For example, how are you defining the files model of the scope? It does not seem to be defined in the directive - only modified. Can you provide that information?

In the meantime, if my analysis of the issue is correct, then replace occurrence of scope.files inside the addFile function with scope.$parent.files - I think that should do the trick - it should update the state of the file in the parent controller's scope and thus should be picked up by the ng-switch directive, thus updating your view correctly.

Upvotes: 1

Related Questions