Angular - ng-repeat在更新嵌套数组时不更新

时间:2017-04-06 03:22:45

标签: javascript angularjs arrays

我使用ng-repeat通过GET请求渲染数据,该请求检索数组。

HTML

<div ng-controller="candidateCtrl" >
    <div class="table-responsive">
      <table class="table table-striped">
        <thead>
            <tr>
                <th>NO</th>
                <th>NAMA</th>
                <th>NIP</th>
                <th>INSTANSI</th>
                <th><span ng-show="animateCandidateAdmin" class="ion-load-a"></span></th>
            </tr>
        </thead>
        <tbody ng-repeat="candidate in candidatesAdmin">
            <tr class="well whel">
                <td>{{$index + 1}}</td>
                <td>{{candidate.candidate_name}}</td>
                <td>{{candidate.candidate_nip}}</td>
                <td>{{candidate.candidate_institusi}}</td>
                <td>
                    <button class="btn btn-xs btn-success" ng-show="candidate.m_assesment_assesment_id == NULL" ng-click="addCandidate3(candidate.candidate_id)">
                </td>
            </tr>

        </tbody>
    </table>
  </div><!-- OFF-MAINBAR -->
  <div ng-repeat="item in percentage_penilaian" >
       <div id="candidate_{{item.m_assesment_assesment_id}}" >
           <div class="panel-body">
               <div class="table-responsive">
                   <table class="table table-striped">
                      <thead>
                          <tr>
                              <th>NO</th>
                              <th>NAMA</th>
                              <th>NIP</th>
                              <th>INSTANSI</th>
                              <th>BOBOT</th>
                              <th>SKOR</th>
                              <th>NILAI</th>
                              <th><span ng-show="animateCandidateManagerial" class="ion-load-a"></span>
                              </th>
                           </tr>
                       </thead>
                       <tbody>
                           <tr ng-repeat="candidate in candidates[item.m_assesment_assesment_id]" class="well whel">
                               <td>{{$index + 1}}</td>
                               <td>{{candidate.candidate_name}}</td>
                               <td>{{candidate.candidate_nip}}</td>
                               <td>{{candidate.candidate_institusi}}</td>
                               <td>{{candidate.percentage}}%</td>
                               <td ng-show="candidate.skor != NULL">                                                                             
                                    <button  ng-click="$eval(arrAddCandidate[percentage_penilaian[$parent.$index+1].m_assesment_assesment_id])(candidate.candidate_id)"><i class="ion-arrow-right-a"></i> Mengikuti {{percentage_penilaian[$parent.$index+1].assesment_name}}</button>
                               </td>
                             </tr>
                           </tbody>
                       </table>
                   </div><!-- OFF-MAINBAR -->
               </div>
           </div>
       </div>
   </div>

JS

    <script>
    var SITEURL = "<?php echo site_url() ?>";
    var selectionApp = angular.module("selectionApp", ["isteven-multi-select"]);

    selectionApp.controller('candidateCtrl', function ($scope, $http) {
        $scope.candidates = [];
        $scope.arrAddCandidate = [];

        $scope.getPercentagePenilaian = function () {
            var url = SITEURL + 'xxx/xxx/' + 14;
            $http.get(url).then(function (response) {
                $scope.percentage_penilaian = response.data;
                for(var i in response.data){ 
                     $scope.arrAddCandidate[response.data[i].m_assesment_assesment_id] = "addCandidate"+response.data[i].m_assesment_assesment_id;                                                                                                                                                                              

                }
            })

        };

        $scope.getCandidateAdmin = function () {
           var url = SITEURL + 'api/get_candidate_admin/' + 14;
           $http.get(url).then(function (response) {                                                                                  
             $scope.candidatesAdmin = response.data;
           })

        };                                                                          

        $scope.get_3 = function () {
            var url = SITEURL + 'xxx/xxx/3__14';
            $http.get(url).then(function (response) {
                $scope.$apply(function () {
                    $scope.candidates[3] = response.data;
                    // $scope.candidates.push(response.data);
                });
            })

        };
        $scope.addCandidate3 = function (id) {
            $scope.animateCandidateAdmin = true;
            var postData = $.param({
                                candidate_id: id,
                                assesment_id: 3                                                                                                });
            $.ajax({
                method: "POST",
                url: SITEURL + "xx/xxx/xxxxx",
                data: postData,
                success: function (response) {
                    if(response=='sukses'){
                        $scope.animateCandidateAdmin = false;
                        $scope.getCandidateAdmin();
                        $scope.get_3();
                    }
                }
            });

        };

        $scope.get_5 = function () {
            var url = SITEURL + 'xx/xxx/5__14';
            $http.get(url).then(function (response) {
                $scope.$applyAsync(function () {
                    $scope.candidates[5] = response.data;
                    // $scope.candidates.push(response.data);
                });
            })

        };
        $scope.addCandidate5 = function (id) {
            $scope.animateCandidateAdmin = true;
            var postData = $.param({
                                candidate_id: id,
                                assesment_id: 5                                                                                                });
            $.ajax({
                method: "POST",
                url: SITEURL + "xx/xxx/xxxxx",
                data: postData,
                success: function (response) {
                    if(response=='sukses'){
                        $scope.animateCandidateAdmin = false;
                        $scope.getCandidateAdmin();
                        $scope.get_5();
                    }
                }
            });

        };
        angular.element(document).ready(function () {
            $scope.getPercentagePenilaian();
            $scope.get_3;
            $scope.get_5;
        });
    });                
