I am using a ng-repeat element to display a list of elements. Each element has some Parse.Pointer objects which are referencing other objects. In my template, when i want to display a value from a referenced object, the value only gets displayed when i first move to an other tab of my ionic app and then return to the tab where i want to display those values.
This is my call for the list of elements:
function getFragments(limit){
var deferred = $q.defer();
var query = new Parse.Query(Fragment);
query.limit(limit);
query.descending('createdAt');
query.find({
success: function(results){
deferred.resolve(results);
error: function(error){
deferred.reject(error);
}
});
return deferred.promise;
}
this is how i assign the values to the $scope:
Fragment.getFragments(20).then(function(fragments){
$scope.fragments=fragments;
});
and this how i display a value of an object that has a pointer in the object (event is a pointer, name is a variable from the event object):
<ion-item ng-repeat="fragment in fragments">
<h3>{{fragment.event.name}}</h3>
Each value of each object in the list also has a get property defined like this:
Fragment.prototype.__defineGetter__('event', function(){
return this.get('event');
});
my first guess without actually running the code would be that angular doesn't know something was updated.
you need to tell Angular that something was updated and that it must run $digest
or $apply
to update it's scope too.
After some struggling I found multiple solutions. I'll describe 2.
Solution 1
For each fragment in the array, fetch the Object for the pointer. On successfully retrieving the object call $scope.$apply() to notify the changes on the scope.
Fragment.getFragments(20).then(function(fragments){
angular.forEach(fragments, function(fragment){
if(fragment.event){
promises.push(fragment.event.fetch({
success: function(){
$scope.$apply();
}
}));
}
});
But since I'm fetching multiple Objects from Pointers for each fragment i wanted to use promises and call $scope.$apply()
when all promises are resolved.
var promises = [];
if(fragment.user){
promises.push(fragment.user.fetch());
}
if(fragment.artist){
promises.push(fragment.artist.fetch());
}
$q.all(promises).then($scope.$apply());
This gives me the message that $digest
already is in progress so i guess that $q.all
already starts the $digest
. So just using $q.all(promise)
solves the problem.
Solution 2
When querying for the fragments, fetch all the Objects for the Pointers before resolving the Promise.
function getFragments(limit) {
var deferred = $q.defer();
var query = new Parse.Query(Fragment);
query.limit(limit);
query.descending('createdAt');
query.find({
success: function (fragments) {
var promises = [];
angular.forEach(fragments, function(fragment){
if(fragment.user){
promises.push(fragment.user.fetch());
}
if(fragment.artist){
promises.push(fragment.artist.fetch());
}
});
$q.all(promises).then(function(){
deferred.resolve(fragments);
});
},
error: function (error) {
console.log('log error');
}
});
return deferred.promise;
}
Conclusion
In my opinion the 2nd solution is the best, because it is better to keep data logic out of the controller and don't use the $scope in the data logic.