Reputation: 3707
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
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
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