简体   繁体   English

在控制器中带有ajax请求的AngularJS指令中未定义范围

[英]scope is undefined in AngularJS directive with ajax request in controller

I am working with AngularJS for about one week and I have a problem with a custom directive that I can't really understand. 我正在使用AngularJS大约一个星期,我遇到了一个我无法理解的自定义指令的问题。 My main goal is to make a html table in a directive with json data loaded in a controller with the $http service. 我的主要目标是在一个指令中创建一个html表,其中json数据在带有$ http服务的控制器中加载。

I have a template for my view. 我有一个模板供我查看。 If I use Angular directive like ng-repeat or expressions it seems data are correctly loaded and bound to the scope, and I can render my view. 如果我使用像ng-repeat或表达式这样的Angular指令,似乎数据被正确加载并绑定到范围,我可以渲染我的视图。

But if I use a custom directive at the document root, it is fired before the controller send the request. 但是,如果我在文档根目录中使用自定义指令,则会在控制器发送请求之前触发它。 So when I use the scope in the link function scope.myData is undefined. 所以当我在链接函数scope.myData中使用范围是未定义的。 But if I use a custom directive inside a ng-repeat I can access local scope. 但是如果我在ng-repeat中使用自定义指令,我可以访问本地范围。 I don't understand why Angular directive fire after data loading, and why mine fire before. 我不明白为什么Angular指令会在数据加载后触发,以及之前为什么会开火。 Am I missing somehing? 我错过了什么吗?

Actually, my data are really more complex than the sample, and I have to analyse them in a custom directive to generate my html table : make rowspan or colspan for certains attribute like group name in the sample data. 实际上,我的数据实际上比样本更复杂,我必须在自定义指令中分析它们以生成我的html表:make rowspan或colspan for certains属性,如示例数据中的group name。

Any help will be useful, thanks a lot in advance. 任何帮助将是有用的,非常感谢提前。

Here my sample code. 这是我的示例代码。

app.js 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 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 的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>

directives.js directives.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 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"]}
                ]

}

The link function is run only once. link功能只运行一次。 It DOES NOT wait for your ajax requests to fetch data and DOES NOT update when the scope changes. 它不会等待您的ajax请求获取数据,并且在范围更改时不会更新。

This is in contrast to {{databinding}} in your templates, which DOES update whenever the scope changes. 这与模板中的{{databinding}}形成对比,模板中的{{databinding}}随着范围的变化而更新。

You could have a look at $scope.$watch which allows you to run a callback whenever a specific scope attribute changes, like so: 您可以查看$scope.$watch ,它允许您在特定范围属性更改时运行回调,如下所示:

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

Using {{databinding}} and ng-repeat would be the more Angularic approach though. 然而,使用{{databinding}}ng-repeat将是更多的角度方法。

There are a few ways to do this: 有几种方法可以做到这一点:

  1. You can try the resolve route parameter (find it in the docs ). 您可以尝试resolve路由参数(在文档中找到它)。 This will delay loading a page until a promise is resolved. 这将延迟加载页面,直到解决了承诺。

  2. You are using Angular like jQuery - don't do that. 你正在使用像jQuery一样的Angular - 不要这样做。 (It is a common problem with Angular newcommers - read this great answer .) For your question about how ng-repeat sees the change: In short, ng-repeat watches the scope variable and takes action on change. (这是Angular新手的常见问题 - 阅读这个很棒的答案 。)关于ng-repeat如何看待变化的问题:简而言之, ng-repeat监视范围变量并对变化采取行动。 You could do something similar as: 你可以做类似的事情:

    scope.$watch("myData", function(newval) { ... }); 范围。$ watch(“myData”,function(newval){...});

If you want to set rowspan-colspan, maybe the expanded syntax of ng-repeat can help: 如果你想设置rowspan-colspan, ng-repeat的扩展语法可能会有所帮助:

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

(check the long example here ) (查看这里的长例)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM