Triggering Angular's $broadcast within an ng-repeat causes repeated firing of events

In my AngularJS application, I have a situation where I am nesting forms inside an ng-repeat. The issue arises when a button within the repeat triggers a function that includes a $scope.$broadcast. While everything else in the function executes correctly, the broadcast ends up triggering multiple times - once for each item in the ng-repeat.

Unfortunately, moving the button outside of the ng-repeat is not an option as it would result in loss of form and data references. I have created a demonstration on Plunker showcasing this setup. If you input values in one of the inputs and click "next" while monitoring the console, you will observe the broadcast firing multiple times. My goal is to find a solution where the broadcast only fires once while still having access to the form for validation checks as shown in the demo code.

Below is the JavaScript code excerpt, and the rest can be found on the 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...');
      }
    };

  }]);
})();

I welcome any suggestions or assistance on how to address this issue. I understand that certain elements like inline styles in the HTML are not recommended practices, but they were included in the Plunker for expediency.

Thank you in advance.

Answer №1

There is a minor issue with the event firing repeatedly. This occurs because the testCtrl is being utilized multiple times, triggering the event each time.

To resolve this, it's advisable to develop individual controllers for each specific step. An alternative approach would be to debounce the $on handler if necessary, although creating distinct controllers with shared logic in a service or implementing inheritance between a base controller and child controllers may be more efficient.

Answer №2

Check out the Updated Plunker here

The issue lies in instantiating the controller multiple times within each template. To resolve this, simply instantiate it once by enclosing your form within a div that includes the ng-controller directive:


    <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 button -->
                <!--<button></button>-->
              </div>
            </div>
          </ng-form>
        </div>
      </form>
    </div>

Make sure to remove the directive from the partials, resulting in the following code snippet:

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

Answer №3

I am grateful for the helpful responses that steered me in the right direction. It became clear to me that utilizing states is essential for ensuring the controller originates from there, rather than including it directly in the html.

Upon reflecting on the advice given earlier, I had a moment of realization. The solution was actually quite straightforward - all I needed to do was modify this line in index.html:

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

To:

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

By changing ng-show to ng-if, I ensured that the child form and state (controller) are only included once per step instead of multiple times. This adjustment proved effective in both the pluntr and my rela app when employing states. Thank you for guiding me towards this solution!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leveraging Prototype's Class creation function to declare confidential and safeguarded attributes and functions

Looking for a solid approach to defining private and protected properties and methods in Javascript? Check out this helpful discussion here on the site. Unfortunately, the current version of Prototype (1.6.0) doesn't offer a built-in method through it ...

Connect jQuery navigation button to a specific web address

Check out this cool jQuery menu script I found: <script type="text/javascript> jQuery(document).ready(function(){ jQuery('#promo').pieMenu({icon : [ { path : "/wp-content/t ...

Utilize the underscore method countBy to analyze the nested properties of objects within an array

When working with JavaScript, I am handling an array of objects structured as shown below: [ { "fields": { "assignee": { "email": "emailid1", "name": "name1" } } }, { "fields": { "assignee": { "e ...

Prevent redirection when submitting and show an error message instead

I implemented a login system where, upon entering the correct username and password, a token is stored in local storage. If there's an error with the credentials, an "Login Unsuccessful" message is displayed. Everything was functioning correctly until ...

What is the best way to create fading text effects in an AngularJS application?

Running an AngularJS web application that showcases three words for 5 seconds each: Hello, World & Goodbye. The controller setup is as follows: self.currentIndex = 0; self.myTexts = ['Hello', 'World', 'Goodbye']; self.cu ...

Display scroll bars over the position:absolute header

My container has content that exceeds its size in both directions. To see the issue, try scrolling horizontally and vertically on the table available here: The vertical scrollbar is visible as desired, except that it gets hidden behind the table header un ...

I have a question about CSS selectors: How can I change the font color of a parent <li> element when the child

After struggling for hours, I'm finally throwing in the towel on this issue. I have an unordered list with no background at the top level and text color of #fff. When rolled over, the background turns #fff and the text color turns #000. The child ul ...

What is the proper method for invoking a function when an HTTP request is made, whether it

Forgive me for asking what may seem like a silly question, but I am new to working with the backend. I am currently developing an AngularJS app using Express/Node and I am attempting to implement PayPal (using the Node.js SDK). My goal is to call the pay ...

Presentation: Troubleshooting Ineffective CSS3 Transitions

I have created a basic slideshow that can accommodate multiple images. Clicking on an image should move to the next slide, and once the last image is clicked, it should loop back to the first slide. The functionality of transitioning between slides seems ...

Changing table data using a switch in mui-datatables when my information is stored as boolean values

How can I update my boolean data in a Switch component for each row fetched from Firestore? The data is currently being displayed correctly, but when I click on the Switch to change it from true to false or vice versa, nothing happens. Can someone help me ...

Guide on handling asynchronous data return within a reducer

I'm struggling to properly handle the state when receiving data from the back-end of my application. This is the code I have: if (action.type === actionTypes.getList) { const id = action.payload.userId; Axios.post(`${apiUrl}/lists`, { ...

What are the best ways to transfer information between functional components in a React application?

When working with React, data exchange between class-based components can be done using states and props in the following way: App.js import Name from './Name'; import React, { Component } from 'react' export class App extends Compo ...

Retrieve the smallest value from an array of objects using BitGO

Bitgo stores all transactions as objects within a large array. Within the nested .entries, we can identify that the first TX object contains two negative values -312084680 and -4254539, of which I only require the lowest value. My current code successfully ...

What are the steps to activate code suggestion with codemirror?

My goal is to implement CodeMirror for enabling users to input code in various languages like CSS, HTML, and JavaScript. One specific requirement is to provide hints to the user when typing code in CSS mode. div { padding- } The system should prompt th ...

A guide on how to group by multiple keys and calculate the sum of multiple property values within a JavaScript array using Node.js

Can you suggest the most efficient method to group by multiple keys and calculate the sum of multiple property values in a JavaScript array? For example: [ { Category: "Category 1", Subcategory: "Subcategory 1", Value1: "15&q ...

Creating an app using Ionic 1 that features scrollable tabs with the ability to handle overflow

My current code snippet is displayed below. On smaller mobile screens, all 7 tabs are not visible at once and instead appear in two rows which looks messy. I want to modify the display so that only 3 tabs are visible at a time and can be scrolled through. ...

Is the JSON data not matching the file's content during validation?

After thorough testing, my JSON data appears to be functioning correctly with regular content. Here is a sample of the working JSON: Working Json { "language": "XYZ", "content": { "GEN": "this is test& ...

What is the best way to eliminate backslash escaping from a JavaScript variable?

I am working with a variable called x. var x = "<div class=\\\"abcdef\\\">"; The value of x is <div class=\"abcdef\"> However, I want it to be <div class="abcdef"> Can someone help me unescape ...

Ways to center your attention on the Textbox

I am currently developing a chat program using JavaScript, HTML, and CSS. How can I set the focus on the input field for typing messages? Is it usually done with CSS code? Here is the current CSS styling for my message input field: Code: #messageField ...

Transferring information from one page to the next

How can I efficiently transfer a large amount of user-filled data, including images, between pages in Next.js? I've searched through the Next.js documentation, but haven't found a solution yet. ...