AngularJS:颜色面板修改值时触发ng-change函数的问题
嘿,我明白你的困扰了——用颜色面板改完颜色,输入框显示新的十六进制值,但colorChanged函数就是不跑,只有手动输入才触发,连$watch都没反应对吧?这事儿我之前也碰到过,本质是第三方颜色面板的更新逻辑没和Angular的机制对齐。
问题出在哪?
大多数颜色选择器插件都是直接操作DOM去改input的value属性,完全绕开了Angular的ngModel系统。Angular的ng-change和$watch都是盯着$scope上绑定的变量看的,插件直接改DOM的话,$scope里的变量根本没更新,Angular的脏检查循环(digest cycle)也没触发,自然检测不到变化。
给你几个靠谱的解决办法
1. 用颜色面板的回调函数(最推荐)
几乎所有正经的颜色选择器都会提供“颜色选择完成”的回调,你可以在这个回调里手动把新颜色同步到$scope,再触发Angular的脏检查。
举个实际代码例子,假设你用的是某款颜色面板:
// 初始化颜色面板的时候绑定回调 $('#yourColorPicker').colorPicker({ onSelect: function(newHexColor) { // 把新颜色赋值给ngModel绑定的变量 $scope.selectedColor = newHexColor; // 手动触发Angular的脏检查,让ng-change和$watch生效 $scope.$apply(); // 或者你也可以直接在这里调用colorChanged函数 // $scope.colorChanged(); } });
对应的HTML就保持原来的样子就行:
<input type="text" ng-model="selectedColor" ng-change="colorChanged()">
2. 换用Angular专属的颜色选择器指令
要是不想手动折腾DOM事件,最省心的办法就是用专门为AngularJS封装的颜色选择器,比如angular-color-picker这类。它们天生就和ngModel集成好了,只要颜色变了,ng-change会自动触发,完全不用你额外处理。
3. 手动监听input的DOM变化
如果实在没法用插件的回调,那可以直接监听input的input或者change原生事件,把DOM里的新值同步到$scope里:
// 在控制器里给input加个DOM事件监听 angular.element(document.getElementById('colorInput')).on('input change', function() { var newColor = this.value; // 避免重复触发,先检查值有没有变 if ($scope.selectedColor !== newColor) { $scope.selectedColor = newColor; $scope.$apply(); } });
HTML里给input加个id方便获取:
<input type="text" id="colorInput" ng-model="selectedColor" ng-change="colorChanged()">
为啥之前的$watch没生效?
因为颜色面板改的是DOM的value,$scope里绑定的selectedColor根本没更新啊!$watch是盯着$scope变量看的,DOM变了但$scope没同步,它当然察觉不到。必须手动把DOM的新值同步到$scope,再用$apply()触发Angular的脏检查,这样$watch和ng-change才会起作用。
内容的提问来源于stack exchange,提问作者Umair Jameel

