AngularJS ng-click触发后表格无法加载JSON数据问题
AngularJS 点击表格行加载二级数据失败排查指引
问题表现
- 标记为*(1)*的首表格数据加载正常,点击行时传入
go函数的Account参数取值正确,二级表格容器可正常显示 - 二级表格内部始终无法渲染对应Account的费用数据
核心错误原因
- 动态注册Angular组件无效:将
dataService服务、customersCtrl2控制器的定义写在了go点击回调内部。AngularJS在页面初始引导完成后,后续动态调用app.service()/app.controller()注册的组件不会被框架识别、初始化,完全无法生效 - 重复声明ng-app:页面两个容器节点分别声明了
ng-app="myApp",AngularJS默认只会自动引导第一个匹配到的ng-app节点,第二个ng-app对应的作用域根本不会被框架接管 - 异步Promise逻辑错误:
$http请求返回的是Promise异步对象,直接将Promise对象赋值给$scope.recds2无法拿到接口返回的业务数据,必须在Promise的then回调中给作用域变量赋值 - 服务写法不符合规范:服务内未正确暴露
getJsonData调用方法,且错误地将$scope注入到服务中(服务是全局单例,不存在作用域概念) - 原生DOM操作存在同步问题:直接通过
document.getElementById修改元素显隐状态,没有和Angular作用域变量绑定,容易出现视图与数据不同步的问题 - HTML注释写法错误:代码中
<----- data below not produced----->不是合法HTML注释格式,会直接渲染在页面上,正确写法为<!-- 注释内容 -->
修正后实现代码
JS逻辑部分
var app = angular.module('myApp', []); // 全局注册数据服务,不要放在点击回调内 app.service('dataService', function($http) { // 暴露按账号拉取费用数据的方法 this.getJsonData = function(ac) { return $http.get('http://Amanda/Charges.aspx?ac=' + ac).then(function(response) { return response.data.records2; }); } }); // 二级表格控制器,全局注册 app.controller('customersCtrl2', function($scope, dataService) { $scope.dataService = dataService; $scope.showChargeTable = false; $scope.recds2 = []; }); // 首表格控制器 app.controller('customersCtrl', function($scope, $http) { // 加载首表格数据 $http.get("http://Amanda/test2.aspx") .then(function(response) { $scope.recds = response.data.records; }); // 行点击逻辑 $scope.go = function(account) { // 通过作用域变量控制表格显隐 $scope.showChargeTable = true; // 调用服务拉取对应账号数据,在回调内赋值 $scope.dataService.getJsonData(account).then(function(records) { $scope.recds2 = records; }); } });
HTML模板部分
<body style="background-color: #F1FAFA"> <!-- 整个页面仅声明一次ng-app,包裹所有需要Angular接管的节点 --> <div ng-app="myApp" ng-controller="customersCtrl2"> <!-- 首表格区域 --> <div ng-controller="customersCtrl"> <table id="Summary"> <tr> <th class="auto-style6" style="width: 66px">Annual<br>Ranking<br><span class="auto-style7">(this week)</span></th> <th>Account</th> <th>Customer</th> <th>Cust <br> Status</th> <th>% of <br>Annual<br>Revenue</th> <th>This week</th> <th>week-1</th> <th style="width: 71px">week-2</th> <th>week-3</th> <th> YTD <br>Revenue</th> <th>Receipted<br>Loads</th> <th>Receipted <br>Pallets</th> <th>Delivery <br>Loads</th> <th>Delivery<br>Pallets</th> <th>Last<br>Agreed £</th> </tr> <tr ng-repeat="x in recds" ng-click="go(x.Account)"> <td class="auto-style2" style="width: 66px">{{ x.Position }}<span class="auto-style8"> ({{ x.WPosition }})</span></td> <td id="act" class="auto-style2">{{ x.Account }}</td> <td class="auto-style2">{{ x.Customer }}</td> <td class="auto-style2">{{ x.CType }}</td> <td class="auto-style3">{{ x.Perc }}</td> <td class="auto-style5"> <span class="auto-style4">{{ x.ThisWeek}} </span> <img ng-src="{{(x.LastWeek - x.ThisWeek) < 0 ? 'Images/green.png' : 'Images/red.png'}}" class="auto-style4" style="float: right"> </td> <td class="auto-style1"> <span class="auto-style4">{{ x.LastWeek }} </span> <img ng-src="{{(x.Week2 - x.LastWeek) < 0 ? 'Images/green.png' : 'Images/red.png'}}" class="auto-style4" style="float: right"> </td> <td class="auto-style1" style="width: 71px"> <span class="auto-style4">{{ x.Week2 }} </span> <img ng-src="{{(x.Week3 - x.Week2) < 0 ? 'Images/green.png' : 'Images/red.png'}}" class="auto-style4" style="float: right"> </td> <td class="auto-style3">{{ x.Week3 }}</td> <td class="auto-style3">{{ x.YTD }}</td> <td class="auto-style3">{{ x.recs }}</td> <td class="auto-style3">{{ x.recsplt }}</td> <td class="auto-style3">{{ x.dels }}</td> <td class="auto-style3">{{ x.delsplt }}</td> <td id="preview" class="auto-style3">{{ x.preview }}</td> </tr> </table> </div> <!-- 二级费用表格区域,通过ng-show控制显隐,无需重复声明ng-app和controller --> <div id="div1" class="block2" ng-show="showChargeTable"> <table id="charge"> <tr> <th>Account</th> <th>Chargecode</th> <th>Rate</th> </tr> <!-- 修正非法HTML注释 --> <!-- data below not produced --> <tr ng-repeat="y in recds2"> <td>{{ y.Customer }}</td> <td>{{ y.ChargeCode }}</td> <td>{{ y.Charge }}</td> </tr> </table> </div> </div> </body>
补充排查点
- 打开浏览器控制台Network面板,确认点击行时
Charges.aspx接口请求正常,无跨域、404/500错误,返回数据结构中确实存在records2数组 - 确认接口返回的字段名与模板绑定的
Customer/ChargeCode/Charge完全一致,Angular模板绑定大小写敏感 - 如果需要父子控制器完全解耦,可以使用
$broadcast/$on做事件通信传递数据,避免作用域嵌套带来的变量污染问题
内容的提问来源于stack exchange,提问作者Robert Bee
相关产品推荐
相关产品推荐

