【问题标题】:scope is undefined in AngularJS directive with ajax request in controller在控制器中使用ajax请求的AngularJS指令中未定义范围
【发布时间】:2013-12-11 10:02:21
【问题描述】:

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

我有一个视图模板。如果我使用 Angular 指令(如 ng-repeat 或表达式),似乎数据已正确加载并绑定到范围,我可以呈现我的视图。

但是如果我在文档根目录使用自定义指令,它会在控制器发送请求之前被触发。所以当我在链接函数中使用范围时,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>

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

{
    "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"]}
                ]

}

【问题讨论】:

    标签: javascript ajax json angularjs


    【解决方案1】:

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

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

    2. 您正在使用 Angular 之类的 jQuery - 不要那样做。 (这是 Angular 新手的常见问题 - 请阅读 this great answer。)关于 ng-repeat 如何看待变化的问题:简而言之,ng-repeat 观察范围变量并对变化采取行动。你可以做类似的事情:

      scope.$watch("myData", function(newval) { ... });

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

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

    (查看长示例here

    【讨论】:

    • 你是对的。我正在使用像 JQuery 这样的 Angular。我将改变主意并尝试更改我的数据骨架并使用 angular 指令在模板中完成所有主要工作。也许删除 HTML 表格并使用网格或其他方式制作我的模板。
    【解决方案2】:

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

    这与模板中的 {{databinding}} 形成对比,模板会在范围更改时更新。

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

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

    不过,使用 {{databinding}}ng-repeat 会是更 Angular 的方法。

    【讨论】:

      猜你喜欢
      • 2015-01-11
      • 2023-03-13
      • 2016-05-25
      • 1970-01-01
      • 2015-08-27
      • 1970-01-01
      • 1970-01-01
      • 2013-05-28
      • 1970-01-01
      相关资源
      最近更新 更多