Using AngularJS to bind a nested method call in an ng-repeat for a one-time operation

Currently, I am delving into the world of AngularJS 1.3 after migrating my application from 1.2. The new one-time binding feature caught my attention, and I decided to experiment with it. However, I encountered a situation where it doesn't seem to work as expected. Can someone enlighten me on why this is happening? In my scenario, I am dynamically generating an id field by invoking a method within the view. This seems to interfere with the functionality of the one-time binding. You can see the issue in action at http://plnkr.co/edit/GyfKKb?p=preview.

The specific problem arises when I anticipate that the one-time binding should not update the ng-repeat when a new element is added to the array. Surprisingly, pushing a new element into the array (via a button click) results in the new element showing up in the output of the ng-repeat.

index.html

<body ng-controller="MainCtrl">
  <!-- TODO: I would expect addItemC() to do nothing with one time binding -->
  <button ng-click="addItemC()">add</button>

  <div ng-repeat="itemC in ::itemsC">

    <!-- dynamically generate id that is causing the issue -->
    {{::itemC.id() | limitTo:3}}

  </div>      
</body>

app.js

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {

  // dynamically generate a random string id (code snippet obtained from a Stack Overflow answer)
  var itemObj = {
    id: function makeid() {
      var text = "";
      var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

      for( var i=0; i < 100; i++ )
          text += possible.charAt(Math.floor(Math.random() * possible.length));

      return text;
    }
  };

  // one-time binding not functioning correctly
  $scope.itemsC = [
    angular.copy(itemObj),
    angular.copy(itemObj),
    angular.copy(itemObj)
  ];
  $scope.addItemC = function() {
    $scope.itemsC.push(angular.copy(itemObj));
  };
});

Answer №1

One possible reason for the error thrown by Angular is due to an excessive number of $digest cycles within the ng-repeat loop. This often occurs when a for loop runs through 100 iterations for each item.

To resolve this issue, consider generating the id within the controller before passing it to ng-repeat for rendering. You can refer to the following plunkr example:

Demo http://plnkr.co/edit/4nFtOy1uGtDyUEWXCVbT?p=preview

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';

  // generate random string id dynamically (code taken from stackoverlow answer)
  function makeid() {
      var text = "";
      var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

      for( var i=0; i < 100; i++ )
          text += possible.charAt(Math.floor(Math.random() * possible.length));

      return text;
    }

  function getItem () {
    return {
      id: makeid()
    };
  }


  var itemObj = {
    id: makeid()
  };


  // one time binding does not work
  $scope.itemsC = [
    getItem(),
    getItem(),
    getItem(),
  ];
  $scope.addItemC = function() {
    $scope.itemsC.push(getItem());
  }

  $scope.removeItem = function(item) {
    var index = $scope.itemsC.indexOf(item);
    $scope.itemsC.splice(index, 1);
  }
});

Remember to update the markup by changing itemC.id() to itemC.id as the id is now treated as a property.

Answer №2

It appears that the function is one-time bound and being called repeatedly. This results in the function returning the same value each time, as it continues to generate random strings.

The one-time binding behavior persists because the function itself remains unchanged. I have introduced a new property, which is not a function, to illustrate how one-time binding remains effective even with this addition.

<div style="font-weight:bold;">itemsC:</div>
<div ng-repeat="itemC in ::itemsC">
  <div ng-click="removeItem(itemC)">
    <!-- dynamically generate id -->
    {{::itemC.name | limitTo:3 }}
  </div>
</div>
<div style="margin-top:10px;">{{itemsC}}</div>

http://plnkr.co/edit/T8KRafey7VJFbcAs4NLZ?p=preview

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

Push-grid interaction through drag-and-drop feature

I'm on a quest to incorporate grid drag-and-drop functionality into my project. While there are numerous frameworks available that offer this feature, one of the most popular options is JQuery UI's sortable library. However, I am specifically lo ...

Chronological style switcher

I'm currently working on a JavaScript project to dynamically change the layout of my webpage at specific times of the day. I have also implemented functionality to revert back to the default style if any manual changes are made. However, I've en ...

Utilize jQuery to set a cookie upon submission of a form or when logging in

Seeking guidance on a new project I'm working on. I have developed a two-page website with a login form that redirects users to the second page upon entering the correct "access code" I created. Everything is functioning as expected. Now, I am interes ...

Analyzing objects within an array for similarities

