When invoking a function using ng-init within ng-repeat, only the final item in the iteration yields a result

My goal is to update the content of a progress bar for each row in a table using ng-init within ng-repeat. Here is my code snippet:

The code snippet for the view section is as follows:

<tr ng-repeat-start="p in projetsListe" ng-init={{progressBar($index)}}>
  <td>
  <button class="btn btn-info btn-sm" ng-click="p.expanded = !p.expanded" expand data-toggle="collapse" id="{{p.IdProjet}}" data-target=".{{p.IdProjet}}">
  <span ng-bind="p.expanded ? '-' : '+'"></span>
  </button>
  </td>
  <td>{{p.NomProjet}}</td>
  <td>{{p.Responsable}}</td>
  <td>{{trestant[$index]}}</td>
  <td><div class="progress">
       <div class="progress-bar progress-bar-danger progress-bar-striped active" role="progressbar" aria-valuenow="40" id="pg1" aria-valuemin="0" aria-valuemax="100"><label id="l1"></label>
       </div>
       <div class="progress-bar progress-bar-success progress-bar-striped active" role="progressbar" aria-valuenow="40" id="pg2" aria-valuemin="0" aria-valuemax="100"></div>
       </div>
       <label style="font-size :10px"><i class="fa fa-circle" style ="color : #df6d69"></i> Temps Passé : {{tpasse[$index]}}h</label>
                               &nbsp &nbsp
       <label style="font-size :10px"><i class="fa fa-circle" style ="color : green"></i> Temps Prévu : {{tprev[$index]}}h</label>
   </td>
</tr>

Below is the function code snippet:

 $scope.progressBar= function(i){   
  var tpa;
        var p1 = document.getElementById('pg1');
        var p2 = document.getElementById('pg2');
        var l1 = document.getElementById('l1');
        tpa = ($scope.tpasse[i]*100)/$scope.tprev[i];
           if(tpa<=100){
             p1.style.width =  tpa + '%';
             p2.style.width =  100-tpa + '%';
             l1.innerHTML = " ";
           }
           else{
             p1.style.width = '100' +'%';   
             l1.innerHTML = "Attention : Temps prévu dépassé !";
           }  
 };

Currently, the data of the last row in the table is displaying in the first row instead of the intended row:

https://i.sstatic.net/lDMQv.png

The result should actually show up in the second row, which is currently empty, while the first row should display a different outcome. Any ideas on how to resolve this issue?

For a visual representation of this issue, you can check out this plunker link: https://plnkr.co/edit/nGxqMOPejKMINb89Ewwx?p=preview

Answer №1

One major issue with your code is that you have assigned the same id to different elements, which is not allowed and causing the progress bars to not display correctly. The following code provides a solution to this problem. However, I would recommend reviewing your code thoroughly as there are other issues present, such as using interpolation with ng-init={{}progressBar($index)}, which will throw an error since progressBar returns nothing. Make sure to carefully assess your code for any additional mistakes.

// Code goes here
var myApp = angular.module('myApp', []);

myApp.controller('Ctrl', function ($scope) {

$scope.tpasse = ['5049','26','100'];
$scope.tprev = ['688','336','400'];

$scope.projetsListe = [
    {
      "NomProjet" : "Project1",
      "ResponsableApitech" : "Jean"

    },

    {
     "NomProjet" : "Project2", 
     "ResponsableApitech" : "Edward"

    },

    {
     "NomProjet" : "Project2", 
     "ResponsableApitech" : "Edward"

    }
];
console.log($scope.projetsListe);

 $scope.progressBar= function(i){   
        var tpa;
        var p1 = document.getElementById('pg'+i);
        var p2 = document.getElementById('pgb'+i);
        var l1 = document.getElementById('l'+i);

        tpa = ($scope.tpasse[i]*100)/$scope.tprev[i];
           if(tpa<=100){
             p1.style.width =  tpa + '%';
             p2.style.width =  100-tpa + '%';
             l1.innerHTML = " ";
           }
           else{
             p1.style.width = '100' +'%';   
             l1.innerHTML = "Attention : You have reached the limits!";
           }  
 };
});

<html ng-app="myApp">

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
  <link data-require="bootstrap-css" data-semver="4.0.0-alpha.4" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" />
  <link data-require="bootstrap@*" data-semver="4.0.5" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" />
  <script data-require="jquery" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script data-require="bootstrap" data-semver="4.0.5" src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/js/bootstrap.min.js"></script>
  <link href="style.css" rel="stylesheet" />
  <script src="script.js"></script>
</head>

