Angular.js 指令动态模板URL

Posted

技术标签:

【中文标题】Angular.js 指令动态模板URL【英文标题】:Angular.js directive dynamic templateURL 【发布时间】:2014-03-17 03:01:50 【问题描述】:

我在 routeProvider 模板中有一个自定义标签,它需要 directive 模板。 version 属性将由作用域填充,然后调用正确的模板。

<hymn ver="before- week - day "></hymn>

根据星期几和星期几,有多种版本的赞美诗。我期待使用该指令来填充正确的.html 部分。 templateUrl 没有读取该变量。

emanuel.directive('hymn', function() 
    var contentUrl;
    return 
        restrict: 'E',
        link: function(scope, element, attrs) 
            // concatenating the directory to the ver attr to select the correct excerpt for the day
            contentUrl = 'content/excerpts/hymn-' + attrs.ver + '.html';
        ,
        // passing in contentUrl variable
        templateUrl: contentUrl
    
);

excerpts 目录中有多个标记为before-1-monday.htmlbefore-2-tuesday.html、...的文件

【问题讨论】:

Dynamic templateUrl - AngularJS 的可能重复项 如果您使用的是 AngularJS 1.5+,请查看这个优雅的解决方案:***.com/a/41743424/1274852 【参考方案1】:
emanuel.directive('hymn', function() 
   return 
       restrict: 'E',
       link: function(scope, element, attrs) 
           // some ode
       ,
       templateUrl: function(elem,attrs) 
           return attrs.templateUrl || 'some/path/default.html'
       
   
);

所以你可以通过标记提供 templateUrl

<hymn template-url="contentUrl"><hymn>

现在您只需注意属性 contentUrl 会填充动态生成的路径。

【讨论】:

