Javascript AngularJS-在服务内排序数组,在控制器/视图中保留绑定

Javascript AngularJS-在服务内排序数组,在控制器/视图中保留绑定,javascript,angularjs,sorting,firebase,Javascript,Angularjs,Sorting,Firebase,我正在寻找一种在Angular服务中对数组进行排序的方法,并且仍然在控制器中保留正确的绑定 如果我跳过排序,绑定效果会很好,但是数组的排序并不是我所需要的 每当我使用Lodash的\uu.sortBy或angular的$filter('orderBy')服务执行排序时,会发生以下两种情况之一: 服务中的数组已正确排序,但与控制器的绑定已断开,因为它不再引用同一数组 如果我试图通过使用Lodash的\uu.cloneDeep或angular的angular.copy来修复此问题,浏览器会因循环引用

我正在寻找一种在Angular服务中对数组进行排序的方法,并且仍然在控制器中保留正确的绑定

如果我跳过排序,绑定效果会很好,但是数组的排序并不是我所需要的

每当我使用Lodash的
\uu.sortBy
或angular的
$filter('orderBy')
服务执行排序时,会发生以下两种情况之一:

  • 服务中的数组已正确排序,但与控制器的绑定已断开,因为它不再引用同一数组

  • 如果我试图通过使用Lodash的
    \uu.cloneDeep
    或angular的
    angular.copy
    来修复此问题,浏览器会因循环引用而冻结(?)

  • Service.js

        angular.module('exampleapp')
    .factory('ClientFeedService', function($filter, $firebase, FIREBASE_URL, FeedItemService) {
    
      return function(clientId) {
    
        var ClientFeedService = this;
        var ref = new Firebase(FIREBASE_URL + 'feeds/clients/' + clientId);
        var initialDataLoaded = false;
        ClientFeedService.feedArray = [];
    
        ClientFeedService.sortItems = function() {
          // Sorting logic here
        };
    
    
        /**
         * Bind to the initial payload from Firebase
         */
        ref.once('value', function() {
    
          // Sort items after initial payload
          ClientFeedService.sortItems();
          initialDataLoaded = true;
        });
    
    
        /**
         * Bind to new items being added to Firebase
         */
        ref.on('child_added', function(feedItemSnap) {
          console.log('child_added');
          ClientFeedService.feedArray.unshift(FeedItemService.find(feedItemSnap.name(), feedItemSnap.val()));
    
          // Sort after new item if initial payload loaded
          if (initialDataLoaded) {
            ClientFeedService.sortItems();
          }
        });
    
        ClientFeedService.getFeedItems = function() {
          return ClientFeedService.feedArray;
        };
    
        return ClientFeedService;
      };
    
    });
    
        app.controller('ClientsFeedCtrl', function($scope, $stateParams, ClientFeedService) {
    
      var clientId = $stateParams.clientId;
      $scope.clientFeed = new ClientFeedService(clientId).getFeedItems();
    
    });
    
    Controller.js

        angular.module('exampleapp')
    .factory('ClientFeedService', function($filter, $firebase, FIREBASE_URL, FeedItemService) {
    
      return function(clientId) {
    
        var ClientFeedService = this;
        var ref = new Firebase(FIREBASE_URL + 'feeds/clients/' + clientId);
        var initialDataLoaded = false;
        ClientFeedService.feedArray = [];
    
        ClientFeedService.sortItems = function() {
          // Sorting logic here
        };
    
    
        /**
         * Bind to the initial payload from Firebase
         */
        ref.once('value', function() {
    
          // Sort items after initial payload
          ClientFeedService.sortItems();
          initialDataLoaded = true;
        });
    
    
        /**
         * Bind to new items being added to Firebase
         */
        ref.on('child_added', function(feedItemSnap) {
          console.log('child_added');
          ClientFeedService.feedArray.unshift(FeedItemService.find(feedItemSnap.name(), feedItemSnap.val()));
    
          // Sort after new item if initial payload loaded
          if (initialDataLoaded) {
            ClientFeedService.sortItems();
          }
        });
    
        ClientFeedService.getFeedItems = function() {
          return ClientFeedService.feedArray;
        };
    
        return ClientFeedService;
      };
    
    });
    
        app.controller('ClientsFeedCtrl', function($scope, $stateParams, ClientFeedService) {
    
      var clientId = $stateParams.clientId;
      $scope.clientFeed = new ClientFeedService(clientId).getFeedItems();
    
    });
    

    有几种方法可以解决这个问题。首先,让我们看看发生了什么

    您正在将初始数组分配给
    $scope.cliendFeed
    。在此之后,随着数据的添加,将生成一个新数组并将其存储在服务中,但您仍然拥有对原始数组的引用。因此,最终,您要做的是找到一种方法使
    $scope.clientFeed
    与您的服务保持同步

    最简单的解决方案可能是使用getter方法,而不是在作用域中存储对数组的引用

    为此,您必须添加如下内容:

    var service = new ClientFeedService(clientId);
    $scope.getClientFeed = function () {
      return service.getFeedItems();
    };
    
    并确保您的
    ng repeat
    调用了此函数:

    <li ng-repeat="item in getClientFeed()">...</li>
    
  • 希望有帮助

  • 您可以将从API返回的新数据推送到控制器中的同一数组,然后应用$filter
  • 下面是一个例子

    function getData(){
       $scope.array.push(returnData);
       sortArrayList($scope.orderByField, $scope.reverseSort);
    }
    
    function sortArrayList(orderByField, reverseSort){
       $scope.array = $filter('orderBy')($scope.array, orderByField, reverseSort);
    }
    

  • 无法在视图中的ng repeat指令上使用orderBy筛选器吗?既然您已经在使用AngularFire(
    $firebase
    ),您不能使用firebase的本机
    orderByChild
    方法,然后
    $asArray()
    获取可以绑定到
    $scope
    ?@Beartums的数组吗,我试图避免这种情况,因为在视图中直接使用过滤器可能会对性能有害(它们在每个摘要周期中被多次调用,而不是在控制器/服务中按需调用)。@FrankvanPuffelen,正在设置的firebase ref只是一个索引,并且不包含使用Firebase的本机orderByChild所需的实际数据,它调用FeedItemService来获取索引中的项目ID。您的建议不在该应用程序的上下文中实现这一点。只要每次调用getter函数时返回相同的内容,getter函数就可以了。不好的是,如果每次调用getter时都返回新对象。