Suppose I have an array containing objects: var arr = [ { id: 1, pt: 0 }, { id: 2, pt: 12 }, { id: 3, pt: 7 }, { id: 4, pt: 45 }, { id: 5, pt: 123 }, ]; I am looking to loop through this array (possibly using array.forEach or array.map) ...

Does the negation operator (!) exhibit unique behavior in TypeScript?

In the realm of JavaScript, certain values are known as "falsy". These include: false 0 '' "" null undefined NaN But how does TypeScript treat the not operator (!)? Is it similar to JavaScript or different? ...

Step-by-step guide on how to index timestamp type using Knex.js

I'm in the process of indexing the created_at and updated_at columns using knex js. However, when I try to use the index() function, I encounter the following error: Property 'index' does not exist on type 'void' await knex.sche ...

Implementing hover intent functionality in Angular 2+

Struggling to incorporate hover intent in Angular 2. Any advice or suggestions would be greatly appreciated. ...

jQuery: Eliminating Parent Elements

Currently, I am developing a small web application that allows users to create lists which are then formatted and emailed to them. However, I am facing difficulties in implementing a method that will allow users to delete list items without clearing the en ...

Sorting through JSON data obtained through YQL

Hello coding enthusiasts, After facing challenges with CORS in an AJAX project, I discovered a workaround using YQL to successfully retrieve JSON data. Now, I'm looking for ways to access and organize this data according to my preferences. Below is t ...

Disappearance of icon upon hovering in CSS

I am currently working with Angular JS (1.x) and I have a requirement to display tooltip text when hovering over an info icon. The tooltip text appears properly, but the issue is that the icon disappears when hovered over. It reappears once the hover is re ...

Save an automatically generated number into a variable and use it to reference an image file for display. This process can be accomplished using JavaScript

I'm having trouble getting my images to display randomly on a page. The images are named 0 - 9.png and I am using a pre-made function for random number generation. However, when I try to call on this function later down the page, nothing appears. It ...

Sorting in reverse order within a table

Is there a way to reverse the order in which my function renders table rows with incremental id? (first row with id=n, last with 1) Here is the code snippet I am using: renderRows = () => { const { receipts } = this.props const reversedReceipt ...

Ways to consistently press a particular button every single second

The code on the webpage looks like this: <div id="content"> <div class="container-fluid"> Slots <p>The current jackpot is 23220!<p/> <p>You lose.</p> <form method=post action=/game ...

What is the best way to establish and maintain lasting connections with the Firebase database while utilizing the superagent

Currently, I am following the Firebase Functions documentation on enhancing Firebase database performance. I have provided the code snippet below for your reference. const request = require('superagent'); const functions = require('fireba ...

Attempting to configure Kafka consumer and producer components

Trying to establish a basic producer-consumer flow with Kafka, utilizing node-rdkafka Operating in debug: 'all' mode, the logs display: Producer: test [0]: MessageSet with 1 message(s) delivered Consumer: Fetch topic test [0] at offset 38 (v2) ...

Inject JSON data into a JavaScript array

I am dealing with a JSON file in the following format: [{"excursionDay":"2"},{"excursionDay":"3"},{"excursionDay":"4"}] My goal is to extract the values of excursionDay and store them in an array in JavaScript like this: dayValues = [2,3,4] Here is m ...

Obtaining JSON Data Using WinJS.xhr():

I'm encountering difficulties with retrieving chat messages using winjs.xhr: function getMessage() { var time = MESSAGE_RETURNED.unixtime; if (time == 0) { time= window.parent.SESSION.unixtime; } WinJS.x ...

The Ajax request (b) fired off during the callback of an earlier Ajax request (a) finishes before (a) itself is fully

I encountered an issue with my code where an ajax call, referred to as callback (b), was expected to depend on the success of another ajax call, known as callback (a). Surprisingly, callback (b) completed successfully before its parent ajax call (a) finish ...

The parameter for the AngularJs filter was found to be undefined

I am currently utilizing the Ui-grid in combination with cell dropdown edit functionality. I am encountering an issue where the undefined entity variable needs to be fixed within the filter. The objective is to pass data to the filter in order to convert ...

Creating a Vue.js component that animates text to fade in and out within a textarea when a button

I need assistance with updating a <textarea> element in my Vue application. Currently, I have the textarea bound to some data in my state. However, when a button is clicked, I want the existing data in the textarea to fade out and be replaced with ne ...