AngularJS - 模板中的指令

3
我会尽力为您翻译以下关于IT技术的内容。下面是需要翻译的内容(请注意保留 html 标记):

我试图找到最佳方法来动态创建使用指令创建的元素的子内容。

举个简单的例子,假设我有一个指令,它创建一个基本的 div 子元素。

<div mydirective></div>

导致

<div mydirective><div></div></div>

该指令可能类似于:
angular.module('demo', [])
.directive('mydirective', function() {
    return {
        restrict: 'A',           
        template:   '<div></div>'
    }
})

如果我想创建一个“扩展”,使内部的div变为蓝色,因为我不知道未来需要哪些扩展,所以我不想切换模板或绑定任何特定属性。

我不知道这些有哪些可能性,或者正常的方法是什么... 但是您能否:

1)向父元素添加另一个指令(类似于 css),即

<div mydirective mybluedirective></div>

我的bluedirective指令在哪里寻找内部div并操纵它?

或者

2)您可以在模板中动态包含指令,例如:

<div mydirective subdirective="mybluedirective"></div>

angular.module('demo', [])
.directive('mydirective', function() {
    return {
        restrict: 'A',           
        template:   '<div [[[THE SUBDIRECTIVE PROPERTY FROM SCOPE??]]></div>'
    }
})

有没有一种方法可以在预编译阶段拦截并注入指令?

第三个选项是使用工厂和继承类来为指令执行工作,但这似乎太过复杂。

我猜应该有一个我不知道的简单方法,任何建议都将不胜感激。

编辑:

我认为我正在尝试动态修改模板以在编译之前使用另一个指令。

3个回答

3

选项1-动态修改模板

如果你想在编译前动态修改一个模板,你可以使用模板函数:

HTML:

<div mydirective subdirective="mybluedirective"></div>

JS:

angular.module('demo', [])
.directive('mydirective', function() {
    return {
        restrict: 'A',           
        template:   function(element, attr) { 
             return '<div ' + attr.subdirective + '></div>'
        }
    }
})

选项2 - 编程访问模板

另外,您可以从mydirective暴露一个API供mybluedirective使用。这种解决方案要求mydirective延迟编译(因为模板将手动编译),并且需要更多的思考来设计和扩展mydirective

HTML

<div mydirective mybluedirective></div>

JS

angular.module('demo', [])
.directive('mydirective', function($compile) {

    return {
        restrict: 'A',           
        template:   '<div></div>',
        // we want a child scope so that we don't pollute the parent scope
        scope: true,
        controller: function($scope, $element) {
            var attrs = {};
            // expose an API to add attributes dynamically
            this.addAttr = function(attr, value) {
                attrs[attr] = value;
            }
            $scope.attrs = attrs;
        },
        compile: function(element, attr) {
            // save the template
            var template = element.find('div');

            // empty the contents so it is not compiled (we're manually compiling during link)
            element.empty();

            return function(scope, element, attr) {
                // add the attributes to the template
                angular.forEach($scope.attrs, function(value, key) {
                    template.addAttr(key, value);
                }
                // add the template to the DOM
                element.append(template);

                // link the template to scope
                $compile(template)(scope);
            }

        }

    }
})
.directive('mybluedirective', function() {
     return {
          restrict: 'A',
          require: 'mydirective',
          link: function(scope, element, attr, mydirectiveController) {
               mydirectiveController.addAttr('ng-class','blue');
          }
     }
});

很好,这是我问题中第2个问题的解决方案。 - sambomartin
两个答案都不错,但是指令式的更适合我。已点赞,但接受了另一个答案。 - sambomartin
谢谢。我正在尝试做的是“2)”。当mydirective编译时,它会包括在'mybluedirective'中定义的任何模板,对吗?此外,是否有一种常见的方式来在指令之间进行通信?想必它们需要共享一个控制器? - sambomartin
mybluedirective - 当它在另一个指令(mydirective)中编译时,我该如何将值绑定到指令(mybluedirective)的控制器上 - 是否有一种引用特定控制器的方法? - sambomartin
我理解你的意思,我认为那应该可行,但是我该怎么做呢? - sambomartin
显示剩余5条评论

2

我使用ng-class绑定到指令内部暴露的变量。您还需要添加作用域,并且如果想设置默认值,则需要添加控制器或链接函数。

这里是一个快速示例:

angular.module('demo', [])
.directive('mydirective', function() {
    return {
        restrict: 'A',           
        // add the ng-class to the template.  It binds to options.someClass
        template:   '<div ng-class="options.someClass"></div>',
        // give the directive its own Scope with an input object named options
        scope: {
            options : "="
        },  
        // Give the directive a controller
        controller: function($scope) {
            //  This is an init function to default the input objects 
             this.onInit = function(){
                   //  If the options object does not exist; create it 
                    if(!$scope.options){
                        $scope.options = {};
                    }
                   //  If our custom someClass variable doesn't exist; then give it a default value
                    if(!$scope.options.someClass){
                        $scope.options.someClass= "defaultClass";
                    }            }
             // call the onInit() function to set up the defaults
             onInit();
        }
    }
})

然后,我还提供了一个包含默认样式的CSS作为指令的一部分。您可以相对容易地将其实现。在您的控制器中创建我们的选项对象:

myDirectiveOptions = {
   someClass = 'myCustomClass';
}

在您的观点中,执行以下操作:

<div mydirective options="myDirectiveOptions"></div>

我发现这种方法既简单又非常强大。


使用这种方法;动态更改指令--ng-class--非常方便;你只需要更新选项对象即可。在你的控制器的某个地方,你可以这样做:

myDirectiveOptions.someClass = 'someOtherCustomClass';

由于 Angular 绑定的神奇机制,myDirective 内部的 ng-class 应该自动识别它。这个更改不必在 myDirective 的控制器中进行。


我理解你的意思,但我想要动态切换指令(在这种情况下是ng-class)。 - sambomartin
@sambomartin 我更新了我的回答;在这种情况下,你只需要改变 myDirectiveOptions.someClass,然后 myDirective 就会自动地捕捉到这些变化。我在我的一个应用程序中也是这样做的。 - JeffryHouser

2
你可以使用第二个指令来查找第一个指令的结果。只需确保“mybluedirective”比“mydirective”具有更高的优先级。
Js Fiddle:http://jsfiddle.net/XHJC2/
angular.module("demo", []).
    controller('SampleCtrl', function ($scope) {

    }).
    directive('mybluedirective', function () {
        return {
            priority: 4000,
            restrict: 'A',           
            link: function (scope, elem, attr) {
                elem.find('div').html('modified!');
            }
        };
    }).
    directive('mydirective', function() {
        return {
            priority: 40,
            restrict: 'A',           
            template:   '<div>TEST</div>'
        };
    });

这是有关指令中的“优先级”的文档:https://docs.angularjs.org/api/ng/service/$compile#-priority-


很好,这就是我问题中第一部分的解决方案。 - sambomartin
这个指令也可以使用模板吗?我不确定它是如何工作的,但与其替换HTML,不如应用一个特定的指令模板。 - sambomartin
我不明白另一个模板会在哪里呈现,因为目标是修改标记而不是完全替换它。您可以通过在指令中注入$compile并调用$compile('<div>my template {{bindMe}}</div>')(scope)来手动编译模板。此函数的结果可以插入到您选择的元素中(而不是替换所有内容)。 - Boyko Karadzhov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接