Search code examples
javascripthtmlangularjsdomangularjs-scope

How to bind scope data to model that is generated dynamically using Javascript?


The scenario I have is to create dynamic table using javascript by passing the data passed from script tag. My javascript code parses the provided json and generates the table header and table body. The table body is generated along with the tags required for angular binding method {{variable_name}}.

But after the DOM is created I need to re-apply the scope to ng-repeat of table.

<html>
<head>
<title>dynamic table</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">
    <script src="js/angular.min.js"></script>
    <script src="js/jquery.min.js"></script>

<script type="text/javascript">
var orderByField = "impressions";
var reverseSort = "false";
var myList = [{firstName: 'John',lastName: 'Doe',age: 30,etc : 'heelo'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Sue',lastName: 'Banter',age: 21,etc: 'cool'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'},{firstName: 'Frank',lastName: 'Burns',age: 54,etc: 'world'}];


function addAllColumnHeaders(myList, selector)
{   
    var columnSet = [];
    var headerTr$ = $('<tr/>');
    var aStart = '<a href="#" ng-click="orderByField=\'';
    var aMid = '\'; reverseSort = !reverseSort">';
    var aEnd = '</a>';

    for (var i = 0 ; i < myList.length ; i++) {
        var rowHash = myList[i];
        for (var key in rowHash) {
            keyLink = aStart+key+aMid+key+aEnd;
            if ($.inArray(key, columnSet) == -1){
                columnSet.push(key);
                headerTr$.append($('<th/>').html(keyLink));
            }
        }
    }
    $(selector).append(headerTr$);
    return columnSet;
}

function createAngularTableDataPlaceholder(myList, selector)
{
    var columnSet2 = [];
    var headerTr2$ = $('<tr/>').attr('ng-repeat','field in myList|orderBy:orderByField:reverseSort');
    var aStart2 = '<td>{{field.';

    var aEnd2 = '}}</td>';

    for (var i = 0 ; i < myList.length ; i++) {
        var rowHash2 = myList[i];
        for (var key2 in rowHash2) {
            keyLink2 = aStart2+key2+aEnd2;
            //alert(keyLink);
            if ($.inArray(key2, columnSet2) == -1){
                columnSet2.push(key2);
                headerTr2$.append($('<td/>').html(keyLink2));
            }
        }
    }
    $(selector).append(headerTr2$);
    return columnSet2;
}
</script>
</head>
<body>
<div class="container">
<section ng-app="app" ng-controller="MainCtrl" ng-init="getMember(myList)">
<table class="table" id="excelDataTable" border="1">
            <thead id="thead">

            </thead>
            <tbody id="tbody">
              <!--tr ng-repeat="field in myList|orderBy:orderByField:reverseSort">

              </tr-->
            </tbody>
  </table>
  </section>
  </div>

  <script>
    var app = angular.module('app', []);

        app.controller('MainCtrl', ['$scope', '$window', function($scope, $window) {        

                addAllColumnHeaders(myList, '#thead');
                createAngularTableDataPlaceholder(myList, '#tbody');
                console.log("header and columns done");

                $scope.orderByField = $window.orderByField;
                console.log($scope.orderByField);

                $scope.reverseSort = false;
                console.log($scope.reverseSort);

                angular.element(document).ready(function () {
                $scope.myList = $window.myList;
                console.log("got "+$scope.myList);
            });

        }]);    
    </script>

</body>
</html>

The dom elements created are as - enter image description here

The current output I am getting is as - enter image description here But the problem is that angular binds all its code at rendering time. How can I use the $scope.watch method or $scope.apply method to get this done after javascript is done. I was trying to do this using

angular.element(document).ready(function ())

but that's not the correct way I suppose.
I am new to angular. Please guide me. Thanks!


Solution

  • You can bootstrap angular after DOM tree is rendered. Just remove ng-app from section and put this code at the end of first script:

    var elem = document.querySelector('section');
    angular.bootstrap(elem, 'app');
    

    Of course, use better way to select your element on which you want to bind ng-app to