【问题标题】:Angular $broadcast called inside ng-repeat fires multiple times在 ng-repeat 中调用的 Angular $broadcast 多次触发
【发布时间】:2015-06-01 02:49:44
【问题描述】:

我在 ng-repeat 中嵌套了一个带有按钮的表单,该按钮的点击事件调用了一个函数,该函数执行了一些事情,包括 $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 中的样式和演示代码的其他方面之类的东西是禁止的。我这样做只是为了让 plunkr 更快。

TIA

【问题讨论】:

    标签: javascript angularjs forms broadcast


    【解决方案1】:

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

    您需要为每个步骤创建单独的控制器。如果你真的必须的话,一个黑客可能会阻止 $on 处理程序,但我只会在公共服务中创建具有逻辑的单独控制器。或者可能是基控制器和子控制器(它们之间的继承)

    【讨论】:

      【解决方案2】:

      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>
      

      从部分中删除指令,所以你只有这个:

      <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 > 
      

      【讨论】:

      • 好吧,这是有道理的,但“部分”实际上来自 ui 路由器状态定义,所以索引中的
        实际上是一个
        和控制器名称来自状态。为了简单起见,我没有把所有这些都放在 plunkr 中。因此,尽管您的答案有效,但当每个 ng-repeat 处于单独状态时,我需要弄清楚如何解释它。
    • 只需从配置中的状态中删除控制器分配,然后像我一样分配控制器。您的状态将在 testCtrl 的上下文中加载。
    • 【解决方案3】:

      感谢您让我走上正轨的回复。使用状态的整个想法是让控制器来自那里,所以把它放在 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 应用程序。谢谢你把我带到这里!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-17
        • 1970-01-01
        • 2014-02-02
        • 2016-03-07
        • 1970-01-01
        • 2016-01-17
        • 1970-01-01
        相关资源
        最近更新 更多