Javascript 在带有嵌入表单的自定义指令上使用ngModel,并进行工作验证?
我有一组通常可重用的表单输入,它们在整个应用程序中可重用,因此我尝试将它们封装在自定义指令中。我想在我的指令上设置一个Javascript 在带有嵌入表单的自定义指令上使用ngModel,并进行工作验证?,javascript,angularjs,angularjs-directive,angularjs-ng-model,angularjs-forms,Javascript,Angularjs,Angularjs Directive,Angularjs Ng Model,Angularjs Forms,我有一组通常可重用的表单输入,它们在整个应用程序中可重用,因此我尝试将它们封装在自定义指令中。我想在我的指令上设置一个ngModel,并在主指令内的几个不同输入(其中一些是指令本身)中对其进行分割以进行编辑 同时,我需要将表单验证结果向上传递给父表单,以便显示适当的消息和样式 实现这一点最简单、最惯用的方法是什么? 这些(简化的)模板应该给你一个我想要的例子 OuterTemplate.html 这就是我对指令的理解。在这种情况下,ng模型和myDirective都是指令。我不清楚如果你在做 1
ngModel
,并在主指令内的几个不同输入(其中一些是指令本身)中对其进行分割以进行编辑
同时,我需要将表单验证结果向上传递给父表单,以便显示适当的消息和样式
实现这一点最简单、最惯用的方法是什么?
这些(简化的)模板应该给你一个我想要的例子
OuterTemplate.html
这就是我对指令的理解。在这种情况下,ng模型和myDirective都是指令。我不清楚如果你在做 1) ng模型上的包装器或 2) 自定义指令 因为如果要执行自定义指令,只需传入数据,例如 {作用域:{数据:'='} 如果您想做一个包装器,您可能不应该传入与ngModel相关的其他属性,这意味着您仍然可以传入数据
ctrl.myComplexModel
,顺便说一句,模型对象不能分配给ng模型,因为ng模型不保存对象,它只保存数据
注意:事实上我找到了这篇文章
显然,你可以通过模型,
不管怎么说,这对我来说太复杂了:)如果你想做一个包装器,我觉得这个图案
但很明显你可能在做“是a”对象。我已经找到了一个不错的解决方案。简言之,我已经从我的自定义指令中删除了
NgModelController
实现,并且我完全依赖自定义指令中form
指令的内部FormController
。据我所知,NgModelController
只是没有被删除设计用于在自定义指令中包装表单。但是,嵌套表单在Angular中得到了很好的支持,因此这是一种方法
我没有意识到的是,从Angular 1.3开始,您可以动态地为表单指定一个名称,而我无法阻止“黑盒”通过泄漏并将自身附加到父窗体控制器,我至少可以控制它在父范围中发布自身时使用的名称,这是可以接受的,并且与ngModel
提供的API非常相似
下面更新了示例
OuterTemplate.html
指令的内部模板基本保持不变。最大的区别是,ngForm
的名称现在是动态设置的
要用ngClass处理这个问题,角度表达式不起作用,所以我更新了我的示例,改为在$scope
上使用函数
最后,对于指令范围的业务规则,我使用了一个带有ngModel
指令和name
集合的隐藏输入。我附加了一个用于验证的自定义迷你指令,仅用于此字段。此字段上的验证错误将冒泡出来供父指令使用
myDirective.js
现在几乎所有的逻辑都已从指令定义中删除。我正在尝试执行一个实现
ngModelController
api的自定义指令,以便在表单中使用自定义指令时可以使用Angular的本机表单验证(这依赖于ngModelController
)。
<form name="outerForm">
<my-directive
ng-model="ctrl.myComplexModel"
name="myDirectiveInstance"
custom-required="ctrl.EnableValidateOne"
toggle-another-validation="ctrl.EnableValidateTwo">
</my-directive>
<div ng-messages="outerForm.myDirectiveInstance.$error">
<ng-message when="customRequired">This is required.</ng-message>
<ng-message when="anotherValidation">This is required.</ng-message>
<ng-message when="innerValidationOne">Something wrong with field 1.</ng-message>
<ng-message when="innerValidationTwo">Something wrong with field 2.</ng-message>
<ng-message when="innerValidationThree">Something wrong with field 3.</ng-message>
<!-- etc... -->
</div>
</form>
<div ng-form="myDirectiveForm">
<div ng-class="{'has-error': myDirectiveForm.fieldOne.$invalid}">
<ui-select
ng-model="model.fieldOne"
name="fieldOne"
required>
</ui-select>
</div>
<div ng-class="{'has-error': myDirectiveForm.fieldTwo.$invalid}">
<input
type="number"
ng-model="model.fieldTwo"
name="fieldTwo"
ng-pattern="directiveCtrl.someRegEx"
ng-required="directiveCtrl.fieldTwoIsRequired">
</div>
<!-- etc... -->
</div>
app.directive('myDirective', function() {
return {
restrict: 'E',
template: 'myDirectiveTemplate.html',
controller: 'MyDirectiveCtrl',
scope: {
model: '=ngModel',
customRequired: '=?',
toggleAnotherValidation: '=?'
},
require: 'ngModel',
link: function(scope, iElem, iAttrs, ngModelController) {
// Black-box the internal validators
// Custom validator to avoid conflicts with ngRequired
ngModelController.$validators.customRequired = function(modelValue, viewValue) {
if(!scope.customRequired)
return true;
// On first digest the field isn't registered on the form controller yet
if(angular.isUndefined(scope.myDirectiveForm.fieldOne))
return true;
return !scope.myDirectiveForm.fieldOne.$error.required;
};
ngModelController.$validators.anotherValidation = function(modelValue, viewValue) {
if(!scope.anotherValidation)
return true;
return scope.passesBusinessRule();
};
ngModelController.$validators.innerValidationOne = function(modelValue, viewValue) {
if(!scope.anotherValidation)
return true;
if(angular.isUndefined(scope.myDirectiveForm.fieldTwo))
return true;
return !scope.myDirectiveForm.fieldTwo.$error.pattern;
};
/* etc... */
// Deep-watching model so that validations will trigger on updates of properties
scope.$watch('model', function() {
ngModelController.$validate();
}, true);
}
};
});
<form name="outerForm">
<my-directive
model="ctrl.myComplexModel"
name="myDirectiveInstance"
custom-required="ctrl.EnableValidateOne"
toggle-another-validation="ctrl.EnableValidateTwo">
</my-directive>
<div>
<span ng-if="outerForm.myDirectiveInstance.fieldOne.$error.required">Internal field 1 is required.</span>
<span ng-if="outerForm.myDirectiveInstance.fieldTwo.$error.required">Internal field 2 is required.</span>
<span ng-if="outerForm.myDirectiveInstance.fieldTwo.$error.pattern">Internal field 2 format error.</span>
<!-- etc... -->
<ng-messages for="outerForm.myDirectiveInstance.$error">
<ng-message when="required">At least one required field is missing.</ng-message>
<ng-message when="custom">
Some directive-wide error set by validate-custom on outerForm.myDirectiveInstance.internalField
</ng-message>
<!-- etc... -->
</ng-messages>
</div>
</form>
<div ng-form="{{ formName }}">
<div ng-class="{'has-error': isInvalid('fieldOne')}">
<ui-select
ng-model="model.fieldOne"
name="fieldOne"
required>
</ui-select>
</div>
<div ng-class="{'has-error': isInvalid('fieldTwo')}">
<input
type="number"
ng-model="model.fieldTwo"
name="fieldTwo"
ng-pattern="directiveCtrl.someRegEx"
ng-required="directiveCtrl.fieldTwoIsRequired">
</div>
<!-- etc... -->
<input
type="hidden"
ng-model="someCalculatedValue"
name="internalField"
validate-custom>
</div>
app.directive('myDirective', function() {
return {
restrict: 'E',
template: 'myDirectiveTemplate.html',
controller: 'MyDirectiveCtrl',
scope: {
model: '=',
customRequired: '=?',
toggleAnotherValidation: '=?',
formName: '@name'
},
};
});