在ng-repeat中调用的Angular $ broadcast多次触发

时间:2015-06-01 02:49:45

标签: javascript angularjs forms broadcast

我在ng-repeat中嵌套了一个带有按钮的窗体,其click事件调用的函数包括$ scope。$ broadcast。除了在ng-repeat中每个项目上触发的广播之外,函数中的所有内容都会触发一次。

我无法在重复之外移动按钮,或者我丢失了表单和数据引用。我有一个演示plunker,显示基本设置。如果在其中一个输入中输入值,并在监视控制台时单击“下一步”,则应多次看到广播触发(每个ng-repeat项目一次)。我需要的是一种让广播只触发一次的方法,同时仍然保持对表单的引用,以便根据演示代码进行验证检查。

这是JS,其余的是plunker

(function () {
var app = angular.module('App', []),
  /** manually triggers $validate event to validate the given form */
isFormValid = function ($scope, ngForm) {
  var i = null;
  //$scope.$emit('$validate');
  $scope.$broadcast('$validate');

  if(! ngForm.$invalid) {
    return true;
  } else {
    // make the form fields '$dirty' so that the validation messages would be shown
    ngForm.$dirty = true;

    for(i in ngForm) {
      if(ngForm[i] && ngForm[i].hasOwnProperty && ngForm[i].hasOwnProperty('$dirty')) { // TODO: is 'field.$invalid' test required?
        ngForm[i].$dirty = true;
      }
    }
  }
};

app.controller('appCtrl', ['$scope', function ($scope) {


    $scope.wizardStep = 1;
    $scope.nextStep = function () {
      var ngForm = $scope['stepForm_' + $scope.wizardStep];
      if(isFormValid($scope, ngForm)) { // trigger manual validation
        $scope.wizardStep++;
      }
    };
    $scope.prevStep = function () {
      $scope.wizardStep--;
    };
    $scope.submit = function () {
      var ngForm = $scope['stepForm_' + $scope.wizardStep]; // we can make this line common
      if(isFormValid($scope, ngForm)) {
        alert('Form is valid. Submitting...');
      }
    };

  }]);
})();

非常感谢任何帮助或想法,我知道html中的样式和演示代码的其他方面都是禁忌的。我只是做了那些让更快的傻瓜。

TIA

3 个答案:

答案 0 :(得分:0)

该事件仅被触发一次。问题是testCtrl正在使用3次,所以它正在捕获事件3次。

您需要为每个步骤创建单独的控制器。如果你真的必须,hack可以在$处理器上去抖动,但我只是在公共服务中用逻辑创建单独的控制器。或者可能是基本控制器和子控制器(它们之间的继承)

答案 1 :(得分:0)

Updated Plunker

您正在每个模板中重复实例化控制器。您只需要通过使用包含ng-controller指令的div包装表单一次实例化它:

    <div ng-controller="testCtrl">
      <form name="wizardForm" novalidate="">
        <div ng-repeat="step in steps" ng-init="stepForm ='stepForm' + ($index + 1)">
          <ng-form name="{{stepForm}}" ng-show="currentStep == $index + 1">
            <div ng-include="step.partial"></div>
            <div class="form-group wiz-btns">
              <div class="col-md-12 text-center">
                <button ng-show="currentStep > 1" type="button" class="btn btn-green" ng-click="prevStep()">
                  <span class="glyphicon glyphicon-circle-arrow-left"></span>


                Previous
              </button>
                <button ng-show="currentStep < steps.length" type="button" class="btn btn-green" ng-click="nextStep(wizardForm[stepForm])">
                Next                                         <span class="glyphicon glyphicon-circle-arrow-right"></span>
                </button>
                <!-- TODO: final submit buton -->
                <!--<button></button>-->
              </div>
            </div>
          </ng-form>
        </div>
      </form>
    </div>

从partials中删除指令,所以你就是这样:

<label class="wiz-label" for="title">Step1 Input:</label>
<input type="text" class="form-control" name="step1" ng-model="data.step1" required/>
<span ng-show="stepForm1.$dirty && stepForm1.step1.$invalid" style="background:red;">Input required</span > 

答案 2 :(得分:0)

感谢您的回复让我走上正轨。使用状态的整个想法是控制器来自那里,所以将它放在html中将无法满足实际需要。

然而,基于先前的回复,该决议对我来说实际上是一个DUH时刻。我所要做的就是在index.html中改变这一行:

<ng-form name="{{stepForm}}" ng-show="currentStep == $index + 1">   

要:

<ng-form name="{{stepForm}}" ng-if="currentStep == $index + 1">  

将此更改从 ng-show 更改为 ng-if 仅将子表单和状态(控制器) )一次而不是每一步一次。这适用于使用状态的pluntr和我的rela应用程序。谢谢你带领我这个!