<body>
  <div ng-controller="Ctrl">

    <table class="table table-bordered table-hover table-striped">
      <thead>
        <tr>
          <th>Nom</th>
          <th>Responsable</th>
          <th>Progress</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="p in projetsListe track by $index">
          <td>{{p.NomProjet}}</td>
          <td>{{p.ResponsableApitech}}</td>
          <td>
            <div class="progress" ng-init="{{progressBar($index)}}">
              <div class="progress-bar progress-bar-danger " role="progressbar" aria-valuenow="40" id="pg{{$index}}" aria-valuemin="0" aria-valuemax="100">
                <label id="l{{$index}}"></label>
              </div>
              <div class="progress-bar progress-bar-success progress-bar-striped " role="progressbar" aria-valuenow="40" id="pgb{{$index}}" aria-valuemin="0" aria-valuemax="100"></div>
            </div>
            <label style="font-size :10px"><i class="fa fa-circle" style="color : #df6d69"></i> Temps Passé : {{tpasse[$index]}}h</label> &nbsp; &nbsp;
            <label style="font-size :10px"><i class="fa fa-circle" style="color : green"></i> Temps Prévu : {{tprev[$index]}}h</label>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</body>

</html>

Check out the updated Plunker here.

Hopefully, this information proves helpful.

Answer №2

Even though you've already accepted the answer, I still recommend using the components approach (especially since you are using angularjs 1.5+) to tackle your issue. There are some aspects in your code that could be improved: ngInit introduces unnecessary complexity into your templates, which can be avoided by leveraging the well-defined lifecycle of components and the $onChanges hook for updating your progress bar. Additionally, handling DOM manipulation inside the controller is not the typical Angular way to work with views; it's preferable to utilize the ngStyle directive in this scenario. Here is a functional example:

angular.module('myApp', []).controller('Ctrl', function ($scope) {
 $scope.projectsList = [
    {
      ProjectName : "Project1",
      TechnicalLead : "Jean",
      timeSpent: 5049,
      timeEstimated: 688
    }, {
      ProjectName : "Project2", 
      TechnicalLead : "Edward",
      timeSpent: 26,
      timeEstimated: 336
    }, {
      ProjectName : "Project4", 
      TechnicalLead : "Edward",
      timeSpent: 177,
      timeEstimated: 336
    }
  ];
})
.component('progressBar', {
  templateUrl: "progress-bar.html",
  bindings: {
    project: '<'
  },
  controller: 'ProgressBarCtrl'
})
.controller('ProgressBarCtrl', [function ProgressBarCtrl (){
  var ctrl = this;
  
  ctrl.$onChanges = onChanges;

  ctrl.styles = {};
  
  function onChanges(changesObject){
    ctrl.styles = getStyles(ctrl.project);
  }
  
  function getStyles(project){
      var tpa, styles = {};
      tpa = (project.timeSpent*100) / project.timeEstimated;
 
      if (tpa <= 100){
        styles = {
          p1Width: tpa + '%',
          p2Width: 100-tpa + '%',
          label1InnerHTML: " "
        };
      } else{
        styles = {
          p1Width: '100%',
          label1InnerHTML: "Attention : You have reached the limits!"
        };
      } 
      
     return styles;
  }
  
  return ctrl;
  
}]);
<html ng-app="myApp">
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
  <link data-require="bootstrap-css" data-semver="4.0.0-alpha.4" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" />
  <link data-require="bootstrap@*" data-semver="4.0.5" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" />
  <script data-require="jquery" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="https://npmcdn.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aedacbdac6cbdcee9f809c809a">[email protected]</a>/dist/js/tether.min.js"></script>
  <script data-require="bootstrap" data-semver="4.0.5" src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/js/bootstrap.min.js"></script>
</head>

<body>
  <div ng-controller="Ctrl">
  
  <table class="table table-bordered table-hover table-striped">
     <thead>
      <tr>
        <th>Name</th>
        <th>Lead</th>
        <th>Progress</th>
      </tr>
    </thead>
    <tbody>
     <tr ng-repeat="p in projectsList">
       <td>{{p.ProjectName}}</td>
       <td>{{p.TechnicalLead}}</td>
       <td>
         <progress-bar project="p"></progress-bar>
       </td>
      </tr>
    </tbody>
  </table>

<script type="text/ng-template" id="progress-bar.html">
<div class="progress">
    <div class="progress-bar progress-bar-danger" ng-style="{'width': $ctrl.styles.p1Width}" role="progressbar"
         aria-valuenow="40" aria-valuemin="0"
         aria-valuemax="100">
        <label>{{$ctrl.styles.label1InnerHTML}}</label>
    </div>
    <div class="progress-bar progress-bar-success progress-bar-striped" ng-style="{'width': $ctrl.styles.p2Width}"
         role="progressbar" aria-valuenow="40"
         aria-valuemin="0" aria-valuemax="100"></div>
</div>

<label style="font-size:10px"><i class="fa fa-circle" style="color:#df6d69"></i> Time spent:
    {{$ctrl.project.timeSpent}} hours</label>
   
<label style="font-size:10px"><i class="fa fa-circle" style="color:green"></i> Initial expected time:
    {{$ctrl.project.timeEstimated}} hours</label>
</script>

</div>
</body>
</html>

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

How to achieve the wrapping functionality in ReactJS that is similar to

Is there a ReactJS equivalent to jQuery's wrap method? I want to wrap menuContents with the following element: <ul className="nav nav-pills nav-stacked"></ul> The contents of menuContents are generated like this: let menuContents = thi ...

