我有一个网页,作为单个实体的编辑器,它作为$ scope.fieldcontainer属性中的深层图形。在我从REST API(通过$ resource)获得响应后,我将一个监视添加到'fieldcontainer'。我正在使用这个手表来检测页面/实体是否“脏”。现在我正在使保存按钮弹起,但实际上我想让保存按钮不可见,直到用户弄脏模型为止。
我得到的是手表的单个触发器,我认为这是因为.fieldcontainer = ...赋值在我创建手表后立即发生。我想只是使用“dirtyCount”属性吸收最初的误报,但感觉非常hacky ......而且我认为必须有一种“Angular惯用”方式来解决这个问题 - 我不是唯一一个使用手表来检测脏模型。
以下是我设置手表的代码:
$scope.fieldcontainer = Message.get({id: $scope.entityId },
function(message,headers) {
$scope.$watch('fieldcontainer',
function() {
console.log("model is dirty.");
if ($scope.visibility.saveButton) {
$('#saveMessageButtonRow').effect("bounce", { times:5, direction: 'right' }, 300);
}
}, true);
});
我一直在想,除了用“if(dirtyCount> 0)”保护我的“UI脏”代码之外,我必须采用更简洁的方式来做...
答案 0 :(得分:469)
第一次调用侦听器时,旧值和新值将完全相同。所以这样做:
$scope.$watch('fieldcontainer', function(newValue, oldValue) {
if (newValue !== oldValue) {
// do whatever you were going to do
}
});
这实际上是Angular docs recommend handling it:
的方式在观察者注册观察者之后,异步调用侦听器fn(通过$ evalAsync)来初始化观察者。在极少数情况下,这是不合需要的,因为当watchExpression的结果没有改变时会调用监听器。要在侦听器fn中检测此场景,您可以比较newVal和oldVal。如果这两个值相同(===)则由于初始化而调用了监听器
答案 1 :(得分:111)
在初始加载之前设置一个标志,
var initializing = true
然后当第一个$ watch触发时,执行
$scope.$watch('fieldcontainer', function() {
if (initializing) {
$timeout(function() { initializing = false; });
} else {
// do whatever you were going to do
}
});
该标志将在当前摘要周期结束时拆除,因此下一次更改不会被阻止。
答案 2 :(得分:41)
我意识到这个问题已得到解答,但我有一个建议:
$scope.$watch('fieldcontainer', function (new_fieldcontainer, old_fieldcontainer) {
if (typeof old_fieldcontainer === 'undefined') return;
// Other code for handling changed object here.
});
使用标志有效但有一点code smell你不觉得吗?
答案 3 :(得分:3)
只需验证新val的状态:
$scope.$watch('fieldcontainer',function(newVal) {
if(angular.isDefined(newVal)){
//Do something
}
});
答案 4 :(得分:1)
在初始加载当前值期间,旧值字段未定义。因此,下面的示例可帮助您排除初始加载。
;WITH c AS (SELECT Name,
MAX(TrackNum) AS TrackNum
FROM @Table1
GROUP BY Name)
UPDATE t
SET t.TrackNum = c.TrackNum
FROM @Table1 t
JOIN c ON t.Name = c.Name
WHERE t.TrackNum IS NULL OR t.TrackNum = ''
SELECT *
FROM @Table1