ng-change获取新值和原始值

125

我正在使用ng-options从下拉菜单中选择值。我想能够比较旧值和新值。ng-change很适合获取下拉列表的新值,但如何同时获取新值和原始值呢?

<select ng-change="updateValue(user)" ng-model="user.id" ng-options="user.id as user.name for user in users"></select> 

例如,假设我想要控制器记录“您以前的用户名称为BILL,您当前的用户名称为PHILLIPE。”


1
请检查我的答案,链接在这里:https://dev59.com/nGEh5IYBdhLWcg3w321G#28296355。可能是重复的。 - bresleveloper
不确定行政上如何运作,但是重复的答案应该与此合并。bresleveloper是一个不错的解决方案(来自重复问题),但TGH的答案也应该显示出来。第一个依赖于框架的工作方式,这可能会在未来发生变化,而第二个则与框架无关。 - user1821052
7个回答

287

使用一个角括号表达式{{expression}},你可以将旧的用户或user.id值作为字面字符串添加到ng-change属性中:

<select ng-change="updateValue(user, '{{user.id}}')" 
        ng-model="user.id" ng-options="user.id as user.name for user in users">
</select>

在ngChange事件中,updateValue方法的第一个参数将是新的用户值,第二个参数将是上次由Angular更新select标记时所形成的文本字面量,其使用旧的user.id值。


6
请注意,方法调用中的“user”是来自“ng-model”的用户,而不是来自ng-options(可能会误导)。希望这个优雅的解决方案也能在未来的Angular版本中使用 :) - icl7126
15
这应该被视为有害的。我刚刚发现了一个脏漏洞,当 user.id 包含特殊字符(如 ' 或 /)时会发生。这是因为 Angular 表达式解析器不喜欢像 updateValue(user, 'blah /blah') 这样的表达式。 - Antoine Banctel-Chevrel
2
在updateValue函数中, $scope.user.id已经包含了新选择的值 - 没有必要向它传递一个新值的参数。 - Majix
@LINQ2Vodka,我认为只有在user.id是数字时才能不使用引号运行...如果user.id是字符串或GUID,则无法正常工作。 - Tamas
1
美丽的:)))) - Makatun
太棒了!我已经在使用Angular工作了3年,但不知道这是可能的。这将改变游戏规则。谢谢! - Justin Christian

17
也可以使用

<select ng-change="updateValue(user, oldValue)"     
       ng-init="oldValue=0"
       ng-focus="oldValue=user.id"
       ng-model="user.id" ng-options="user.id as user.name for user in users">
</select>

1
这个答案在ng-repeat上非常有效。如果您使用的元素支持ng-change但不支持ng-focus,则也可以使用ng-click。 - meticoeus
1
ng-init="oldValue=0" & ng-focus="oldValue=user.id" 对我很有帮助。 - thatzprem

16

您可以使用类似ng-change=someMethod({{user.id}})的方式。 通过将您的值保留在{{expression}}内,它会在行内计算表达式,并为您提供当前值(在调用ng-change方法之前的值)。

<select ng-model="selectedValue" ng-change="change(selectedValue, '{{selectedValue}}')">

15

在控制器中保留一个currentValue变量,在每次更改时更新它。然后,在更新之前每次将其与新值进行比较。

使用$watch的想法也不错,但我认为简单的变量是最简单和最合乎逻辑的解决方案。


观察操作有点昂贵,我喜欢db-inf的答案...它是一个简单有效的解决方案。 - Pramod Sharma
4
最佳答案:如果你在ng-repeat内部,可以使用ng-init创建一个子作用域内的变量。 - Romain F.
1
在我看来,这是最好的选择。由于ngChange默认不提供检索旧值的功能,像@db-inf的解决方案可能会在未来版本中崩溃。此外,这似乎是控制器的职责,将其委托给视图层似乎很奇怪。 - Felipe Leão

9

6
我看到一篇文章声称手表相比于ng-change更加不卫生/低效。http://www.benlesh.com/2013/10/title.html - Menelaos
5
根据我的经验,你几乎从不想使用手表。 - nardnob
2
如果编程是一门主观的艺术,你可能会有所发现。然而,有许多原因可能会使您想避免ng-charge或其他基于指令的方法,这与按照“Angular”方式执行任务无关。 - tommybananas

2
你可以使用watch,因为它有旧值和新值,但是这会增加循环检测的次数。
我建议在控制器中保留第二个变量并设置它。

这只是一个相当琐碎的例子,我会选择可读性而不是担心单个观察者在这种情况下。不过,我想这仍然是一件值得警惕的好事。 - tommybananas
1
Watch和ng-change实际上有不同的行为:ng-change只检测用户事件,而$watch会在变量改变时触发。监视器增加了复杂性,并且容易在代码更改其值时创建更新周期。 - Rhys van der Waerden
我同意@Rhys van der Waerden的观点...这篇文章指出$watch有一定的危险性:http://www.benlesh.com/2013/10/title.html - Menelaos

0

你可以随时这样做:

... ng-model="file.PLIK_STATUS" ng-change="file.PLIK_STATUS = setFileStatus(file.PLIK_ID,file.PLIK_STATUS,'{{file.PLIK_STATUS}}')" ...

在控制器中:

$scope.setFileStatus = function (plik_id, new_status, old_status) {
    var answer = confirm('Czy na pewno zmienić status dla pliku ?');
    if (answer) {
        podasysService.setFileStatus(plik_id, new_status).then(function (result) {
            return new_status;
        });
    }else{
        return old_status;
    }
};

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