2013-01-31 34 views
26

是否可以通过在指令的作用域中传递值来即时更改templateUrl? 我想将数据传递给控制器​​,将根据从指令传递你可以随时更改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. 
     } 
    }); 

回答

53

这是可能的,但是当你的模板是加载取决于某些范围 - 数据,您不能再使用该指令的templateUrl属性,并且您将被迫使用较低级别的API,即$http$compile

你需要做的大概是什么(只能在链接功能中)是使用$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));     
       });    
      } 
     } 
    }); 

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

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

+0

是啊,我试图用ngInclude玩,但我不能f ind如何获得局部变量的值。如何在我的情况下获得'数据'?我正在尝试attrs.data,但它返回'undefined' – Agzam

+0

提供了更多信息。我不确定是否真的想要使用插值属性,因为这意味着模板可以作为$ digest循环的一部分动态更改。但如果你真的想这样做,你将不得不$观察属性。 –

+0

解决了我的问题。谢谢! – OpherV

16

这是Angular 1.1.4+版本中的一个新特性,我只是发现如果我使用当前unstable(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" 
]) 
+3

参数是'(元素,属性)' – EpiphanyMachine

+0

谢谢你发现这个 –

2

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

来源:

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

要:

var boom = scope.data.myData 

这为我工作,并有可能在指令中使用

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

+0

例子从上面的Plnkr分叉:[http://plnkr.co/edit/7BQxFEZ12Zxw9J9yT7hn](http://plnkr.co/edit/7BQxFEZ12Zxw9J9yT7hn? p =预览)。 请注意,即使'iAttrs.data'有一个值(如果你记录'iAttrs'对象,你可以看到),这种方法不适用于Angular 1.0.8(如上面所使用的),当你尝试访问它。 – GFoley83

1

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

.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(); 
      }); 
     } 
    }; 
} ]) 
0

这些问题的答案都不错,但不够专业。有使用templateUrl,这是我们不经常使用的语法。它可以返回一个url。那功能有一些参数的功能。如果你想要更多这里是一个很酷的文章

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

+0

这不是问题的核心。如果你真的创建了一个类似于OP的演示应用程序,你会发现你不能简单地将插值传递给指令的'templateURL'函数。 –

2

我有类似的问题

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 
 
     } 
 
    }; 
 
});
<nav-menu scrolled="scrolled"></nav-menu>

+0

这有助于即我的属性值将在运行时更改,并且需要基于此具有不同的模板url。 –

相关问题