Parsejs angular/ionic retrieving relational object

2019-08-26 20:03发布

问题:

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');
});

回答1:

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.



回答2:

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.