AngularJS指令中的作用域未定义,控制器中有ajax请求

scope is undefined in AngularJS directive with ajax request in controller

本文关键字:控制器 ajax 请求 未定义 指令 作用域 AngularJS      更新时间:2024-06-27

我使用AngularJS大约一周了,我对一个自定义指令有一个问题,我真的无法理解。我的主要目标是用$http服务在控制器中加载的json数据在指令中创建一个html表。

我有一个视图模板。如果我使用像ng-reeat或表达式这样的Angular指令,那么数据似乎已正确加载并绑定到作用域,并且我可以呈现我的视图。

但是,如果我在文档根目录中使用自定义指令,它会在控制器发送请求之前被激发。因此,当我使用链接函数scope.myData中的作用域时,它是未定义的。但是,如果我在ng repeat中使用自定义指令,我可以访问本地作用域。我不明白为什么Angular指令在数据加载后触发,为什么我的指令在加载前触发。我是不是错过了什么?

事实上,我的数据确实比样本更复杂,我必须在一个自定义指令中分析它们来生成我的html表:在样本数据中为某些属性(如组名)生成rowspan或colspan。

任何帮助都是有用的,提前感谢。

这是我的示例代码。

app.js

    angular.module('myApp', [
  'ngRoute',
  'myApp.filters',
  'myApp.services',
  'myApp.directives',
  'myApp.controllers'
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: 'MyCtrl1'});
  $routeProvider.when('/test', {templateUrl: 'partials/test.html', controller: 'TestCtrl'});
  $routeProvider.otherwise({redirectTo: '/view1'});
}]);

controllers.js

angular.module('myApp.controllers', []).
  controller('TestCtrl',['$scope', '$http',function($scope, $http){
            $http.get('data/test.json').success(function(data) {
                    $scope.myData = data;
            }); 
  }])   ;

test.html

<!-- this works perfectly -->
<h3>{{myData.title}}</h3>
<table class="table table-condensed table-bordered">
    <thead>
        <tr>
            <th ng-repeat="col in myData.cols">{{col.title}}</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="row in myData.rows">
                    <td>{{row.group}}</td>
                    <td ng-repeat="col in row.cols">{{col}}</td>
        </tr>
    </tbody>
</table>
<!-- does not work ! -->
<table test-table></table>

指令.js

angular.module('myApp.directives', []).
        .directive('testTable', ['$compile', function(compile){
                return{
                    link: function(scope,elm,attrs,ctrl){
                    for(var i = 0, l= scope.myData.rows.length; i<l; i++){
                        var tr = angular.element(['<tr>', '</tr>'].join(''));
                        console.log(tr);
                        for(var j = 0; j<scope.myData.cols.length; j++){                          
                           var td = angular.element(['<td>', String(scope.myData.rows[i].cols[j]), '</td>'].join(''));
                           tr.append(td);  
                        }
                        elm.append(tr);
                    }
                    compile(elm.contents())(scope);
                }
                }
        }]);

test.json

{
    "title" : "This is a simple sample data.",
    "cols" : [{"title":"Group Name"},{"title":"Col1"},{"title":"Col2"},{"title":"Col3"}],
    "rows" : [
        {"group" : "group A","cols":["Something","Something else","Other stuff"]},
        {"group" : "group A","cols":["Something","Something else","Other stuff"]},
        {"group" : "group A","cols":["Something","Something else","Other stuff"]},
        {"group" : "group B","cols":["Something","Something else","Other stuff"]},
        {"group" : "group B","cols":["Something","Something else","Other stuff"]}
                ]
}

有几种方法可以做到这一点:

  1. 您可以尝试resolve路由参数(在文档中找到它)。这将延迟加载页面,直到承诺得到解决。

  2. 您使用的是类似于jQuery的Angular——不要这样做。(这是Angular newcommers的一个常见问题-阅读这个好答案。)对于您关于ng-repeat如何看待更改的问题:简而言之,ng-repeat监视范围变量并对更改采取行动。你可以做类似的事情:

    范围$watch("myData",函数(newval){。。。});

如果你想设置rowspan colspan,也许ng-repeat的扩展语法可以帮助你:

<header ng-repeat-start="item in items">
    ...
<footer ng-repeat-end>

(查看此处的长示例)

link函数只运行一次。它不会等待您的ajax请求获取数据,也不会在范围更改时更新。

这与模板中的{{databinding}}形成对比,后者在范围发生变化时都会更新。

您可以看看$scope.$watch,它允许您在特定范围属性更改时运行回调,如下所示:

scope.$watch('myData', function (newMyData) {
  //Build the table and insert it into DOM
});

使用{{databinding}}ng-repeat将是更具角度的方法。