Codeceptjs does not have the capability to scroll or swipe down without being linked to a specific element

I'm facing an issue with scrolling/swiping down in an Android application while using codeceptjs. The method I'm currently using only works on the visible element, but I need to scroll down to the bottom of the page or a specific element without ...

Can we switch between using Vue components in .vue formats and commonJS formats seamlessly?

Here is the commonJS format: Vue.Component('custom-component',{ template : '<p>Some template</p>', data : {} methods : {} }); And here is the .vue format: <template> <p>Some template&l ...

The process of transferring a PHP variable to JavaScript

I'm making a new attempt at a more specific solution here. I'm trying to retrieve the value from my <span id=”$var”>BadText</span> using a variable. Passing the idFull to the function works well when I first assign the value to a ...

What is the best way to delete a jQuery.bind event handler that has been created for an event

I have a div and I need to assign two scroll functions to it, but I also want to remove one of them after a certain condition is met. <div id="div1" class="mydivs"> something </div> <div id="div2">Some crap here</div> <script&g ...

The Javascript eval method throws a ReferenceError when the variable is not defined

In my constructor, I was trying to create a dynamic variable from a string. Everything was working smoothly until I suddenly encountered this error out of nowhere. I didn't make any changes that could potentially disrupt the system, and the variables ...

In Javascript, merge two arrays together in a specific format

Can we transform two arrays into a specific format so I can create my D3 graph? Here are the two arrays I have: date = ["sept,09 2015","sept, 10 2015","sept, 11 2015"] likes = [2,4,5] I need to convert them to this format: [{ date: '...', lik ...

Scroll through content using buttons in JavaScript can be utilized repeatedly as needed

I want to showcase a collection of movies on my website through a horizontal, scrollable div. Since I disabled the scrollbar, users can no longer scroll, leading me to incorporate two buttons - one for moving right and one for moving left. However, the i ...

Issue with jQuery sortable serialization when dynamically adding content is not being recognized

I've been attempting to re-order a list through ajax on sortable update. However, when I add a new item to the list via ajax after the sortable has already been initialized upon page load, it fails to recognize the new item with the "serialize" functi ...

What is the process for adding information to datatables using jQuery?

I have been struggling to make a data table in jQuery function correctly. I am able to append data to the table, but the sorting, pagination, and search features are not working. Even though the data is visible in the table, it shows as 0 records. I am wor ...

Expressjs returns an empty object when using Angular's $location

Recently, I have been diving into Angular and exploring its functionalities. One requirement in my project is to export data to an Excel file. Here is the process flow I have come up with: Get query string -> send to express -> output file In the s ...

What is the best way to find out if an array index is within a certain distance of another index?

I'm currently developing a circular carousel feature. With an array of n items, where n is greater than 6 in my current scenario, I need to identify all items within the array that are either less than or equal to 3 positions away from a specific inde ...

What is the process of replacing fetch with JavaScript?

Looking to test my React application and mock the backend calls, I made the decision to swap out fetch with a Jest function that returns a static value. The issue I encountered was my inability to override the default fetch behavior. After some research, ...

Building and utilizing xterm.js on your local machine - A step-by-step guide

I have been attempting to modify the source code of xterm.js and test my changes before submitting a PR. Unfortunately, I have not been able to generate a functional 'distribution.' (I apologize if my terminology is incorrect -- I am still fairl ...

Transclusion with multiple slots in AngularJS

Attempting to incorporate a component in AngularJS 1.5.8 with multi-slot transclusion. The test performs well when utilizing a directive, however, with a component, it appears that the slot cannot be located!. This is how the component is declared app. ...

In my JavaScript code for generating a Fibonacci series, I aim to include a comma at the end of each string

I am currently working on a JavaScript program to generate a Fibonacci series, and there are certain conditions that need to be met: Each number in the series should be separated by a comma. The method should handle invalid values and return -1 for integ ...

Steps to fix issues with Cross-Origin Read Blocking (CORB) preventing cross-origin responses and Cross Origin errors

var bodyFormData = new FormData(); bodyFormData.set("data", "C://Users//harshit.tDownloads\\weather.csv"); bodyFormData.set("type", "text-intent"); //axios.post("https://api.einstein.ai/v2/language/datasets/upload", axio ...

Unable to retrieve /ID from querystring using Express and nodeJS

I am brand new to the world of Express and nodeJS. I have been experimenting with query strings and dynamic web pages, but I keep getting an error saying that it cannot retrieve the ID. I'm completely lost as to where I might have made a mistake. An ...

What is the solution to adding values from a counter?

I am trying to create a JavaScript counter: function animateSun() { var $elie = $("#sun"); $({ degree: 0 }).animate({ degree: 360 }, { duration: 190999, easing: 'linear', step: function(val) { now = Math.round ...

Why am I getting the "Cannot locate control by name" error in my Angular 9 application?

Currently, I am developing a "Tasks" application using Angular 9 and PHP. I encountered a Error: Cannot find control with name: <control name> issue while attempting to pre-fill the update form with existing data. Here is how the form is structured: ...