javascript 动态添加 Angular 指令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20482592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 18:35:57  来源:igfitidea点击:

Dynamically adding Angular directives

javascriptangularjsangularjs-directive

提问by alfonsob

I'm fairly new to angular JS and am finding it a steep learning curve, I get the feeling im really missing the point here but here goes:

我对 Angular JS 还很陌生,我发现它的学习曲线很陡峭,我觉得我真的错过了这里的重点,但这里是:

I want to add a directive to my page from a controller. So I thought if I add the directive tag to the page, the directive and associated controller/template etc get added with it. After reading about the $compile method, I thought this would then be used to bind this directive to its newly created tag. This part is commented out below, but with or without this, I need the word login to appear and its controller to control it?

我想从控制器向我的页面添加指令。所以我想如果我将指令标签添加到页面,指令和关联的控制器/模板等就会被添加。在阅读了 $compile 方法之后,我认为这将用于将此指令绑定到其新创建的标签。这部分在下面注释掉了,但是有没有这个,我需要出现登录这个词并用它的控制器来控制它?

I can find lots of examples of similar around the web when the directive tag is on the page at load time, and can get those to work fine, so this is whats making think it is related to the $compile method - what am I missing?

当指令标签在加载时在页面上时,我可以在网络上找到很多类似的例子,并且可以让它们正常工作,所以这就是认为它与 $compile 方法相关的原因 - 我错过了什么?

HTML:

HTML:

<div ng-app="application" ng-controller="myController"></div>

JS:

JS:

var myApp = angular.module('application', []);

myApp.controller('myController', ['$scope', function($scope) {

        function showLoginDirective () {
            $scope.login = angular.element(document.createElement('login'));

            angular.element(document.body).append($scope.login);
        };

        showLoginDirective();
    }
]);

angular.module('directives', [])
    .directive('login', function($compile) {
        return {
            restrict: 'E',
            controller: 'LoginController',
            template: '<div>login</div>',
            link: function(scope, element, attrs) {
                //$compile(element.contents())(scope.$new);
                console.log('should I not have a div containing login controlled by loginController at this point?');
            }
        };
});

the above code is also here: http://jsfiddle.net/d5n6L/7/

上面的代码也在这里:http: //jsfiddle.net/d5n6L/7/

采纳答案by jraede

You shouldn't really be dynamically adding elements to the page with Angular. Many people, myself included, who come from a jQuery background, assume that we can continue with this practice and just add things to the page as we need them.

您真的不应该使用 Angular 向页面动态添加元素。许多有 jQuery 背景的人,包括我自己,都认为我们可以继续这种做法,只在需要时向页面添加内容。

However, with Angular, the logic should really all be visible in the markup. What does that mean? In your case, you should have the directive there no matter what, and then control its visibility with ng-showor ng-hideor ng-class.

然而,对于 Angular,逻辑应该在标记中全部可见。这意味着什么?在您的情况下,无论如何您都应该有指令,然后使用ng-showorng-hide或 or控制其可见性ng-class

So, something like this would be best:

所以,这样的事情最好:

<login ng-show="showLogin"></login>

And then you can use your directive as you programmed.

然后您可以在编程时使用您的指令。

Note that you can also define an inline controller (assign an array of dependencies and a function of those dependencies as the controllerproperty of your directive). That keeps all related code in the same place.

请注意,您还可以定义内联控制器(分配依赖项数组和这些依赖项的函数作为controller指令的属性)。这将所有相关代码保持在同一位置。

E.g.,

例如,

angular.module('directives', [])
    .directive('login', function($compile) {
        return {
            restrict: 'E',
            controller: ['$scope', function($scope) {

                function showLoginDirective () {
                    $scope.showLogin = true;

                };

                 showLoginDirective();
              }
            ],
            template: '<div>login</div>',
            link: function(scope, element, attrs) {
                //$compile(element.contents())(scope.$new);
                console.log('should i not have a div containing login controlled by loginController at this point?');
            }
        };
});

回答by eddiec

Rather than compiling dynamically from within your controller I suggest you use ng-if to declaratively express which DOM elements should exist on the DOM.

我建议您使用 ng-if 来声明性地表达哪些 DOM 元素应该存在于 DOM 上,而不是从您的控制器中动态编译。

HTML

HTML

