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'
        },
      };
    });