angularjs – 使用Angular指令进行复杂表单验证/ GUI操作的Pro / con

前端之家收集整理的这篇文章主要介绍了angularjs – 使用Angular指令进行复杂表单验证/ GUI操作的Pro / con前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在构建一个新的SPA前端,以取代现有企业遗留的过时且需要更新的系统大杂烩.我是棱角分明的新人,想看看社区能否给我一些看法.我会陈述我的问题,然后问我的问题.

我必须根据来自.js include的数据生成几个复选框系列,其数据如下:

$scope.fieldMappings.investmentObjectiveMap = [
  {'id':"CAPITAL PRESERVATION",'name':"Capital Preservation"},{'id':"STABLE",'name':"Moderate"},{'id':"BALANCED",'name':"Moderate Growth"},// etc
  {'id':"NONE",'name':"None"}
];

使用ng-repeat创建复选框,如下所示:

<div ng-repeat="investmentObjective in fieldMappings.investmentObjectiveMap">
     ...
    </div>

但是,我需要复选框表示的值映射到不同的模型(不仅仅是双向绑定到fieldmappings对象).为了实现这一点,我创建了一个指令,它接受目标数组destarray,最终映射到模型.我也知道我需要处理一些非常具体的gui控件,例如如果检查了其他任何内容则取消选中“None”,或者如果其他所有内容都未选中则选中“None”.此外,“无”在每组复选框中都不是一个选项,因此指令需要足够通用以接受验证功能,该功能可以根据已经点击的内容调整复选框组输入的选中状态,但是智能如果没有名为“NONE”的选项,就不会破坏.我开始通过添加一个在控制器中调用函数的ng-click来做到这一点,但是在查看堆栈溢出时,我读到人们说将DOM操作代码放在控制器中是不好的 – 它应该在指令中.那我需要另一个指令吗?

至今:
(HTML):

<input my-checkBox-group
              type="checkBox"
              fieldobj="investmentObjective"
              ng-click="validationfunc()"
              validationfunc="clearOnNone()"
              destarray="investor.investmentObjective" />

指令代码

.directive("myCheckBoxGroup",function () {
  return {
    restrict: "A",scope: {
      destarray:      "=",// the source of all the checkBox values
      fieldobj:       "=",// the array the values came from
      validationfunc: "&"   // the function to be called for validation (optional)
    },link: function (scope,elem,attrs) {
      if (scope.destarray.indexOf(scope.fieldobj.id) !== -1) {
        elem[0].checked = true;
      }
      elem.bind('click',function () {
        var index = scope.destarray.indexOf(scope.fieldobj.id);
        if (elem[0].checked) {
          if (index === -1) {
            scope.destarray.push(scope.fieldobj.id);
          }
        }
        else {
          if (index !== -1) {
            scope.destarray.splice(index,1);
          }
        }
      });
    }
  };
})

.js控制器片段:

.controller( 'SuitabilityCtrl',['$scope',function ( $scope ) {
  $scope.clearOnNone = function() {
    // naughty jQuery DOM manipulation code that
    // looks at checkBoxes and checks/unchecks as needed
  };

上面的代码完成并正常工作,除了clearOnNone()中的顽皮jquery代码,这就是我写这个问题的原因.

这是我的问题:在所有这些之后,我想我自己 – 如果我只是用我的控制器中编写的jQuery手动处理所有这些GUI逻辑和验证垃圾,我就可以完成.在编写这些复杂的指令时,未来的开发人员将不得不解决的问题在于,如果我刚刚编写了jQuery代码,我们99%的人会一目了然地理解它,那么在什么时候变得愚蠢呢?其他开发者如何划清界限?

我看到整个堆栈溢出.例如,this question似乎可以用十几行简单的jQuery来回答,但是他选择了角度方式,指令和部分……对于一个简单的问题似乎需要做很多工作.

我不希望这个问题违反规则,所以具体来说,我想我想知道:我应该如何编写代码来检查是否选择了“无”(如果它作为选项存在于此组中复选框),然后相应地选中/取消选中其他框?更复杂的指令?我无法相信我是唯一一个必须实现代码的开发人员,而这些代码只是为了满足一个固定的框架而需要更复杂的代码.我需要使用另一个util库吗?

我根据Jim的建议将它发布在Programmers.StackExchange.com上.与此同时,我决定采用一种解决方案来处理所有棘手的DOM操作.

我尝试了两种方法 – 在控制器中处理DOM事件,并通过指令处理它:

(通过控制器) – .js代码

$scope.clearOnNone = function(groupName,$event) {
    var chkBoxArr = $('input[name^=' + groupName + ']'),nonNoneValChecked = false,targetElem = null,labelText = "";

    // get the target of the click event by looking at the <label> sibling's text
    targetElem = event.target.nextElementSibling.textContent.trim();

    // if target was the None option,uncheck all others
    if (targetElem === "None") {
      chkBoxArr.each(function() {
        labelText = this.nextElementSibling.textContent.trim();

        if (labelText !== "None") {
          this.checked = false;
        }
      });
    }
    // if the target was anything BUT the None option,uncheck None
    else {
      chkBoxArr.each(function() {
        labelText = this.nextElementSibling.textContent.trim();

        if (labelText === "None") {
          this.checked = false;
        }
      });
    }
  };

(通过控制器) – HTML代码

<div ng-repeat="investmentObjective in fieldMappings.secondaryInvestmentObjectiveMap">
        <input checkBox-group
                type="checkBox"
                name="secondaryInvestmentObjective"
                ng-click="validationfunc('secondaryInvestmentObjective',$event)"
                validationfunc="clearOnNone('secondaryInvestmentObjective',$event)"
                fieldobj="investmentObjective"
                destarray="suitabilityHolder.suitability.secondaryInvestmentObjective" />
        <label class="checkBox-label"
                popover-title="{{investmentObjective.name}}"
                popover="{{investmentObjective.help}}"
                popover-trigger="mouseenter">{{investmentObjective.name}}
        </label>
      </div>

(通过控制器) – 指令代码

.directive("checkBoxGroup",1);
          }
        }
      });
    }
  };
})

