Receiving Console Error When Attempting to Implement ngClass Directive Within Another Directive

I have encountered a console error while trying to utilize ngClass within my directive. The specific error message reads:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

To demonstrate this issue, here is a simplified version of the directive causing the problem:

angular.module('myApp', [])
    .directive('myDirective', function () {
    return {
        restrict: 'E',
        scope: {
            myNgClass: '='
        },
        template: '<div ng-class="myNgClass">Hello World</div>'
    }
});

Furthermore, I am implementing the directive in the following manner:

<my-directive my-ng-class="{'green':true}"></my-directive>

You can also access a related jsFiddle link.

Answer №1

First and foremost, this issue is specific to the version of Angular being used (v1.2.1) - it was resolved in v1.2.5 (see demo with v1.2.5).

Secondly, it is advisable not to utilize two-way binding ("=") if there is no need to modify the value from within the directive. Unnecessarily using "=" creates 2 watchers.

Instead, opt for one-way string binding ("@"), like this:

scope: {
  myNgClass: '@'
},
template: '<div ng-class="{{myNgClass}}">Hello World</div>'

However, bear in mind that this approach has limited functionality. For instance, passing an object (

$scope.greenStyle = { green: true };
) to the directive won't work as expected:

<my-directive my-ng-class="greenStyle"></my-directive>

It's more effective to use a one-way binding to expressions - "&". This method maintains a single watch and binds to an object instead of a string. The scope.myNgClass now acts as a function returning the value of the bound expression:

scope: {
  myNgClass: '&'
},
template: '<div ng-class="myNgClass()">Hello World</div>'

View Demo

Answer №2

Replace using @ instead of =.

myNgClass: '@'

When you opt for =, angular sets up a $watch for changes to 'myNgClass'. Adding a $watch leads anguar to include $$hashKey to the object and "tries" to assign back the modified object to its original source (ensuring both have the same object).

The issue arises during $digest comparison where it has

{'green':'true', $$hashKey: '123546246'}
against the evaluated expression {'green':'true'}. This results in a failed comparison triggering the $watch listener (NOTE: This is just a theory. I am not completely certain about the addition of hashKey, but what I do know is that it considers the objects as distinct instances causing the watch listener to trigger). As my-ng-class always returns a new instance of that object, it will always be unique and thus activate the watch listener.

