【问题标题】:Can you change templateUrl on the fly?您可以即时更改 templateUrl 吗?
【发布时间】:2013-01-15 22:28:54
【问题描述】:

是否可以通过在指令范围内传递值来动态更改 templateUrl? 我想将数据传递给控制器​​,该控制器将根据从指令传递的数据呈现页面

可能看起来像这样:

<div> 
   <boom data="{{myData}}" />
</div> 

.directive('boom', function {
        return {
            restrict: 'E',
            transclude: true,
            scope: 'isolate',
            locals: { data: 'bind' },
            templateUrl: "myTemplate({{boom}}})" // <- that of course won't work.
        }
    });

【问题讨论】:

标签: angularjs angularjs-directive


【解决方案1】:

这是可能的,但是当你要加载的模板依赖于一些范围数据时,你不能再使用指令的 templateUrl 属性,你将不得不使用较低级别的 API,即 $http 和 @ 987654325@.

您需要做的(仅可能在链接功能中)是使用$http 检索模板的内容(不要忘记涉及$templateCache!)然后“手动”编译模板的内容。

这听起来像是很多工作,但实际上它相当简单。我建议查看使用此模式的ngInclude 指令sources

这是这样一个指令的框架:

app.directive('boom', function($http, $templateCache, $compile, $parse) {
        return {
            restrict: 'E',
            link: function(scope , iElement, iAttrs) {                            
              var boom = $parse(iAttrs.data)(scope);
              $http.get('myTemplate'+boom, {cache: $templateCache}).success(function(tplContent){
                iElement.replaceWith($compile(tplContent)(scope));                
              });              
            } 
        }
    });

假设它将被用作&lt;boom data='name'&gt;&lt;/boom&gt;。在这里工作:http://plnkr.co/edit/TunwvhPPS6MdiJxpNBg8?p=preview

请注意,我已将属性评估从 {{name}} 更改为属性解析,因为可能一个模板应该在开始时只确定一次。

【讨论】:

  • 是的,我正在尝试使用 ngInclude,但我找不到如何获取局部变量的值。在我的情况下如何获得data?我正在尝试 attrs.data,但它返回 undefined
  • 提供了更多信息。我不确定您是否真的想使用属性插值,因为这意味着模板可以作为 $digest 循环的一部分动态更改。但如果你真的想这样做,你就必须 $observe 属性。
  • 也解决了我的问题。谢谢!
  • 我使用的是 Angular 1.0.8,值得一提的是,当您在 Angular 之前没有包含 jQuery 时,$compile 会失败。\
  • 你无法想象我对此有多感激!我有自己的(类似)解决方案,但结合我的一个指令,它只编译了两次......非常感谢!
【解决方案2】:

这是 Angular 1.1.4+ 版本中的一项新功能,我刚刚发现如果我使用当前的不稳定 (1.1.5),您可以将函数传递到指令的模板 url。函数的第二个参数是属性指令的值,如下所示。

这里是unpublished docs 的链接,显示官方更改。

使用partials/template1.html作为来自

的模板url

HTML:

<div sub_view="template1"></div>

指令:

.directive('subView', [()->
  restrict: 'A'
  # this requires at least angular 1.1.4 (currently unstable)
  templateUrl: (notsurewhatthisis, attr)->
    "partials/#{attr.subView}.html"
])

【讨论】:

  • 参数为(element, attributes)
【解决方案3】:

我稍微改变了 pkozlowski.opensource 的答案。

发件人:

var boom = $parse(iAttrs.data)(scope);

收件人:

var boom = scope.data.myData

这对我有用并且可以使用

<boom data="{{myData}}" /> 

在指令中。

【讨论】:

  • 从上面的 Plnkr 分叉的示例:http://plnkr.co/edit/7BQxFEZ12Zxw9J9yT7hn。请注意,这种方法不适用于 Angular 1.0.8(如上所述),因为即使 iAttrs.data 有一个值(如果您记录 iAttrs 对象,您可以看到),当您尝试访问时它是 undefined它。
【解决方案4】:

