ngInit not working properly with AngularJS and Django

682 views Asked by At

I am passing the list of tuple from view to template as shown below in view.py:

def index(request):
    page_index =  int(request.GET["page"])
    s_page = (page_offset*page_index) + 1
    e_page = (page_index + 1)*page_offset
    user_statuses = get_user_status()
    user_statuses.sort(key=lambda user_statuses: datetime.datetime.strptime(user_statuses[0], '%Y-%m-%d'),reverse=True)
    print user_statuses
    user_statuses = user_statuses[s_page : e_page+1]
    print user_statuses
    return render(request, 'view_status.html', {'lists': user_statuses,'next_page':page_index+1,'prev_page':page_index-1})

The user_statuses is the list of tuples.

Below is my template:

   <body>
      <div ng-app="appTable">
         <div ng-controller="Allocation">
            <h2><span>VIEW STATUS</span></h2>
            <a ng-href="/welcome_page/">Return to Welcome Page</a><br><br>  
            Select start date:
            <input type="text"
               datepicker
               ng-model="start_date" />
            <br>
            <br>
            Select end date:
            <input type="text"
               datepicker
               ng-model="end_date" />
            <br>
            <br>
            <button ng-click="Submit()"> Submit </button> 
            {%verbatim%}    {{error}}{%endverbatim%}
            {%verbatim%}    {{msg}}{%endverbatim%}
            <br>
            <table>
               <th bgcolor="#35a5f0">   
               <td bgcolor="#35a5f0">Date</td>
               <td bgcolor="#35a5f0">Project</td>
               <td bgcolor="#35a5f0">Release</td>
               <td bgcolor="#35a5f0">Feature</td>
               <td bgcolor="#35a5f0">Module name</td>
               <td bgcolor="#35a5f0">Hours spent</td>
               <td bgcolor="#35a5f0">Comment</td>
               </th>
               </thead>
               <tbody>
                  {%for list in lists%}
                  <tr>
                     {{list.0}} {{list.1}}
                     <td><input type="checkbox" ng-model="data.isDelete"/></td>
                     <td>
                        <div ui-view  ng-init="data.date='{{list.0}}'" >
                           <input type="text"
                              datepicker
                              ng-model="data.date" />
                        </div>
                     </td>
                     <td>
                        <div ng-init="data.dept='{{list.1}}' " >
                           <input type="text" ng-model="data.dept" />
                        </div>
                     </td>
                     <td>
                        <select ng-model="data.release" ng-options="x for x in range">
                        </select>
                     </td>
                     <td>
                        <select ng-model="data.feature" ng-options="x for x in feature">
                        </select>
                     </td>
                     <td>
                        <input type = "text" ng-model = "data.modulename">
                     </td>
                     <td>
                        <select ng-model="data.hours" ng-options="x for x in hours">
                        </select>
                     </td>
                     <td>
                        <input type = "text" ng-model = "data.comment">
                     </td>
                  </tr>
                  {% endfor %}
               </tbody>
            </table>
            <a ng-href="/view_status/?page={{prev_page}}">Previous</a>  
            <a ng-href="/view_status/?page={{next_page}}">Next</a>  
         </div>
      </div>
   </body>

Here is my AJ script:

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

    app.controller("Allocation", function($scope, $http) {
        $scope.start_date = "2017-05-01";
        $scope.end_date = "2017-05-19";

        $scope.data = {}
        $scope.hours = ["1", "2", "3"];
        $scope.range = ["1", "2", "3"];
        $scope.feature = ["UT", "FSDS", "Coding", "QA"];

        $scope.postData = function(s_date, e_date) {
            console.log('post called');
            var data = {
                s_date: s_date,
                e_date: e_date,


            };
            console.log(data);
            $http.post('/view_status/', data).then(function(response) {
                if (response.data)
                    $scope.msg = "Data Submitted Successfully!";
            }, function(response) {
                $scope.msg = "Service not Exists";
                $scope.statusval = response.status;
                $scope.statustext = response.statusText;
                $scope.headers = response.headers();
            });
        };


    });

    app.directive("datepicker", function() {

        function link(scope, element, attrs, controller) {
            // CALL THE "datepicker()" METHOD USING THE "element" OBJECT.
            element.datepicker({
                onSelect: function(dt) {
                    scope.$apply(function() {
                        // UPDATE THE VIEW VALUE WITH THE SELECTED DATE.
                        controller.$setViewValue(dt);

                    });
                },
                dateFormat: "yy-mm-dd" // SET THE FORMAT.
            });
        }

        return {
            require: 'ngModel',
            link: link
        };
    });
</script>

The value of the the dictionary user_statuses from view.py is as below:

[(u'2017-05-02', u'p2', u'1', u'UT', u'pqr', u'1', u'Add extra information'), (u'2017-05-01', u'p1', u'1', u'UT', u'abc', u'1', u'Add extra information')]

My output: enter image description here

As you can see when I print {{list.0}} and {{list.1}} it shows me the correct output. But when I use same values to display in table using ng-init then it shows me the same values in both the rows which is the problem. Please help.

2

There are 2 answers

4
e4c5 On

I think, you shouldn't be using ng-init here

This directive can be abused to add unnecessary amounts of logic into your templates

What's happening here is that you have a local variable defined in your javascript called data that is being used by angular to update form field. However the trouble is that in your HTML each row over writes the data variable. So they all end up having the same variable.