If you still prefer using = (though there's no necessity), you simply need to define your initial object once elsewhere before passing it through. You can use ng-init for this purpose, like so:

<my-directive ng-init="clazz={'green':'true'}" my-ng-class="clazz"></my-directive>

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

Converting camera space coordinates to scene space in three.js

I want to position a cube relative to the camera instead of relative to the scene. However, in order to display it in the scene, I need to determine the scene coordinates that align with the cube's camera space coordinates. I came across the function ...

Error encountered when attempting to insert data into a PostgreSQL database using Node.js and Sequelize

I'm currently using the node sequelize library to handle data insertion in a postgress database. Below is the user model defined in the Users.ts file: export class User extends Sequelize.Model { public id!: number; public name: string; public ...

Creating flexible Vue routes using a single router component and a navigational menu

I am working on a Vue project and I want to implement nested routes in my router.js. My goal is to have just one menu for all the nested routes and only one <router-view></router-view> in a master component. This is what I envision (in pseudoc ...

When using the Node.js drive API, setting the emailMessage while creating a permission does not trigger the sending of an

Working with Node.js and the googleapis v61.0.0 client to utilize drive api v3. Strange issue encountered when attempting to create a permission: setting the 'emailMessage' param to anything other than an empty string (or not specifying it at all ...

What is the best way to pick an option from a dropdown menu using angularjs?

Is there a way to select an item from a dropdown list in AngularJS without using ng-repeat with an object array? I can easily select an option when using ng-repeat, but how can this be achieved with a normal select list? <select class="form-control" ...

Transform Array into JSON using AngularJS

My array consists of three elements var data = []; data["username"]=$scope.username; data["phoneNo"]=$scope.phoneNo; data["altPhoneNo"]=$scope.altPhoneNo; I need to send this data to the server in JSON format, so I used var jsonData = JSON.str ...

Node.js: The choice between returning the original Promise or creating a new Promise instance

Currently, I am in the process of refactoring a codebase that heavily relies on Promises. One approach I am considering is replacing the new Promise declaration with simply returning the initial Promise instead. However, I want to ensure that I am correctl ...

After performing a replacement, the appendChild() method may not function as expected

Currently, I am delving into the world of creating a Firefox extension. Although I have never ventured into extension development before and my grasp on JS/JSON/XML is limited, the ever-present Google is there to lend a hand. This block of code is designed ...

How can I reorganize an object array into key value pairs using Javascript and then save it to mongoose and MongoDB for storage or outputting purposes?

Having just started with JS and utilizing node.js, express, and mongoose, I find myself working with an incoming array containing random key-value pairs that are unpredictable. // For example const simpleArray = { d: "h", e: "i", f: "j" ...

angular js: accessing nested json elements made easy

**How can I use Angular to display seeds or other data from "torrents" in HTML? ** Although this code appears to be working fine, it does not display any information when trying to show the seeds. HTML CODE <section class="list"> <article ...

"Revamping the text style of input materials in React JS: A step-by

How can I modify the style of the text field component in Material UI? Specifically, I would like to change the appearance of the text that the user enters. I have attempted to use the Material API, but it has not provided the desired results. Here is an ...

In what way does this function have the ability to output a singular object?

function list() { return Array.prototype.slice.call(arguments, 0); //I'm struggling to understand this line } var list1 = list(1, 2, 3); // [1, 2, 3] I stumbled upon this code snippet showcasing the slice method and I'm curious about how the ...

Having trouble with Npx and npm commands not running in the VSCode terminal?

I am currently facing an issue while attempting to set up a react app in vscode using the command npx create-react-app my-app. It seems like the command is not working properly. Can anyone provide guidance on what steps I should take next? Despite watchin ...

Calculate the total sum of input values containing data retrieved from the backend once the component data has been loaded and all backend data has been fetched in VueJS

My challenge involves a table that is filled with inputs located within table cells. All these inputs have the same class, regardless of how many are retrieved. My goal is to access the values of each input, add them together, and then place the sum in ano ...

Overlay a small image on top of a larger background image using canvas, then merge them into a single set of pixel

Is there a way to combine a smaller image with a larger background image on one canvas while allowing the smaller image to move around? I'll need to save the original background pixel data so that each frame can be redrawn with the overlay in its upda ...

Utilizing Local Storage in Vuex Store with Vue.js

I have been working with localStorage for storing and retrieving items in my JavaScript code housed within a .vue file. However, I am now looking to find a way to transfer this stored data into my Vuex store, specifically within the mutations section locat ...

Ensuring the integrity of data for POST requests

When using Angular to communicate with an Express backend, I encountered a problem where I can successfully retrieve data from my .get request, but my .post request is triggering a validation error. In the client-controller: $scope.addFriend = function( ...

Obtain the output of the msDropdown Jquery plugin

For my project, I am utilizing the json version of the msDropdown plugin which can be found at this LINK. I have a basic question regarding how to retrieve the value from the example page shown on that link. Although I am not very proficient in JavaScript ...

Preventing attribute or tag cloning in Jquery: What you need to know

I'm having some trouble with JQuery. I want to clone an attribute or tag that is dragged from one div1 to another div2, which is working fine. But the issue arises when I drag or move the position of an existing tag on div2, then the cloning process s ...

Solutions for concealing the current div when clicking on a new div that reveals a fresh one

Is there a way to hide the current div once you click on a new div that reveals another one? The code below toggles the display of the div, but what I am attempting to achieve is that when you click on a new item after clicking on the first one, the first ...