在Angular中动态包含组件

时间:2017-07-05 10:19:56

标签: javascript angularjs angularjs-directive

我有一个角度应用程序(到目前为止)有一个插件机制,以便我可以在运行时添加和修改菜单项。为此,我有一个插件可以自行注册的服务,例如:

MenuService.addItem(
    "/main/foo",
    "bar",
    {
        title : "Bar",
        templateUrl : "foo/bar/templates/bar.html",
        controller : "BarController",
        controllerAs : "bar",
        visible : true,
        [...]
    }
);

然后我有一个指令来检索和迭代项添加给定的层次结构级别。在内部,它使用$ route来注册路由,模板可以像这样呈现结构:

 <li menu-item path="/main">
     <a href="{{item.path}}">{{item.title}}</a>
     <ul ng-if="items.children.length>0">
         <li menu-item path="{{item.path}}">
         </li>
     </ul>
 </li>

这一切都很简单,工作正常。现在,我还希望以类似的方式包含整个视图。大概是这样的:

<div include-components path="/main/foo">
</div>

我想迭代在此路径中注册的项目,并复制指令所在的节点或添加具有正确模板和控制器集的子节点。如果只注册了上面一个项目,那么生成的DOM应如下所示:

<div 
    include-components 
    path="/main/foo" 
    ng-controller="BarController" 
    ng-include="...template.html">

    [included template+controller render here]

</div>

或(带子元素):

<div include-components path="/main/foo">
    [first registered template /w controller]
    [second registered template /w controller]
    [...]
</div>

我目前的尝试看起来像这样:

angular.module("angular-plugin").directive(
    "includeComponents",
    function(MenuService,$route,$templateCache) {
        console.log($route);
        return {
            transclude: 'element',
            scope: {
                path : "@"
            },
            link: function(scope, el, attr, ctrl,transclude) {
                var items = MenuService.get(scope.path);
                items.forEach(function(each){
                     [... what?]
                });
            }
        }
    }
});

我在循环中尝试了很多不同的东西......但是我无法进行模板显示,更不用说让初始化项目中的控制器了。我正在查看ngView的源代码,它应该做一些非常相似的事情......但是我还没有能够让它工作。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

好的,现在我花了一些时间看ngView ......我想出了下面的指令。这确实有效。有什么遗漏?之后我是否需要进行任何清理工作?

angular.module("foobar").directive(
    "includeComponents",
    function(PluginMenuService,$route,$templateCache,$controller,$compile) {
        console.log($route);
        return {
            scope: {
                path : "@"
            },
            link: function(scope, el, attr, ctrl,transclude) {
                var items = PluginMenuService.get(scope.path);
                if(items.length > 0) {
                    items.forEach(
                        function(each) {
                            templ = $templateCache.get(each.templateUrl);
                            var child = el.append(templ);
                            var controller = $controller(each.controller, {});
                            var link = $compile(child.contents());

                            childScope = scope.$new();

                            childScope[each.controllerAs] = controller;
                            childScope["component"] = each;
                            child.data('$ngControllerController', controller);

                            link(childScope);
                        }
                    );
                }
            }
        }
    });