javascriptangularjsangularjs-scopeangularjs-ng-model

How to fetch data from dynamically created input textboxes on click of save button in Angularjs


I'm dynamically creating textboxes and save button for each Item and on click of save button I need to fetch value from the text box of that particular item.

 for (let d = 0; d <= ItemsInfo.length - 1; d++)
    {                 
           content += '<tr>  <td> <label for="lblPriority">Item Priority </label>  </td>  ';
           content += ' <td>   <input type="text" id="inpItemPRIORITY" ng-model="prty" value=" ' +  ItemsInfo[d].PRIORITY  + ' " /> </td> </tr>';
           content += '<tr>  <td>  <label for="lblItemComment">Item Comment</label></td> ';
           content += ' <td>   <input type="text" id="inpItemCOMMENT"  ng-model="cmnt"  value=" ' + ItemsInfo[d].COMMENT + ' " /> </td> </tr>';
            // Save Item
          content += '<tr>  <td>  <button class="get-data" ng-click="buttonClick(prty,cmnt)">Save Item(' + ItemsInfo[d].ITEM_ID + ')</button> </td> </tr> ';
  }

In controller:

 $scope.buttonClick = function (prty,cmnt) {
  console.log(prty + " " + cmnt); } // console.log displays as undefined undefined

or is there a better way to do this?


Solution

  • As a start, the proper AngularJs would be to use ngRepeat directly in your HTML template, but i'm still giving you a solution with your current code:

    First, an HTML id should be unique, you are looping manually on your array in the controller, so you can add an index number to the id, and give it to your function to find the elements (also fixed the for loop condition for optimisation):

    In this case, it's useless to bind to a model, or else all inputs will use the same scope variable. This code also shows the proper way to retrieve a DOM element in jQlite format in AngularJS:

    for (let d = 0; d < ItemsInfo.length; d++)
    {                 
        content += '<tr>  <td> <label for="lblPriority">Item Priority </label>  </td>  ';
        content += ' <td>   <input type="text" id="inpItemPRIORITY_' + d + '" value="' +  ItemsInfo[d].PRIORITY  + '" /> </td> </tr>';
        content += '<tr>  <td>  <label for="lblItemComment">Item Comment</label></td> ';
        content += ' <td>   <input type="text" id="inpItemCOMMENT_' + d + '"  value="' + ItemsInfo[d].COMMENT + '" /> </td> </tr>';
        // Save Item
        content += '<tr>  <td>  <button class="get-data" ng-click="buttonClick(' + d + ')">Save Item(' + ItemsInfo[d].ITEM_ID + ')</button> </td> </tr> ';
    }
    
    $scope.buttonClick = function (index) {
        let prty = angular.element( document.querySelector( '#inpItemPRIORITY_' + index ) ),
            cmnt = angular.element( document.querySelector( '#inpItemCOMMENT_' + index ) );
        console.log(prty.val() + " " + cmnt.val());
    };
    

    Here a snippet that demonstrate. just an example to show that it works (EDIT: added $compile directive for buttonClick to work properly).

    angular.module('selectExample', [])
      .controller('ExampleController', ['$scope',  function($scope) {
        
        const ItemsInfo = [
            { ITEM_ID: 'a1', COMMENT: 'comment a1', PRIORITY: 0 },
            { ITEM_ID: 'b1', COMMENT: 'comment b1', PRIORITY: 1 },
            { ITEM_ID: 'c1', COMMENT: 'comment c1', PRIORITY: 2 },
        ];
        
        let content = '';
        for (let d = 0; d < ItemsInfo.length; d++)
        {                 
            content += '<tr>  <td> <label for="lblPriority">Item Priority </label>  </td>  ';
            content += ' <td>   <input type="text" id="inpItemPRIORITY_' + d + '" value=" ' +  ItemsInfo[d].PRIORITY  + ' " /> </td> </tr>';
            content += '<tr>  <td>  <label for="lblItemComment">Item Comment</label></td> ';
            content += ' <td>   <input type="text" id="inpItemCOMMENT_' + d + '"  value=" ' + ItemsInfo[d].COMMENT + ' " /> </td> </tr>';
            // Save Item
            content += '<tr>  <td>  <button class="get-data" ng-click="buttonClick(' + d + ')">Save Item(' + ItemsInfo[d].ITEM_ID + ')</button> </td> </tr> ';
        }
        $scope.htmlContent = content;
        
        $scope.buttonClick = function (index) {
            let prty = angular.element( document.querySelector( '#inpItemPRIORITY_' + index ) ),
                cmnt = angular.element( document.querySelector( '#inpItemCOMMENT_' + index ) );
            console.log(prty.val() + " " + cmnt.val());
        };
    
      }])
      .directive('bindHtmlCompile', ['$compile', function ($compile) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                scope.$watch(function () {
                    return scope.$eval(attrs.bindHtmlCompile);
                }, function (value) {
                    element.html(value);
                    $compile(element.contents())(scope);
                });
            }
        };
      }]);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular-sanitize.min.js"></script>
    <div ng-app="selectExample" ng-controller="ExampleController">
      <table bind-html-compile="htmlContent"></table>
    </div>