我有一个AngularJS自定义组件,它基本上包裹了Material Design mdSelect
,但可以通过绑定轻松配置可用值,默认值和当前值。
但该组件在mdDialog
中充当一般编辑组件,可以根据正在编辑的事物更改其选项。这是一个“下一步”按钮,转到下一个要编辑的“东西”。按下按钮时,自定义组件将具有新的可用值,默认值和当前值 - 如下所示:
<foo-component default-value="dialog.getDefaultFoo()" current-foo="dialog.currentFoo">
</foo-component>
请注意,如果未给出可用值列表(如上例所示),则该组件会假定一个只包含一个值的值列表,指示“default-value”。
因此,当用户选择“下一步”时,mdSelect
中的值列表将会更改,因为dialog.getDefaultFoo()
返回的值。新选择的值将为dialog.currentFoo
。
但如果dialog.currentFoo
为null
,我希望控件自动选择指示的默认值,或者如果未指示默认值,则为第一个可用值。使用$onInit
创建组件时,这很容易。但是一旦创建,我如何知道(在组件内部)用户选择了“下一步”并且可用值列表已更改?
在“下一步”按钮的代码中,我拨打this.fooForm.$setPristine()
。根据{{3}},当调用此方法时,表单控制器将“传播到此表单中包含的所有控件”。所以我考虑让我的自定义控件挂钩检测$setPristine()
被调用,这样如果新值为null
,它可以自动从列表中选择默认值。但现在我又回到了同样的情况:我的自定义组件如何检测到表单上正在调用$setPristine()
?
本质上,我的自定义组件需要检测其中一个绑定值何时更改,并在某些条件下执行其他值的某些自定义更新。我知道我可以使用外部自定义组件的getter / settter,但是自定义组件如何检测其中一个绑定值是否已更改?
为了使问题更复杂,dialog.currentFoo
实际上是一个函数,我的组件将其识别为getter / setter函数,它将根据对话框的状态返回/更新正确的值。所以我甚至无法检测到这个值已经改变了,因为实际的函数永远不会改变 - 只有它返回的值才会改变。
实际上它比这更复杂,因为mdSelect
只是发送到dialog.currentFoo
的对象的一个件;否则它不会传播到组件之外。
尝试总结一下,我需要在自定义组件中知道绑定dialog.currentFoo
(实际上是getter / setter方法)现在将返回null
,以便自定义组件可以选择默认值基于内部mdSelect
中列出的当前项(也是动态的)的值(也是动态的)。我会接受解决方法,例如检测到封闭表单上已调用$setPristine()
。我甚至会接受一个hack,比如强迫AngularJS在某些外部状态发生变化时重新创建自定义组件。
答案 0 :(得分:0)
这很棘手,因为AngularJS很棘手,因为跟踪自定义AngularJS控件/输入组件的信息非常困难。
首先,需要做的是make the custom component use the normal ngModel
framework;尝试使用双向绑定currentValue
“伪造”它并不会因为这种复杂性而削减它,此外,ngModel
是“正确的”AngularJS方法。要解决此问题,您需要使用NgModelController
。虽然one page给出了神奇的公式,但找出如何使用组件执行此操作本身很困难。它是这样的:
require: {
ngModelCtrl: "ngModel"
},
bindings: {
ngModel: "<"
//TODO add defaultValue or whatever other properties here
},
然后你不直接访问双向值;您使用NgModelController
界面:
//get the current value
const foo = this.ngModelCtrl.$modelValue;
//set the current value
this.ngModelCtrl.$setViewValue(foo);
我可以告诉您,如果您将ng-model-options="{getterSetter:true}"
添加到组件中,ngModelOptions
将自动应用于您的模型,并且将自动调用getter / setter。
现在,您已熟悉整个ngModel
框架,并使用NgModelController
添加/访问验证程序和各种高级功能。
回到我的需求,我需要在某些条件下“重置组件”,我可以修补NgModelController#$setPristine()
。表单控制器识别我的组件是ngModel
框架的一部分,并在表单重置为其原始状态时调用$setPristine()
。
this.$onInit = () => {
this.ngModelCtrl.$setPristine = () => {
myInternalValue1 = null;
myInternalValue2 = this.defaultValue;
};
this.ngModelCtrl.$setPristine(); //initialize default value
};
这解释了我对表单控制器“将[$setPristine()
]传播到此表单中包含的所有控件”的疑问,我在原始问题中提到过。秘诀是组件必须成为真实ngModel
系统的一部分,以便它可以像AngularJS期望的那样进行交互,以及获得对重要内部方法的访问。