重置 AngularJS Material 将自定义组件设计为原始
reset AngularJS Material Design custom component to pristine
我有一个 AngularJS 自定义组件,它基本上围绕 Material 设计 mdSelect
,但通过其绑定提供了可用、默认和当前值的简单配置。
但是该组件在 mdDialog
中用作通用编辑组件,可以根据正在编辑的内容更改其选项。因此有一个 "Next" 按钮可以转到下一个要编辑的 "thing"。按下按钮时,自定义组件将具有新的可用值、默认值和当前值——类似这样:
<foo-component default-value="dialog.getDefaultFoo()" current-foo="dialog.currentFoo">
</foo-component>
请注意组件,如果未给出可用值列表(如上例所示),则组件假定只有一个值的值列表,"default-value" 表示。
因此,当用户 selects "Next" 时,mdSelect
中的值列表将更改,因为 return 由 dialog.getDefaultFoo()
编辑的值.新的 selected 值将是 dialog.currentFoo
.
但是如果 dialog.currentFoo
是 null
,我希望控件自动 select 指示的默认值,或者如果没有指示默认值,则第一个可用值。当使用 $onInit
创建组件时,这很容易。但是一旦它被创建,我怎么知道(在组件内部)用户已经 selected "Next" 并且可用值列表已经改变?
在 "Next" 按钮的代码中,我调用了 this.fooForm.$setPristine()
。根据 documentation,调用此方法时表单控制器将 "propagate to all the controls contained in this form." 所以我考虑让我的自定义控件挂钩检测正在调用 $setPristine()
,以便它可以自动 select 如果新值为 null
,则为列表中的默认值。但是现在我又回到了同样的情况:我的自定义组件如何检测到 $setPristine()
在表单上被调用?
本质上,我的自定义组件需要检测其绑定值之一何时更改,并在特定条件下对其他值执行一些自定义更新。我知道我可以在 外部 自定义组件中使用 getter/settter,但是自定义组件如何检测到其绑定值之一已更改?
更复杂的是,dialog.currentFoo
实际上是一个函数,我的组件将其识别为 getter/setter 函数,它将根据对话框的状态 return/update 正确的值.所以我什至无法检测到这个值已经改变,因为实际函数永远不会改变——只有它 return 的值会改变。
实际上比这更复杂,因为 mdSelect
只是发送到 dialog.currentFoo
的对象的一个 部分 ;否则它不会传播到组件外部。
总结一下,我需要在自定义组件中知道绑定 dialog.currentFoo
(实际上是 getter/setter 方法)现在 return null
是否如此自定义组件可以 select 基于内部 mdSelect
中列出的当前项目(也是动态的)的默认值(也是动态的)。我会接受解决方法,例如检测 $setPristine()
已在封闭表单上调用。我什至会接受 hack,例如当某些外部状态发生变化时强制 AngularJS 重新创建自定义组件。
这很棘手,因为 AngularJS 很棘手,而且很难跟踪自定义 AngularJS control/input 组件的信息。
首先需要做的第一件事就是make the custom component use the normal ngModel
framework; trying to "fake" it using a two-way bound currentValue
doesn't cut it for this complexity, and besides, ngModel
is the "correct" AngularJS way to do it. To pull this off you'll need to use NgModelController
. Finding out how to do this with a component is difficult in itself, although one page给出神奇的公式。它是这样的:
require: {
ngModelCtrl: "ngModel"
},
bindings: {
ngModel: "<"
//TODO add defaultValue or whatever other properties here
},
那么你不直接访问two-way值;您使用 NgModelController
接口:
//get the current value
const foo = this.ngModelCtrl.$modelValue;
//set the current value
this.ngModelCtrl.$setViewValue(foo);
据我所知,如果您将 ng-model-options="{getterSetter:true}"
添加到组件,ngModelOptions
将自动应用于您的模型,并自动调用 getters/setters。
现在您已连接到整个 ngModel
框架,并使用 NgModelController
到 add/access 验证器和各种高级功能。
回到我的需求,在某些情况下我需要 "reset the component",我可以修补到 NgModelController#$setPristine()
。表单控制器识别出我的组件是 ngModel
框架的一部分,并在表单重置为原始状态时调用 $setPristine()
。
this.$onInit = () => {
this.ngModelCtrl.$setPristine = () => {
myInternalValue1 = null;
myInternalValue2 = this.defaultValue;
};
this.ngModelCtrl.$setPristine(); //initialize default value
};
这解释了我对表单控制器的疑虑 "propagat[ing $setPristine()
] to all the controls contained in this form",我在原来的问题中提到过。秘诀在于该组件必须成为真实 ngModel
系统的一部分,以便它可以像 AngularJS 期望的那样进行交互,并获得对重要内部方法的访问权。
我有一个 AngularJS 自定义组件,它基本上围绕 Material 设计 mdSelect
,但通过其绑定提供了可用、默认和当前值的简单配置。
但是该组件在 mdDialog
中用作通用编辑组件,可以根据正在编辑的内容更改其选项。因此有一个 "Next" 按钮可以转到下一个要编辑的 "thing"。按下按钮时,自定义组件将具有新的可用值、默认值和当前值——类似这样:
<foo-component default-value="dialog.getDefaultFoo()" current-foo="dialog.currentFoo">
</foo-component>
请注意组件,如果未给出可用值列表(如上例所示),则组件假定只有一个值的值列表,"default-value" 表示。
因此,当用户 selects "Next" 时,mdSelect
中的值列表将更改,因为 return 由 dialog.getDefaultFoo()
编辑的值.新的 selected 值将是 dialog.currentFoo
.
但是如果 dialog.currentFoo
是 null
,我希望控件自动 select 指示的默认值,或者如果没有指示默认值,则第一个可用值。当使用 $onInit
创建组件时,这很容易。但是一旦它被创建,我怎么知道(在组件内部)用户已经 selected "Next" 并且可用值列表已经改变?
在 "Next" 按钮的代码中,我调用了 this.fooForm.$setPristine()
。根据 documentation,调用此方法时表单控制器将 "propagate to all the controls contained in this form." 所以我考虑让我的自定义控件挂钩检测正在调用 $setPristine()
,以便它可以自动 select 如果新值为 null
,则为列表中的默认值。但是现在我又回到了同样的情况:我的自定义组件如何检测到 $setPristine()
在表单上被调用?
本质上,我的自定义组件需要检测其绑定值之一何时更改,并在特定条件下对其他值执行一些自定义更新。我知道我可以在 外部 自定义组件中使用 getter/settter,但是自定义组件如何检测到其绑定值之一已更改?
更复杂的是,dialog.currentFoo
实际上是一个函数,我的组件将其识别为 getter/setter 函数,它将根据对话框的状态 return/update 正确的值.所以我什至无法检测到这个值已经改变,因为实际函数永远不会改变——只有它 return 的值会改变。
实际上比这更复杂,因为 mdSelect
只是发送到 dialog.currentFoo
的对象的一个 部分 ;否则它不会传播到组件外部。
总结一下,我需要在自定义组件中知道绑定 dialog.currentFoo
(实际上是 getter/setter 方法)现在 return null
是否如此自定义组件可以 select 基于内部 mdSelect
中列出的当前项目(也是动态的)的默认值(也是动态的)。我会接受解决方法,例如检测 $setPristine()
已在封闭表单上调用。我什至会接受 hack,例如当某些外部状态发生变化时强制 AngularJS 重新创建自定义组件。
这很棘手,因为 AngularJS 很棘手,而且很难跟踪自定义 AngularJS control/input 组件的信息。
首先需要做的第一件事就是make the custom component use the normal ngModel
framework; trying to "fake" it using a two-way bound currentValue
doesn't cut it for this complexity, and besides, ngModel
is the "correct" AngularJS way to do it. To pull this off you'll need to use NgModelController
. Finding out how to do this with a component is difficult in itself, although one page给出神奇的公式。它是这样的:
require: {
ngModelCtrl: "ngModel"
},
bindings: {
ngModel: "<"
//TODO add defaultValue or whatever other properties here
},
那么你不直接访问two-way值;您使用 NgModelController
接口:
//get the current value
const foo = this.ngModelCtrl.$modelValue;
//set the current value
this.ngModelCtrl.$setViewValue(foo);
据我所知,如果您将 ng-model-options="{getterSetter:true}"
添加到组件,ngModelOptions
将自动应用于您的模型,并自动调用 getters/setters。
现在您已连接到整个 ngModel
框架,并使用 NgModelController
到 add/access 验证器和各种高级功能。
回到我的需求,在某些情况下我需要 "reset the component",我可以修补到 NgModelController#$setPristine()
。表单控制器识别出我的组件是 ngModel
框架的一部分,并在表单重置为原始状态时调用 $setPristine()
。
this.$onInit = () => {
this.ngModelCtrl.$setPristine = () => {
myInternalValue1 = null;
myInternalValue2 = this.defaultValue;
};
this.ngModelCtrl.$setPristine(); //initialize default value
};
这解释了我对表单控制器的疑虑 "propagat[ing $setPristine()
] to all the controls contained in this form",我在原来的问题中提到过。秘诀在于该组件必须成为真实 ngModel
系统的一部分,以便它可以像 AngularJS 期望的那样进行交互,并获得对重要内部方法的访问权。