<div ng-app="application" ng-controller="myController">
    <div ng-if="showLogin" login></div>
</div>

JS

JS

var myApp = angular.module('application', []);

myApp.controller('myController', ['$scope', function($scope) {

        function showLoginDirective () {
            $scope.showLogin = true;
        };

        showLoginDirective();
    }
]);

angular.module('directives', [])
    .directive('login', function($compile) {
        return {
            restrict: 'E',
            controller: 'LoginController',
            template: '<div>login</div>',
            link: function(scope, element, attrs) {
                //$compile(element.contents())(scope.$new);
                console.log('should i not have a div containing login controlled by loginController at this point?');
            }
        };
});

回答by Michal Charemza

I want to add a directive to my page from a controller.

我想从控制器向我的页面添加指令。

You should be able to define a boolean variable on the $scope that determines whether or not to show the login.

您应该能够在 $scope 上定义一个布尔变量来确定是否显示登录。

$scope.loginShouldBeShowing = false;
$scope.showLogin = function() {
  $scope.loginShouldBeShowing = true;
};

You can then use this in the template, with the ngIf directive, to only show the login template if this variable is set to true

然后,您可以在模板中使用 ngIf 指令,仅在此变量设置为 true 时才显示登录模板

<login ng-if="loginShouldBeShowing"></login>

You can see this in your modified JSFiddle at

您可以在修改后的 JSFiddle 中看到这一点

http://jsfiddle.net/jK9zr/2/

http://jsfiddle.net/jK9zr/2/

I've also added a button so you can see in the console that the linkfunction only runs after after you press the button, and loginShouldBeShowinggets set to true

我还添加了一个按钮,因此您可以在控制台中看到该link功能仅在您按下按钮后运行,并loginShouldBeShowing设置为true

I can find lots of examples of similar around the web when the directive tag is on the page at load time, and can get those to work fine, so this is whats making think it is related to the $compile method

当指令标签在加载时在页面上时,我可以在网络上找到很多类似的例子,并且可以让它们正常工作,所以这就是认为它与 $compile 方法有关的原因

From my understanding and previous use, it's perfectly usual to include directives in the template that are only used in certain situations, i.e. when certain $scope variables are set to certain values, using ngIf, or maybe ngSwitch or ngShow. I think things would soon get very messy if you tried to $compile every part of the template that may or may not be used at any one time. Although I'm only a relative beginner in AngularJS, so far I've only ever had to use $compile when evaluating attributes of custom directives, so

根据我的理解和以前的使用,在模板中包含仅在某些情况下使用的指令是非常常见的,即当某些 $scope 变量设置为某些值时,使用 ngIf,或者 ngSwitch 或 ngShow。我认为,如果您尝试 $compile 模板的每个部分可能会或可能不会在任何时候使用,事情很快就会变得非常混乱。虽然我只是 AngularJS 的相对初学者,但到目前为止我只需要在评估自定义指令的属性时使用 $compile,所以

<login after-login="doThisFunction()"></login>

might then need to use $compile to call doThisFunction()at an appropriate point.

然后可能需要使用 $compiledoThisFunction()在适当的点调用。

As a small sidebar, the names of your variables are a bit telling that in the controller, you're concerned with what's happening in the template. It's more usual to keep some sort of model/business "state" in the controller, and then show the appropriate thing in the template. So you might have in the controller:

作为一个小的侧边栏,变量的名称有点说明在控制器中,您关心模板中发生的事情。更常见的是在控制器中保留某种模型/业务“状态”,然后在模板中显示适当的内容。所以你可能在控制器中有:

$scope.loginState = 'loggedOut';

And then in the template:

然后在模板中:

<login ng-if="loginState == 'loggedOut'"></login>

Edit: I also noticed that the login directive was in a different module to the rest of the app. I suspect this caused issues, so I modified that aspect in my JSFiddle so there was only the one module.

编辑:我还注意到登录指令与应用程序的其余部分位于不同的模块中。我怀疑这会导致问题,因此我在 JSFiddle 中修改了该方面,因此只有一个模块。

Edit: I think I am confused between $compile and $parse above, so I would check against the docs/other sources about my use of $compile.

编辑:我想我对上面的 $compile 和 $parse 感到困惑,所以我会检查关于我使用 $compile 的文档/其他来源。