将 ng-include 节点替换为模板?

85

有点新接触 Angular。是否可能用包含的模板内容替换 ng-include 节点?例如:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <div ng-include src="'test.html'"></div>
</div>

生成的HTML代码为:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <div ng-include src="'test.html'">
        <span class="ng-scope"> </span>
        <p>Test</p>
        <span class="ng-scope"> </span>
    </div>
</div>

但是我想要的是:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <p>Test</p>
</div>

1
'test.html' 中删除单引号以使用模板而不是 URL。 - charlietfl
1
阅读ng-include文档的注释,似乎用单引号将模板字符串括起来,而不使用URL。此外,相关的stackoverflow问题:https://dev59.com/TGYr5IYBdhLWcg3wH2vK - SunnySydeUp
你正在倒序阅读文档和你链接的帖子。 - charlietfl
7个回答

134

我遇到了同样的问题,但仍然希望使用ng-include功能包含动态模板。我正在构建一个动态的Bootstrap工具栏,需要更清晰的标记以正确应用CSS样式。

这是我想出的解决方案,对于那些感兴趣的人:

HTML:

<div ng-include src="dynamicTemplatePath" include-replace></div>

自定义指令:

app.directive('includeReplace', function () {
    return {
        require: 'ngInclude',
        restrict: 'A', /* optional */
        link: function (scope, el, attrs) {
            el.replaceWith(el.children());
        }
    };
});

如果在上面的示例中使用此解决方案,将 scope.dynamicTemplatePath 设置为 'test.html' 将导致所需的标记。


需要 Angular v1.2+。 - colllin
太好了,期待进一步分析,但目前也在使用中!谢谢! - avcajaraville
9
请注意,这种DOM操作相当“hacky”。如果包含模板的根元素使用了诸如ng-repeat之类的内容,就会出现问题。它将无法将结果插入DOM中。 - Guria
在使用这个解决方案的同时,是否有改变模板的方法?我尝试过,但之前的模板仍然保留在页面上。 http://jsfiddle.net/U3pVM/19880/ 我在 jsfiddle 中删除了 require: 'ngInclude',因为出现了错误。 - Anton
1
请查看我的回答,这将失败,因为prelink函数已经在子元素中运行。 - Sai Dubbaka
显示剩余6条评论

28

感谢@user1737909的建议,我意识到ng-include并不是最好的选择。指令是更好和更明确的方法。

var App = angular.module('app', []);

App.directive('blah', function() {
    return {
        replace: true,
        restrict: 'E',  
        templateUrl: "test.html"
    };
});

在HTML中:

<blah></blah>

2
谢谢!我一直在寻找ng-include的解决方案,但这让我意识到指令更好。 - Matt Kim
请注意,模板中的 replace:true 已被标记为弃用。由于其弃用状态,我建议避免使用此解决方案。 - Peter V. Mørch
@PeterV.Mørch 谢谢。对于那些感兴趣的人,这是提交记录:https://github.com/angular/angular.js/commit/eec6394a342fb92fba5270eee11c83f1d895e9fb。看起来它被弃用是因为它过于复杂(也许还有其他原因)。 - SunnySydeUp

15

我有同样的问题,我的第三方CSS样式表不喜欢多余的DOM元素。

我的解决方案非常简单。只需将ng-include提前1个位置即可。因此,而不是

<md-sidenav flex class="md-whiteframe-z3" md-component-id="left" md-is-locked-open="$media('gt-md')">
  <div ng-include="myService.template"></span>
</md-sidenav>

我只是做了这个:

<md-sidenav flex class="md-whiteframe-z3" md-component-id="left" md-is-locked-open="$media('gt-md')" ng-include="myService.template">
</md-sidenav>

我打赌这在大多数情况下都会起作用,即使从技术上讲并不是问题所问的。


10

另一个选择是编写自己的简单替换/包含指令,例如:

另一种选择是编写自己的简单替换/包含指令,例如:

    .directive('myReplace', function () {
               return {
                   replace: true,
                   restrict: 'A',
                   templateUrl: function (iElement, iAttrs) {
                       if (!iAttrs.myReplace) throw new Error("my-replace: template url must be provided");
                       return iAttrs.myReplace;
                   }
               };
           });

接下来将按以下方式使用:

<div my-replace="test.html"></div>

9
这是替换子元素的正确方式。
angular.module('common').directive('includeReplace', function () {
    return {
        require: 'ngInclude',
        restrict: 'A',
        compile: function (tElement, tAttrs) {
            tElement.replaceWith(tElement.children());
            return {
                post : angular.noop
            };
        }
    };
});

4
我的部分HTML代码包含了一些ng-repeat语句,这是唯一解决它们的答案!非常感谢。 - Saad Benbouzid
我不得不将函数内容从“编译”移动到“链接”,因为在编译阶段我的元素是空的。 - itachi

3

以下指令扩展了ng-include本地指令的功能。

它添加了一个事件监听器,在内容准备好并加载后替换原始元素。

使用它的方式与原始方法相同,只需添加“replace”属性:

<ng-include src="'src.html'" replace></ng-include>

或者使用属性表示法:
<div ng-include="'src.html'" replace></div>

这里是指令(记得将“include-replace”模块作为依赖项包含在内):

angular.module('include-replace', []).directive('ngInclude', function () {
    return {
        priority: 1000,
        link: function($scope, $element, $attrs){

            if($attrs.replace !== undefined){
                var src = $scope.$eval($attrs.ngInclude || $attrs.src);

                var unbind = $scope.$on('$includeContentLoaded', function($event, loaded_src){
                    if(src === loaded_src){
                        $element.next().replaceWith($element.next().children());
                        unbind();
                    };
                });
            }
        }
    };
});

2

我建议选择比 @Brady Isom 提供的方案更加安全的解决方案。

我更喜欢依赖于 ng-include 提供的 onload 选项,以确保在尝试移除模板之前已经加载了它。

.directive('foo', [function () {
    return {
        restrict: 'E', //Or whatever you need
        scope: true,
        template: '<ng-include src="someTemplate.html" onload="replace()"></ng-include>',
        link: function (scope, elem) {
            scope.replace = function () {
                elem.replaceWith(elem.children());
            };
        }
    };
}])

无需第二个指令,因为一切都在第一个指令中处理。

请注意,使用Angular 1.5时,指令元素中的第一个子元素是注释。因此,我确保获取ng-include元素,然后用其子元素替换它:let ngInclude = angular.element( element[ 0 ].querySelector( 'ng-include' ) ); ngInclude.replaceWith( ngInclude.children() ); - Mattijs

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