然后我决定讨厌event.target.nextElementSibling.textContent.trim()行…我觉得我应该仔细检查所有这些方法是否存在,或者使用try / catch.所以我重写了指令以包含来自控制器的逻辑:

(通过指令) – HTML代码

<div ng-repeat="otherInvestment in fieldMappings.otherInvestmentsMap">
        <input type="checkBox"
                checkBox-group
                groupname="otherInvestment"
                labelvalue="{{otherInvestment.name}}"
                fieldobj="otherInvestment"
                destarray="suitabilityHolder.suitability.otherInvestment" />
        <label class="checkBox-label"
                popover-title="{{otherInvestment.name}}"
                popover="{{otherInvestment.help}}"
                popover-trigger="mouseenter">{{otherInvestment.name}}
        </label>
      </div>

(通过指令) – 指令代码

.directive("checkBoxGroup",// the array the values came from
      groupname:      "@",// the logical name of the group of checkBoxes
      labelvalue:     "@"   // the value that corresponds to this checkBox
    },attrs) {
      // Determine initial checked Boxes
      // if the fieldobj.id exists in the destarray,check this checkBox
      if (scope.destarray.indexOf(scope.fieldobj.id) !== -1) {
        elem[0].checked = true;
      }

      // Update array on click
      elem.bind('click',function () {
        // store the index where the fieldobj.id exists in the destarray
        var index = scope.destarray.indexOf(scope.fieldobj.id),// get the array of checkBoxes that form this checkBox group
            chkBoxArr = $('input[groupname^=' + scope.groupname + ']');

        // Add if checked
        if (elem[0].checked) {
          if (scope.labelvalue === "None") {
            // loop through checkBoxes and uncheck all the ones that are not "None"
            chkBoxArr.each(function() {
              // have to noodle through the checkBox DOM element to get at its attribute list
              // - is there a cleaner way?
              var tmpLabelValue = this.attributes.labelvalue.nodeValue.trim();
              if (tmpLabelValue !== "None") {
                this.checked = false;
              }
            });
          }
          // if the target was anything BUT the None option,uncheck None
          else {
            chkBoxArr.each(function() {
              var tmpLabelValue = this.attributes.labelvalue.nodeValue.trim();

              if (tmpLabelValue === "None") {
                this.checked = false;
              }
            });
          }

          if (index === -1) {
            // add the id to the end of the dest array
            // **will not maintain original order if several are unchecked then rechecked**
            scope.destarray.push(scope.fieldobj.id);
          }
        }

        // Remove if unchecked
        else {
          if (index !== -1) {
            scope.destarray.splice(index,1);
          }
        }
      });
    }
  };
})

回想起来,我想我更喜欢在指令中包含所有代码,尽管我认为它比通过jQuery在控制器中抛出所有处理更不直观和复杂.它从控制器中删除了clearOnNone()函数,这意味着在html标记和指令中处理此功能的所有代码.

我不喜欢this.attributes.labelvalue.nodeValue.trim()这样的代码,我仍然在我的指令中结束了.对于像我这样的场景,业务部门有一定的要求(没有其他方式可以放置它)既繁琐又繁琐,我不知道真的有一种“干净”的方式来编写它.

原文链接:https://www.f2er.com/angularjs/141761.html

猜你在找的Angularjs相关文章