</script>

来自$ scope.getCandidateAdmin

的回复
[{"candidate_id":"24","candidate_name":"contoh","candidate_nip":"12345","candidate_institusi":"Institusi A","selection_selection_id":"14"}]

回应$ scope.getPercentagePenilaian

[{"id":"14","m_assesment_assesment_id":"3","percentage":"50"},
{"id":"15","m_assesment_assesment_id":"5","percentage":"10"}]

$ scope.get_3

的回复
[{"id":"43","selection_selection_id":"14","m_assesment_assesment_id":"3"
,"candidate_id":"24","m_candidate_id" :"1","candidate_name":"contoh","candidate_nip":"12345","candidate_institusi":"Institusi A","competency_skor":null}]

添加候选项后,我相信$ scope.candidates数组已正确更新,但我视图中的表不会更改。我不知道我做错了什么。

1 个答案:

答案 0 :(得分:0)

潜在问题

我认为&#39; m_assesment_assesment_id&#39;存储为String而不是Integer,这是问题的根源。

[
  { "id":"14",
    "m_assesment_assesment_id":"3",  // Note: the numbers are wrapped in quotes
    "percentage":"50"
  },
  { "id":"15",
    "m_assesment_assesment_id":"5", // JSON parsers will interpret these as Strings, NOT numbers
    "percentage":"10"}
]

理解问题的背景

由于ng-repeat正在使用item.m_assesment_assesment_id属性,因此Angular将这些解析为字符串。将此String传递给Array时,Array将被解释为JavaScript对象而不是数组。例如:

// Both the following evaluate to the same thing
// Using dot accessor
item.m_assesment_assesment_id
// Using square brackets to access data through Object Notation
item["m_assesment_assesment_id"]

这就是JavaScript将您的数组解释为对象的原因,使用item.m_assesment_assesment_id作为而不是索引

<!-- item.m_assesment_assesment_id will evaluate as a String as the JSON data specifies the String format, triggering Object evaluation, not Array evaluation -->
<tr ng-repeat="candidate in candidates[item.m_assesment_assesment_id]" class="well whel">

以下是阵列评估的一些很好的概述: https://www.w3schools.com/js/js_arrays.asp

  

关联数组许多编程语言都支持数组   命名索引。

     

具有命名索引的数组称为关联数组(或哈希)。

     

JavaScript不支持具有命名索引的数组。

     

在JavaScript中,数组总是使用带编号的索引。

解决方案

有几种解决方案。如果您有权操作JSON格式,我建议在那里纠正问题:

{  
   "id":"14",
   "m_assesment_assesment_id": 3,  // No quote == Integer
   "percentage":"50"
}

但这需要您访问构建响应的服务器代码,并且可能存在使用字符串的架构原因。

或者,您可以更改ng-repeat:

<tr ng-repeat="candidate in candidates[parseInt(item.m_assesment_assesment_id)]" class="well whel">

然而,由于在Angular $digest()事件期间需要更多处理,因此会有性能损失。这对小型数据集来说并不重要,但值得注意。

如果您无权更改服务器上的JSON格式,并且您不想对$digest事件施加额外负担,则您的控件可以处理来自AJAX调用。这通常是Angular文档推荐的方法。

angular.module("selectionApp", ["isteven-multi-select"])
  .controller('candidateCtrl', function ($scope, $http) {
        $scope.candidates = [];
        $scope.arrAddCandidate = [];

        $scope.getPercentagePenilaian = function () {
            var url = SITEURL + 'xxx/xxx/' + 14;
            $http.get(url).then(function (response) {
                // USE OUR CONVENIENCE METHOD HERE TO CONVERT STRINGS TO INTEGERS
                $scope.percentage_penilaian = processPercentagePenilaian(response.data);
                for(var i in response.data){ 
                    $scope.arrAddCandidate[response.data[i].m_assesment_assesment_id] = "addCandidate"+response.data[i].m_assesment_assesment_id;                                                                                                                                                                              

            }
        })

    };

   // *** MORE of your code exists between these functions

   // ALSO YOU HAVE TO CALL THIS IN THE CALLBACK OF THE APPROPRIATE AJAX CALLBACK
   var processPercentagePenilaian = function(items) {
      // Loop through the Items
      angular.forEach(items, function(item, key) {
         // For Every Item, convert the m_assesment_assesment_id to an Integer
         item.m_assesment_assesment_id = parseInt(item.m_assesment_assesment_id);
      });

// End Controller
});