$watch只触发一次

5
我正在使用针对AngularJS的smart table (http://lorenzofox3.github.io/smart-table-website/),并创建了一个名为isReset的标志,它将触发表格重新加载。这是因为我有一个指令在观察该标志,并在设置isReset时运行刷新,刷新完成后,它将再次关闭该标志。 我的问题是,当我设置标志时,它第一次运行,但在监视标志的行为后,似乎从未被设置为false。我尝试手动将标志设置为false,但下一次$watch甚至没有触发。我的代码如下,如果您能帮助我解决这个问题,那就太好了。最奇怪的是,我还有另一个地方使用了完全相同的方式,而且它可以按预期工作。
JS
        $scope.resetFilter = function() {
        $scope.timestampFilter = "";
        $scope.levelFilter = "";
    };

    $scope.getAPIServerLogs = function (tableState) {
        $scope.isLoading = true;
        ServerLog.get({
            "serverType": "API",
            "timestampFilter": $scope.timestampFilter,
            "levelFilter": $scope.levelFilter,
            "offset": tableState.pagination.start,
            "limit": tableState.pagination.number,
            "sortField": tableState.sort.predicate,
            "order": tableState.sort.reverse ? "desc" : "asc"
        }, function (response) {
            $scope.isLoading = false;
            $scope.serverlogs = response.data;
            $scope.displayedserverlog = [].concat($scope.serverlogs);
            tableState.pagination.numberOfPages = response.pages;
        });
    };

指令

directives.directive('stReset', function () {
return {
    require: '^stTable',
    replace: false,
    scope: {stReset: "=stReset"},
    link: function (scope, element, attr, ctrl) {
        scope.$watch("stReset", function () {
            if (scope.stReset) {
                // reset scope value
                var tableState = ctrl.tableState();
                tableState.pagination.start = 0;
                tableState.sort.prediate = {};
                tableState.search = {};
                ctrl.pipe();
                scope.stReset = false;
            }
        }, true);
    }
};

HTML

<table st-table="displayedserverlog" st-safe-src="serverlogs" st-pipe="getAPIServerLogs"
   class="table table-striped table-hover logtable">
<thead st-reset="isReset">
<tr>
    <th st-sort-default="reverse" st-sort="timestamp" width="11%">Timestamp</th>
    <th st-sort="logger" width="30%">logger</th>
    <th st-sort="level" width="3%">Level</th>
    <th st-sort="thread" width="11%">Thread</th>
    <th st-sort="message" width="45%">Message</th>
</tr>
</thead>
<tbody ng-repeat="serverlog in serverlogs">
<tr ng-click="click(serverlog)" ng-class="{'tr-active':serverlog.isClicked, 'pointer danger':serverlog.exception}">
    <td>{{serverlog.timestamp | date: 'yyyy-MMM-dd hh:mm:ss'}}</td>
    <td>{{serverlog.logger}}</td>
    <td>{{serverlog.level}}</td>
    <td>{{serverlog.thread}}</td>
    <td>{{serverlog.message}}</td>
</tr>
<tr ng-show="serverlog.isClicked">
    <td colspan="6">
        <div class="row">
            <div class="col-md-12">
                <div>{{serverlog.exception}}</div>
                <pre><div ng-repeat="trace in serverlog.stacktrace track by $index" class="stacktrace">{{trace}}
                </div></pre>
            </div>
        </div>
    </td>
</tr>
</tbody>
<tfoot ng-hide="isLoading">
<tr>
    <td colspan="10" class="text-center">
        <div st-pagination="" st-items-by-page="50"></div>
    </td>
</tr>
</tfoot>


ServerLog.get 代码包含什么?它是 jQuery ajax 吗?还是你只有控制台错误? - Pankaj Parkar
$watch函数接受两个参数,newVal和oldVal。https://docs.angularjs.org/api/ng/type/$rootScope.Scope。此外,为什么要检查对象相等性? - Index
@pankajparkar 只有控制台错误。甚至没有错误,它只是不按照我期望的方式运行。 - Harry
移除 scope: {stReset: "=stReset"},,这样你就可以从父级作用域中读取/观察值的副本,或者你可以尝试使用 @ 而不是 =。 - YOU
3个回答

0
这个 Plunker 模拟了你的问题:http://plnkr.co/edit/c8crhe9ZR44GQBJ2sqm6?p=preview(请查看控制台)。
    scope.$watch("flag", function(neww, old){
            count ++;
            console.log("inWatch " + count + ": " + neww + ', ' + old);
            if (scope.flag === true) {
                scope.flag = false;
            }
    });

在$watch中将标志设置为false基本上意味着它将始终为false(因为:您修改值--> $watch运行--> 在函数的末尾将该值设置为false--> 值为false)


你说得对。我不小心漏掉了一行重要的代码,它是一个按钮,用于设置“isReset”为true。这应该重置表格,因为它应该通过“st-reset =”isReset“=>触发$watch => pipe(),重新加载表格=>再将isReset设置为false。我的问题是,在此实现中,“isReset”由于某种原因无法设置为false,即使在另一页上,它也可以完美地按照我们期望的方式工作(正如您在plunker中很好地说明的那样)。 - Harry
那么,当你说它在另一个页面上工作时...你是否在两个页面上都使用了相同的指令(st-reset)(并获得不同的结果),或者你有一个类似的实现,在那里它按预期工作? - Ana F
就我所看到的(与st-reset交互的代码行),它们是相同的(使用st-reset触发st-table的刷新)。不同之处在于,对于此块,$watch没有将isReset设置为false,并且即使在块外手动将其设置为false,似乎也不会再次触发。 - Harry

0

我找到了一个解决方案。虽然不确定为什么它有效,但我添加了

scope.$parent.$parent.isReset = false;

到指令的结尾,它按预期工作。然而,替换现有的

scope.stReset = false;

破坏了我使用指令的另一个地方。现在,我会两个都做。将来当我更聪明的时候,我会重新审视这个问题。我希望这能帮助未来的某个人,让他们不要像我一样浪费三天时间去解决它。


0

试一试吧。

var watcher = $scope.$watch('someScope', function(newValue, oldValue){
    if(newValue === 'yourValue') {
      watcher(); // stop this watch
    }
  });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接