这是一个后续答案,解决了之前答案的一些问题。值得注意的是,它只会编译一次模板(如果您的页面上有很多模板,这一点很重要,并且它会在模板链接后监视模板的更改。它还将类和样式从原始元素复制到模板(尽管当您使用“replace:true”时,Angular 不会以非常优雅的方式在内部执行。与当前使用模板或模板Url 的函数的角度支持的方法不同,您可以使用范围信息来确定要加载的模板。

.directive('boom', ['$http', '$templateCache', '$compile', function ($http, $templateCache, $compile) {
    //create a cache of compiled templates so we only compile templates a single time.
    var cache= {};
    return {
        restrict: 'E',
        scope: {
            Template: '&template'
        },
        link: function (scope, element, attrs) {
            //since we are replacing the element, and we may need to do it again, we need
            //to keep a reference to the element that is currently in the DOM
            var currentElement = element;
            var attach = function (template) {
                if (cache[template]) {
                    //use a cloneAttachFn so that the link function will clone the compiled elment instead of reusing it
                    cache[template](scope, function (e) {
                        //copy class and style
                        e.attr('class', element.attr('class'));
                        e.attr('style', element.attr('style'));
                        //replace the element currently in the DOM
                        currentElement.replaceWith(e);
                        //set e as the element currently in the dom
                        currentElement = e;
                    });
                }
                else {
                    $http.get('/pathtotemplates/' + template + '.html', {
                        cache: $templateCache
                    }).success(function (content) {
                        cache[template] = $compile(content);
                        attach(template);
                    }).error(function (err) {
                        //this is something specific to my implementation that could be customized
                        if (template != 'default') {
                            attach('default');
                        }
                        //do some generic hard coded template
                    });
                }
            };

            scope.$watch("Template()", function (v, o) {
                if (v != o) {
                    attach(v);
                }
            });
            scope.$on('$destroy', function(){
                currentElement.remove();
            });
        }
    };
} ])

【讨论】:

    【解决方案5】:

    这些答案很好,但不专业。有一种使用templateUrl 的语法,我们不经常使用它。它可以是一个返回url 的函数。该函数有一些参数。如果你想要更多,这里是一篇很酷的文章

    http://www.w3docs.com/snippets/angularjs/dynamically-change-template-url-in-angularjs-directives.html

    【讨论】:

    • 这不是核心问题。如果您实际上创建了一个类似于 OP 的演示应用程序,您会发现您不能简单地将插值传递给指令的 templateURL 函数。
    【解决方案6】:

    我也遇到过类似的问题

     return {
            restrict: 'AE',
            templateUrl: function(elm,attrs){return (attrs.scrolled='scrolled' ?'parts/scrolledNav.php':'parts/nav.php')},
            replace: true,

    partnersSite.directive('navMenu', function () {
        return {
            restrict: 'AE',
            templateUrl: function(elm,attrs){return (attrs.scrolled='scrolled' ?'parts/scrolledNav.php':'parts/nav.php')},
            replace: true,
            link: function (scope, elm, attrs) {
                scope.hidden = true;
                //other logics
            }
        };
    });
    &lt;nav-menu scrolled="scrolled"&gt;&lt;/nav-menu&gt;

    【讨论】:

    • 这对 有帮助吗,即我的属性值会在运行时发生变化,并且需要基于不同的模板 url那个。
    【解决方案7】:

    这个问题将使用 ng-include 解决如下:

    MyApp.directive('boom', function() {
        return {
          restrict: 'E',
          transclude: true,
          scope: 'isolate',
          locals: { data: 'bind' },
          templateUrl: '<div ng-include="templateUrl"></div>',
          link: function (scope) {
            function switchTemplate(temp) {
              if (temp == 'x')
              { scope.templateUrl = 'XTemplate.html' }
              else if (temp == 'y')
              { scope.templateUrl = 'YTemplate.html' }
            }
          }
        }
    });
    

    在指令的链接函数中使用任意temp参数调用switchTemplate函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-06
      • 2011-01-25
      • 1970-01-01
      • 2014-08-29
      • 2018-10-11
      相关资源
      最近更新 更多