javascript - 如何清除隐藏时的 Angularjs 子表单模型值?

标签 javascript angularjs

我正在尝试清除隐藏时的 angularjs 子表单模型值。我有某种用于 ng-if 的条件来隐藏表单的某些部分,并希望如果 ng-if 条件再次返回 true,则表单的该部分没有数据。就这样,这不会那么困难...???

<form name="parentForm">
<input type="text" name="alwaysRequired" ng-model="model.required" required /> 
<h3>Parent Form</h3>
<input type="checkbox" name="showOptionalFormSelected" ng-model="model.showOptional" id="showOptionalForm" /> 
<label for="showOptionalForm">show optional form</label>
<div ng-if="model.showOptional" clear-forms-on-hide>
  <h3>Optional Form</h3>
  <div ng-form="optionalForm">
  <input type="text" name="optionalInputName" ng-model="model.optionalValue" required />
  </div>
</div>
</form>

我希望它尽可能简单,代码中没有太多指令。

我尝试的一切都不起作用,因为当我试图获取模型绑定(bind)并重置它们时,整个范围树都被破坏了。

  • 如果我使用 ng-show 它可以工作,但是这些输入上的所有验证器都会崩溃,并且所有这些表单都被标记为 $invalid。
  • 如果我尝试获取每个 ng-model,使用它的字符串值,获取范围,使用 $parse 生成访问器,我只能使用它来处理已损坏的范围。
  • 我还没有尝试使用 $destroy 并希望作用域仍然能够写入模型,但我对此表示怀疑。我担心在导航离开时会弄乱导航并删除我的数据。
  • 我尝试收集这些表单中的所有字段,并删除具有更高优先级的指令中的数据,但那些收集的 ng-model 只能看到被破坏的范围:-/

对于最后一次尝试,我重建了一个小型的独立示例,以某种方式重现了该问题:

'use strict';
angular.module('clearForm', [])
  .component('formBox', {
    template: `<div ng-form="{{$ctrl.innerFormName}}"><ng-transclude /></div>`,
    transclude: true,
    bindings: {
      innerFormName: '<'
    }
  })
  .component('inputComponent', {
    template: `<input type="text" name="{{$ctrl.inputName}}" ng-model="$ctrl.ngModel" required />`,
    transclude: true,
    bindings: {
      inputName: '<',
      ngModel: '='
    }
  })
  .controller('InitModelController', ['$scope', function InitModelController($scope) {
    $scope.model = {
      optionalValue: 'test',
      showOptional: true,
      required: 'important something we need',
      optional2: {
        one: 'one',
        other: 'other',
      },
      componentInput: 'component input'
    };
  }])
  .directive('clearFormsOnHide', function clearFormOnHide() {
    return {
      restrict: 'A',
      priority: 700,
      bindings: {
        ngIf: '<',
      },
      link: function(scope, element, attr) {
        if (!attr.ngIf)
          throw new Error('This directive must be used together with ng-if!');

        let formsWatch = null;
        let inputsToClear = [];
        scope.$watch(attr.ngIf, onIfChange);

        function onIfChange(showContent) {
          if (!showContent) {
            if (formsWatch) formsWatch();
            clearKnownInputs();
          } else
            formsWatch = scope.$watch(attr.clearFormsOnHide, collectNgModelElementsFromForms);
        }

        function collectNgModelElementsFromForms(formsToClear) {
          if (!formsToClear)
            throw new Error('No form named ' + attr.clearFormsOnHide + ' found in current scope.', scope);
          if (!window.angular.isArray(formsToClear))
            formsToClear = [formsToClear];
          formsToClear.forEach(collectNgModelsFromForm);
        }

        function collectNgModelsFromForm(form) {
          Object.values(form)
            .filter((ele) => ele && ele.hasOwnProperty('$touched'))
            .forEach(element => inputsToClear.push(element));
        }

        function clearKnownInputs() {
          inputsToClear.forEach(clearNgModel);
          inputsToClear = [];
        }

        function clearNgModel(hiddenNgModel) {
          hiddenNgModel.$rollbackViewValue();
          hiddenNgModel.$setViewValue(null);
          hiddenNgModel.$commitViewValue();

          // eslint-disable-next-line
          hiddenNgModel.$$ngModelSet(hiddenNgModel.$$scope, null);
          hiddenNgModel.$setUntouched();
          hiddenNgModel.$setPristine();
          hiddenNgModel.$render();
        }
      }
    };
  });