很好,但是...我可以从 templateUrl 函数访问范围属性吗? templateUrl 取决于范围值,但我无法访问它:( 很高兴您找到了解决方案。我不建议指令依赖于其父指令,除非它是在指令的 require 部分中设置的控制器。 终于!正是我想要的!我没有意识到我可以从 templateUrl 函数访问 elem 和 attrs 。谢谢! templateUrl 每个指令被调用一次,它不是在每个指令实例初始化时被调用,小心!!!虽然它可能是角度的错误...... 我还没有检查过,但根据我的最新发现,可能值得一提的是它是once per $compile phase。换句话说,如果您将ng-repeat 与您的指令一起使用,并希望根据特定的ng-repeat 项目上下文设置单独的模板,它将不起作用,因为$compile 阶段在实际ng-repeat 发生之前遍历您的指令一次。所以在这个意义上它被称为一次......【参考方案2】:

您可以使用ng-include 指令。

试试这样的:

emanuel.directive('hymn', function() 
   return 
       restrict: 'E',
       link: function(scope, element, attrs) 
           scope.getContentUrl = function() 
                return 'content/excerpts/hymn-' + attrs.ver + '.html';
           
       ,
       template: '<div ng-include="getContentUrl()"></div>'
   
);

UPD。用于观看ver属性

emanuel.directive('hymn', function() 
   return 
       restrict: 'E',
       link: function(scope, element, attrs) 
           scope.contentUrl = 'content/excerpts/hymn-' + attrs.ver + '.html';
           attrs.$observe("ver",function(v)
               scope.contentUrl = 'content/excerpts/hymn-' + v + '.html';
           );
       ,
       template: '<div ng-include="contentUrl"></div>'
   
);

【讨论】:

它的绝佳解决方案。有没有办法编写它可以处理多个实例?目前,一旦设置了范围,它就无法识别新的 attrs.ver。 你的意思是,你想看ver的属性变化和重新渲染指令? 感谢您的澄清。如果您以 upd. 中发布的方式声明指令,则使用多个 &lt;hymn ...&gt; 时的用例应该可以正常工作。或者也许是时候在jsfilddle 构建原型了? 您好 @AlenGiliana,Ive take a look at your site, and changed [JSFiddle](http://jsfiddle.net/JQgG5/6/). All you need is scope:` 在指令声明中 - scope isolation。此外,我强烈建议您使用最新版本的 angular。 &lt;script type="text/ng-template" id="..."&gt; - 是 html 页面的本地替代品 您的意思是使用 Angular 1.2.1 吗?顺便谢谢你的帮助,这个学习曲线太疯狂了:)【参考方案3】:

感谢@pgregory,我可以使用此指令进行内联编辑来解决我的问题

.directive("superEdit", function($compile)
    return
        link: function(scope, element, attrs)
            var colName = attrs["superEdit"];
            alert(colName);

            scope.getContentUrl = function() 
                if (colName == 'Something') 
                    return 'app/correction/templates/lov-edit.html';
                else 
                    return 'app/correction/templates/simple-edit.html';
                
            

            var template = '<div ng-include="getContentUrl()"></div>';

            var linkFn = $compile(template);
            var content = linkFn(scope);
            element.append(content);
        
    
)

【讨论】:

【参考方案4】:

这里不需要自定义指令。只需使用ng-include src 属性。它已编译,因此您可以将代码放入其中。 See plunker with solution for your issue.

<div ng-repeat="week in [1,2]">
  <div ng-repeat="day in ['monday', 'tuesday']">
    <ng-include src="'content/before-'+ week + '-' + day + '.html'"></ng-include>
  </div>
</div>

【讨论】:

【参考方案5】:

我遇到了同样的问题,但我以与其他人略有不同的方式解决了问题。 我正在使用角度 1.4.4。

在我的例子中,我有一个创建 CSS Bootstrap 面板的 shell 模板:

<div class="class-container panel panel-info">
    <div class="panel-heading">
        <h3 class="panel-title">title </h3>
    </div>
    <div class="panel-body">
        <sp-panel-body panelbodytpl="panelbodytpl"></sp-panel-body>
    </div>
</div>

我想根据路线包含面板正文模板。

    angular.module('MyApp')
    .directive('spPanelBody', ['$compile', function($compile)
        return 
            restrict        : 'E',
            scope : true,
            link: function (scope, element, attrs) 
                scope.data = angular.fromJson(scope.data);
                element.append($compile('<ng-include src="\'' + scope.panelbodytpl + '\'"></ng-include>')(scope));
            
        
    ]);

当路由为#/students 时,我将包含以下模板:

<div class="students-wrapper">
    <div ng-controller="StudentsIndexController as studentCtrl" class="row">
        <div ng-repeat="student in studentCtrl.students" class="col-sm-6 col-md-4 col-lg-3">
            <sp-panel 
            title="student.firstName student.middleName student.lastName"
            panelbodytpl="'/student/panel-body.html'"
            data="student"
            ></sp-panel>
        </div>
    </div>
</div>

panel-body.html 模板如下:

Date of Birth: data.dob * 1000 | date : 'dd MMM yyyy'

在有人想要尝试的情况下的示例数据:

var student = 
    'id'            : 1,
    'firstName'     : 'John',
    'middleName'    : '',
    'lastName'      : 'Smith',
    'dob'           : 1130799600,
    'current-class' : 5

【讨论】:

【参考方案6】:

我有一个关于这个的example。

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  </head>

  <body>
    <div class="container-fluid body-content" ng-controller="formView">
        <div class="row">
            <div class="col-md-12">
                <h4>Register Form</h4>
                <form class="form-horizontal" ng-submit="" name="f" novalidate>
                    <div ng-repeat="item in elements" class="form-group">
                        <label>item.Label</label>
                        <element type="item.Type" model="item"></element>
                    </div>
                    <input ng-show="f.$valid" type="submit" id="submit" value="Submit" class="" />
                </form>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
    <script src="app.js"></script>
  </body>

</html>

angular.module('app', [])
    .controller('formView', function ($scope) 
        $scope.elements = [
            "Id":1,
            "Type":"textbox",
            "FormId":24,
            "Label":"Name",
            "PlaceHolder":"Place Holder Text",
            "Max":20,
            "Required":false,
            "Options":null,
            "SelectedOption":null
          ,
          
            "Id":2,
            "Type":"textarea",
            "FormId":24,
            "Label":"AD2",
            "PlaceHolder":"Place Holder Text",
            "Max":20,
            "Required":true,
            "Options":null,
            "SelectedOption":null
        ];
    )
    .directive('element', function () 
        return 
            restrict: 'E',
            link: function (scope, element, attrs) 
                scope.contentUrl = attrs.type + '.html';
                attrs.$observe("ver", function (v) 
                    scope.contentUrl = v + '.html';
                );
            ,
            template: '<div ng-include="contentUrl"></div>'
        
    )

【讨论】:

以上是关于Angular.js 指令动态模板URL的主要内容,如果未能解决你的问题,请参考以下文章

Angular JS中的动态菜单指令问题

Angular.js 组件动态模板URL

Angular JS - 7 - Angular JS 常用指令2

angularJS 使用自定义指令输出模板

angular js中的directive

为啥 angular.js 在添加动态元素时不够聪明,无法编译 DOM?