2013-01-31 19 views
26

E 'possibile cambiare templateUrl al volo passando valori nella portata della direttiva? Voglio passare i dati al controllore che il rendering della pagina sulla base dei dati che passava dalla direttivaPuoi cambiare templateUrl al volo?

qualcosa forse che assomiglia a quello:

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

risposta

53

E 'possibile, ma quando il modello per essere caricato dipende da alcuni dati di ambito non è più possibile utilizzare la proprietà templateUrl della direttiva e sarà necessario utilizzare l'API di livello inferiore, ovvero $http e $compile.

Circa Quello che dovete fare (possibile solo in funzione di collegamento) è quello di recuperare il contenuto del modello utilizzando $http (non dimenticate di coinvolgere $templateCache!) E quindi compilare il contenuto del modello "manualmente".

Potrebbe sembrare che sia molto lavoro, ma in pratica è piuttosto semplice. Suggerirei di dare un'occhiata alla direttiva ngIncludesources in cui viene utilizzato questo modello.

Ecco uno scheletro di una tale direttiva:

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));     
       });    
      } 
     } 
    }); 

supponendo che sarebbe stato utilizzato come <boom data='name'></boom>. Lavoro plunk qui: http://plnkr.co/edit/TunwvhPPS6MdiJxpNBg8?p=preview

Si prega di notare che ho modificato la valutazione degli attributi da {{name}} agli attributi di analisi poiché probabilmente un modello dovrebbe essere determinato solo una volta, all'inizio.

+0

sì, sto cercando di giocare con ngInclude, ma io non posso f ind come ottenere il valore della variabile locale. Come ottenere 'dati' nel mio caso? Sto provando attrs.data, ma restituisce 'undefined' – Agzam

+0

Fornito maggiori informazioni. Non sono sicuro se vuoi davvero utilizzare l'interpolazione dei tuoi attributi poiché significherebbe che il modello può cambiare dinamicamente come parte del ciclo $ digest. Ma se vuoi davvero farlo dovresti $ osservare gli attributi. –

+0

Risolto anche il mio problema. Grazie! – OpherV

16

Questa è una nuova funzionalità in Angular versioni 1.1.4+ Ho appena scoperto che se uso l'attuale instabile (1.1.5) è possibile passare una funzione nell'URL modello di una direttiva. Il secondo parametro della funzione è il valore della direttiva attributo come mostrato di seguito.

Questo è un collegamento allo unpublished docs che mostra la modifica ufficiale.

Per utilizzare partials/template1.html come modello di URL da

Html:

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

direttiva:

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

i parametri sono '(elemento, attributi)' – EpiphanyMachine

+0

Grazie per aver trovato questo –

2

ho cambiato la risposta da pkozlowski.opensource un po '.

Da:

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

A:

var boom = scope.data.myData 

che ha funzionato per me ed è possibile utilizzare

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

nella direttiva.

+0

Esempio biforcuto da Plnkr sopra: [http://plnkr.co/edit/7BQxFEZ12Zxw9J9yT7hn](http://plnkr.co/edit/7BQxFEZ12Zxw9J9yT7hn? p = anteprima). Nota questo approccio non funziona con Angular 1.0.8 (come usato sopra) come anche se 'iAttrs.data' ha un valore (che puoi vedere se registri l'oggetto' iAttrs'), è 'indefinito' quando prova ad accedervi. – GFoley83

1

Questa è una risposta di follow-up che risolve alcuni problemi con le risposte precedenti.In particolare, compilerà i modelli solo una volta (che è importante se ne hai molti nella tua pagina, e guarderà le modifiche al modello dopo che è stato collegato. Copie inoltre classe e stile dall'elemento originale al template (anche se non nel modo molto elegante angular internamente quando si utilizza "replace: true". A differenza del metodo angolare supportato corrente di utilizzare una funzione per template o templateUrl, è possibile utilizzare le informazioni sull'ambito per determinare il modello da caricare.

.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

Quelle risposte sono buone, ma non professionale. C'è una sintassi di utilizzare templateUrl, che non usiamo spesso. può essere una funzione che restituisce un URL funzione .che ha alcuni argomenti. Se voglio di più qui è un articolo fresco

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

+0

Questo non è il problema a cuore. Se crei un'applicazione demo simile agli OP, vedrai che non puoi semplicemente passare il valore interpolato alla funzione 'templateURL' della direttiva. –

2

ho avuto problema simile

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

Questo aiuta ad avere cioè il mio valore di attributo cambierà durante il runtime e deve avere un url di modello diverso basato su quello. –