最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using multiple AngularJS directives in one div tag - Stack Overflow

programmeradmin0浏览0评论

I am unable to use multiple directives in the same div tag. The following html does not display the product names that the module supplies

<!DOCTYPE html>
<html ng-app="gemStore">
    <head>
        <title></title>
        <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
    </head>
    <body>
        <div ng-controller="StoreController as store" ng-repeat="pro in store.products">
            <h1>{{pro.name}}</h1>
        </div>
        <script src='scripts/angular.min.js'></script>
        <script type="text/javascript" src="scripts/app.js"></script>
    </body>
</html>

But if I add the ng-controller in a different div tag(see below) I am able to see the products. What is the reason behind this.

<!DOCTYPE html>
<html ng-app="gemStore">
    <head>
        <title></title>
        <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
    </head>
    <body>
        <div ng-controller="StoreController as store" >
            <div ng-repeat="pro in store.products">
                <h1>{{pro.name}}</h1>
            </div>
        </div>
        <script src='scripts/angular.min.js'></script>
        <script type="text/javascript" src="scripts/app.js"></script>
    </body>
</html>

I did search about using multiple directives in a single div tag but was unsuccessful in finding any information. Is this a restriction imposed by AngularJS?

Following is the contents of app.js

(function() {
    var app = angular.module('gemStore', []);
    app.controller('StoreController', function() {
        this.products = gems;
    });

    var gems = [
        { name: 'Alwin', price: 200, description: "Checking my name" },
        { name: 'Alwin', price: 200, description: "Checking my name" },
        { name: 'Alwin', price: 200, description: "Checking my name" },
    ];


})();

I am unable to use multiple directives in the same div tag. The following html does not display the product names that the module supplies

<!DOCTYPE html>
<html ng-app="gemStore">
    <head>
        <title></title>
        <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
    </head>
    <body>
        <div ng-controller="StoreController as store" ng-repeat="pro in store.products">
            <h1>{{pro.name}}</h1>
        </div>
        <script src='scripts/angular.min.js'></script>
        <script type="text/javascript" src="scripts/app.js"></script>
    </body>
</html>

But if I add the ng-controller in a different div tag(see below) I am able to see the products. What is the reason behind this.

<!DOCTYPE html>
<html ng-app="gemStore">
    <head>
        <title></title>
        <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
    </head>
    <body>
        <div ng-controller="StoreController as store" >
            <div ng-repeat="pro in store.products">
                <h1>{{pro.name}}</h1>
            </div>
        </div>
        <script src='scripts/angular.min.js'></script>
        <script type="text/javascript" src="scripts/app.js"></script>
    </body>
</html>

I did search about using multiple directives in a single div tag but was unsuccessful in finding any information. Is this a restriction imposed by AngularJS?

Following is the contents of app.js

(function() {
    var app = angular.module('gemStore', []);
    app.controller('StoreController', function() {
        this.products = gems;
    });

    var gems = [
        { name: 'Alwin', price: 200, description: "Checking my name" },
        { name: 'Alwin', price: 200, description: "Checking my name" },
        { name: 'Alwin', price: 200, description: "Checking my name" },
    ];


})();
Share Improve this question edited Jun 24, 2014 at 12:31 Dhaval Panchal 6486 silver badges26 bronze badges asked Jun 24, 2014 at 12:27 Alwin DossAlwin Doss 9722 gold badges16 silver badges34 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 6

You can use multiple directives on the same DOM node. The issue you are running into is related to $pile priority and what ng-repeat does.

First of all you must understand that there's a clear algorithm that defines the way in which directives on the same DOM node are piled. There's a priority parameter that defaults to 0. Directives are piled based on this parameter, highest to lowest. ng-repeat has a priority of 1000 while ng-controller has a priority of 500. So ng-repeat is piled first.

Second you need to know how ng-repeat works. If you read the sources you see that it uses the terminal parameter. That parameter tells AngularJS that it should not pile any directives with lower priorities.

Thus, in your code, ng-controller is never piled ("executed").

Further, if ng-controller is not piled then ng-repeat does not have a $scope to work on, the $digest loop won't have anything to do. You'd be tempted to think store is undefined, and so is store.products, but you'd be wrong. If that were the case you'd see a lot of "Trying to access property 'products' on undefined object 'store'", but you don't because the code in ng-repeat is never executed.

What you are trying to do is not possible. ng-repeat would normaly create several instance of the specific tag. In your example it would create several divs, each one creating a seperate controller. I have no source for this, but I guess that $scope is only valid inbetween the controller tags. Therefore your ng-repeat argument does not point to you products list, but onto a higher scope. Due to the fact that there is no entry in this scope ng-repeat hast nothing to show.

Putting multiple directives onto a div is not a problem. This is a snippet of code from an app of mine, using both ng-click and ng-class:

<a href="" class="listItems" ng-click="selectPost($index)" ng-class="{disabledLink: !post.available}">

Your problem is you did it with the Controller, I'm not sure exactly how the ng-controller directive works, but you were essentially declaring a different instance of the controller, for each row in a list from the first controller. How this didn't end up in some crazy infinite loop, I don't know. But essentially, don't declare your controller in an ng-repeat. unless your looping through a list of controllers!

Edit: Daniel has hit the route of the problem much better than I did. The ng-repeat creates a html element for each item in the list. However the controller hadn't been initialised, so the was no scope to get the list from, so there were no elements to draw, and no controllers got created. By putting the ng-controller 1 element further up, the list was created, and there was a scope, containing a list, which the ng-repeat could use to draw your items.

Directives are piled and linked in priority order with the higher priority directives executed before lower priority directives.

ng-controller has a priority of 0 and ng-repeat has a priority of 1000, so ng-repeat is piled and linked first.

If both were piled, this would not cause the issue. However, ng-repeat is also defined with a terminal attribute.

According to angular documentation:

terminal:

If set to true then the current priority will be the last set of 
directives which will execute (any directives at the current priority 
will still execute as the order of execution on same priority is undefined).

This means that once ng-repeat is piled, no other directives with a lower priority (such as ng-controller) will be executed.

[EDIT]

Apparently, there is a discrepancy between the source code and documentation as to the correct priority of ng-controller. The code uses a priority of 500, but the documentation mentions it is defined with a priority of 0.

发布评论

评论列表(0)

  1. 暂无评论