在Angular中,当service变量被更新时,Watch不会被触发

Watch not triggered when service variable is updated in Angular

本文关键字:Watch 更新 Angular service 变量      更新时间:2023-09-26

基本上,我正在做的是使用ng-repeat在视图中加载数据。当发生拖放操作时,我使用指令将项目从一个组移动到另一个组。该指令调用服务中的move函数并更新list变量。

我的问题是,当项目被移动时,ng-repeat没有更新。我尝试使用$scope.$watch,但没有运气。服务列表变量正在更新,但是由于某种原因没有触发监视。我尝试使用broadcast,这是有效的,但我已经读到,这是一个坏的做法,在控制器中使用广播,因为它会产生错误。

更新ng-repeat的最佳方法是什么?不知道为什么它不起作用。如果您需要更多的细节,请告诉我。

这是我的服务

angular.module('Data', [])
    .factory('DataService', DataService);
function DataService() {
    var list = [];
    list.push({
        id: 6,
        title: "First Group",
        items: [
            {
                id: 1,
                title: "This is an item"
            }
        ]
    });
    list.push({
        id: 7,
        title: "Testng",
        items: [
        ]
    });
    return {
        'get': get,
        'move': move,
    };
    function get() {
        return list;
    }
    function move(index, fromItemIndex, toItemIndex) {    
        list[fromItemIndex].items.push({
                id: 5,
                title: "This is an item"
            });
    }
}

这是我的控制器

function MyController($scope, DataService) {
    var vm = this;
    vm.list = DataService.get();
    $scope.$watch(function() {
        return DataService.get();
    }, function(value) {
        console.log('Wtatching');
        console.log(value);
    }, true);
}

我的观点

<div ng-repeat="item in vm.list track by $index">
    <div class="group" droppable group="<% $index %>">
        <div class="group-title">
            <% group.title %>
        </div>
        <div class="group-content">
            <div ng-repeat="item in item.items track by $index">
                <div class="group-item">
                    <div class="group-item-title" 
                         draggable 
                         group="<% $parent.$index %>" 
                         item="<% $index %>">
                        <% item.title %>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

编辑

这是一个plnker版本:https://plnkr.co/edit/bQuotNU7oOm92PCgmhcj

当您拖拽item 1并将其放到自身上时,您将看到服务列表更新了,但是手表没有被触发。

我认为问题是你的ng-repeat表达式。试着移除track by $index .

如果你正在使用jQuery(或其他非angular回调)来移动项目(拖放),那么你需要像这样包装你的move代码:

function move(index, fromItemIndex, toItemIndex) {
    $timeout(function() {
        list[fromItemIndex].items.push({
            id: 5,
            title: "This is an item"
        });
    });
}

确保在工厂中注入$timeout。在Angular中有一个文摘循环的概念,Angular会定期更新Angular上下文中的数据。

From the docs:

在$digest阶段,作用域检查所有的$watch表达式并将它们与之前的值进行比较。这个肮脏的检查完成了异步.

如果一些Angular数据在非Angular环境中被修改,比如jQuery拖拽&drop时,Angular将不会意识到这个变化,直到你告诉它。所以使用$scope.$apply()是用来告诉Angular有些东西发生了变化。但是如果消化循环已经在进行,$apply()有时会失败,所以建议使用一些Angular的打包服务,比如$timeout

要点:

$timeout用于隐式触发摘要循环

更多细节在这里:https://docs.angularjs.org/error/$rootScope/inprog#triggering-events-programmatically

(考虑使用UI。如果你使用的是基于jQuery的库,则由Angular UI团队维护。