I've created a controller in Angular that looks like this (edited for brevity):
function AppCtrl($scope, $http, $location, $dataService) {
$scope.projects = $dataService.data.projects;
}
Which correctly loads the $scope.projects
promise from my $dataService
service.
app.service('$dataService', function($q, $http, $location, $rootScope) {
var dataService = this; //Provides access 'this' inside functions below
var projectsDeferred = $q.defer();
$http.get('/api').success(function(data, status, headers, config) {
projectsDeferred.resolve(data.projects);
}).error(function(err) {
projectsDeferred.reject(err);
});
this.data = {projects: projectsDeferred.promise};
//UPDATE FUNCTION
function updateObjectInArray(array, object, newData) {
for(i in array) {
if(array[i] == object) {
if(newData != undefined) {
array[i] = newData;
} else {
return array[i];
}
}
}
return undefined;
}
this.updateProject = function(project, updateData) {
$http.put('/api/projects/' + project._id, updateData)
.success(function(data, status, headers, config) {
updateObjectInArray(dataService.data.projects.$$v, project, data);
}).error(function(data, status, headers, config) {});
};
});
I've created another controller that looks like this, that selects a single project from the array of projects based on the current URL:
function ProjectCtrl($scope, $route) {
//Getting the current project from the array of projects
$scope.project = $scope.projects.then(function(projects) {
for(i in projects) {
if(projects[i]._id == $route.current.params.projectId) {
return projects[i];
}
}
});
}
When I try to run my updateObjectInArray()
function (on the success of my $http.put()
request), my $scope.projects
in AppCtrl
is correctly updated (the array of projects) but my $scope.project
in ProjectCtrl
is not updated. I can log array[i]
inside the updateObjectInArray()
function and it will log exactly what I expect, and I can log $scope.projects
in AppCtrl
and it will update accordingly, but when I try to log $scope.project
in my ProjectCtrl
controller, it isn't updated accordingly.
I thought the reason was because I had to call $rootScope.$apply()
or $rootScope.$digest()
after I updated the array[i]
object in updateObjectInArray()
, however, I get the error that $digest is already in progress
.
What do I need to do to make sure my $scope.project
item in the array gets updated in my ProjectCtrl
? Do I need to resolve a new promise for it?
Simply put you can use $q. defer() to create a Promise. A Promise is a function that returns a single value or error in the future. So whenever you have some asynchronous process that should return a value or an error, you can use $q. defer() to create a new Promise.
$q is an angular defined service. It's the same as new Promise(). But $q takes things to the next level by enhancing additional feature that developers can use to perform complex tasks more simply. resolve(value) – resolves the derived promise with the value.
$q is integrated with the $rootScope. Scope Scope model observation mechanism in AngularJS, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repaints, which would result in flickering UI. Q has many more features than $q, but that comes at a cost of bytes.
As soon as the projects
are loaded, you're using one of the items from the array projects[i]
, let's theoretically assume it's the object 0x1
in memory. The problem is that when a new item is loaded (let's assume 0x2
), and you update the array, you're changing the object that resides in the array position (the 0x1
), but $scope.project
still references the now abandoned object 0x1
. You can't just change it in the array, you have to modify it, so you don't need to rebind the $scope.project
variable.
The best solution is to change array[i] = newData
to angular.extend(array[i], newData)
. This way, you gonna just change all properties of array[i], and as your $scope.project
points to the same object in memory it will be updated.
Anyway, I also believe you may want to change if(array[i] == object) {
to if(array[i]._id === object._id) {
and your equality comparisons (==
) to strictly equality comparisons (===
). This if
suits better your cause, as the new created object is not the same as the old one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With