input[type="text"] {
  display: block;
}
<script src="//code.angularjs.org/1.6.6/angular.js"></script>
<script src="script.js"></script>
<link href="style.css" rel="stylesheet" type="text/css">
<div ng-app="clearForm" ng-strict-di ng-controller="InitModelController">
  <form name="parentForm">
    <h3>Parent Form</h3>

    <input type="text" name="alwaysRequired" ng-model="model.required" required />
    <input type="checkbox" name="showOptionalFormSelected" ng-model="model.showOptional" id="showOptionalForm" />
    <label for="showOptionalForm">show optional form</label>
    <div ng-if="model.showOptional" clear-forms-on-hide="[parentForm.optionalForm,parentForm.optionalForm2]">
      <h3>Optional Form</h3>
      <div ng-form="optionalForm2">
        <div ng-repeat="name in ['one','other']">
          <input type="text" name="optionalForm2_{{name}}" ng-model="model.optional2[name]" required />
        </div>
      </div>

      <div ng-form="optionalForm">
        <input type="text" name="optionalInputName" ng-model="model.optionalValue" required />
        <input-component input-name="componentInputName" ng-model="model.componentInput"> </input-component>
        <label for="showOptionalDateCheckbox">show optional date</label>
        <input type="checkbox" name="optionalInputCheckboxName" id="showOptionalDateCheckbox" ng-model="model.optionalCheck" required />
      </div>

    </div>
    <form-box inner-form-name="'boxedOptionalForm'" ng-if="model.optionalCheck" clear-forms-on-hide="[parentForm.boxedOptionalForm]">
      <input type="date" name="optionalDate" ng-model="model.optionalDate" />
    </form-box>
  </form>
  <ul>

    <li>always required value: {{model.required|json}}</li>
    <li>hide optional: {{model.showOptional|json}}</li>
    <li>optional 2 value one: {{model.optional2.one|json}}</li>
    <li>optional 2 value other: {{model.optional2.other|json}}</li>
    <li>optional value: {{model.optionalValue|json}}</li>
    <li>optional checkbox: {{model.optionalCheck|json}}</li>
    <li>optional component input: {{model.componentInput|json}}</li>
    <li>optional date: {{model.optionalDate|json}}</li>
  </ul>
</div>

我们几乎所有的事情都使用组件,但这并不会让事情变得更容易:-/

  • 我们为每个包含表单的可视框都有一个框组件,这使得在不知道其名称的情况下很难获取表单。
  • 所有输入元素也都包装在组件中。因此,任何需要靠近输入的东西都需要能够关闭,并且需要在所有这些组件中进行配置,并且不鼓励这样做。
  • 所有这些子输入都是嵌套的,具有不同的范围,位于 ng-repeats 内部,相互依赖。这使得很难在另一个作用域中使用它们的 ng-model 字符串,并且很容易在 Controller 中复制逻辑来手动删除模型。

有人知道如何删除一堆模型值而不单独指定它们,但仍然使用 ng-if 吗?如果仅清除表单或仅清除 ng-model 值,这并不重要。

最佳答案

在指令中创建方法 resetModel() 并更改代码:

<input type="checkbox" name="showOptionalFormSelected" ng-model="model.showOptional" id="showOptionalForm" ng-change="resetModel(model)" />

然后在resetModel()方法中重置模型。

关于javascript - 如何清除隐藏时的 Angularjs 子表单模型值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46933770/

相关文章:

javascript - 用于网站流媒体的免费音频播放器

javascript - 如何将非作用域变量传递给 AngularJS 过滤器?

javascript - 复选框错误值未传递给 Angular 模型

javascript - 如何通过代码清理使动态导入/需要依赖于变量?

javascript - Angularjs ng-有条件重复

javascript - 使用变量一次

javascript - 将 JS 库 xml2js 与 Angular 2 结合使用

php - 使用 PHP/Ajax 在 Jquery Lightbox 中获取结果

javascript - 动态模板和范围变量

javascript - 这个函数可以递归或更干净地重写吗?