Further, it's not always a good idea to combine the Django loop and the Angular loop particularly if you use ng-init.

I think your right approach is to deliver the user_statuses as an ajax response and loop through it with ng-repeat.

1
space earth On

I am able to achieve my goal using the {%for%} in the controller.This loop will take the data from the list one by one and append in to the list "dataList" in controller.This list will be printed in the rows of table by HTML using "ng-repeat".Below is my code:

<html>
       <head>
          <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.0/themes/base/jquery-ui.css">
          <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
          <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>
          <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
       </head>
       <style>
          h2 {
          width: 100%; 
          text-align: center; 
          color:#35a5f0;
          line-height: 1em;
          margin: 10px 0 20px; 
          background-color:#35a5f0;
          } 
          h2 span { 
          background:#fff; 
          padding:0 10px; 
          }
          table, th , td {
          border: 1px solid grey;
          border-collapse: collapse;
          padding: 5px;
          }
          table tr:nth-child(odd) {
          background-color: #f2f2f2;
          }
          table tr:nth-child(even) {
          background-color: #ffffff;
          }
       </style>
       <body>
          <div ng-app="appTable">
             <div ng-controller="Allocation">
                <h2><span>VIEW STATUS</span></h2>
                <a ng-href="/welcome_page/">Return to Welcome Page</a><br><br>  
                Select start date:
                <input type="text"
                   datepicker
                   ng-model="start_date" />
                <br>
                <br>
                Select end date:
                <input type="text"
                   datepicker
                   ng-model="end_date" />
                <br>
                <br>
                <button ng-click="Submit()"> Submit </button> 
                {%verbatim%}    {{error}}{%endverbatim%}
                {%verbatim%}    {{msg}}{%endverbatim%}
                <br>
                <span ng-init="add()"></span>
                <table>
                   <th bgcolor="#35a5f0">   
                   <td bgcolor="#35a5f0">Date</td>
                   <td bgcolor="#35a5f0">Project</td>
                   <td bgcolor="#35a5f0">Release</td>
                   <td bgcolor="#35a5f0">Feature</td>
                   <td bgcolor="#35a5f0">Module name</td>
                   <td bgcolor="#35a5f0">Hours spent</td>
                   <td bgcolor="#35a5f0">Comment</td>
                   </th>
                   <tr ng-repeat="data in dataList">
                      <td><input type="checkbox" ng-model="data.isDelete"/></td>
                      <td>
                         <input type="text"
                            datepicker
                            ng-model="data.date" />                 
                      </td>
                      <td><input type="text" ng-model="data.dept"/></td>
                      <td>
                         <select ng-model="data.release" ng-options="x for x in range">
                         </select>
                      </td>
                      <td>
                         <select ng-model="data.feature" ng-options="x for x in feature">
                         </select>
                      </td>
                      <td>
                         <input type = "text" ng-model = "data.modulename">
                      </td>
                      <td>
                         <select ng-model="data.hours" ng-options="x for x in hours">
                         </select>
                      </td>
                      <td>
                         <input type = "text" ng-model = "data.comment">
                      </td>
                   </tr>
                </table>
                <a ng-href="/view_status/?page={{prev_page}}">Previous</a>  
                <a ng-href="/view_status/?page={{next_page}}">Next</a>
             </div>
          </div>
       </body>
       <script>
 var app = angular.module("appTable", []);

          app.controller("Allocation", function($scope, $http) {
              $scope.start_date = "2017-05-01";
              $scope.end_date = "2017-05-15";

              $scope.data = {}
              $scope.hours = ["1", "2", "3"];
              $scope.range = ["1", "2", "3"];
              $scope.feature = ["UT", "FSDS", "Coding", "QA"];
              $scope.dataList = [];
              $scope.displayList = [];

              $scope.update_data = function(dept) {
                  data.dept = dept;

              };

              $scope.postData = function(s_date, e_date) {
                  console.log('post called');
                  var data = {
                      s_date: s_date,
                      e_date: e_date,


                  };
                  console.log(data);
                  $http.post('/view_status/', data).then(function(response) {
                      if (response.data)
                          $scope.msg = "Data Submitted Successfully!";
                  }, function(response) {
                      $scope.msg = "Service not Exists";
                      $scope.statusval = response.status;
                      $scope.statustext = response.statusText;
                      $scope.headers = response.headers();
                  });
              };
              $scope.add = function() {
                  { %
                      for list in lists %
                  }
                  var data1 = {};

                  data1 = {
                      date: '{{list.0}}',
                      dept: '{{list.1}}',
                      release: '{{list.2}}',
                      feature: '{{list.3}}',
                      modulename: '{{list.4}}',
                      hours: '{{list.5}}',
                      comment: '{{list.6}}'
                  };
                  $scope.dataList.push(data1);

                  { % endfor %
                  }

              };



          });

          app.directive("datepicker", function() {

              function link(scope, element, attrs, controller) {
                  // CALL THE "datepicker()" METHOD USING THE "element" OBJECT.
                  element.datepicker({
                      onSelect: function(dt) {
                          scope.$apply(function() {
                              // UPDATE THE VIEW VALUE WITH THE SELECTED DATE.
                              controller.$setViewValue(dt);

                          });
                      },
                      dateFormat: "yy-mm-dd" // SET THE FORMAT.
                  });
              }

              return {
                  require: 'ngModel',
                  link: link
              };
          });
       </script>
    </html>