2013-07-22 13 views
29

Data una direttiva (container1) con transclude e un ambito isolato, quando la direttiva è legata poi devo questi scopi:Perché l'ambito di ng-transclude non è figlio dell'ambito della sua direttiva - se la direttiva ha un ambito isolato?

Scope 004   <-- scope of the body 
    Scope 005  <-- scope of directive container1 
    Scope 006  <-- scope of the ng-transclude 

mi aspettavo:

Scope 004   <-- scope of the body 
    Scope 005  <-- scope of the directive 
     Scope 006 <-- scope of the ng-transclude 

Se la stessa direttiva ha un ambito condiviso anziché uno ambito isolato, ottengo il risultato previsto.

Questo mi causa un problema perché, se il contenuto transclusa contiene un'altra direttiva (component1) con un ambito isolato, ottengo:

Scope 004    <-- scope of the body 
    Scope 005   <-- scope of the directive 
    Scope 006   <-- scope of the ng-transclude 
      Scope 007 <-- scope of directive component1 

voglio usare le direttive di questo tipo:

<container1> 
    <component1 data="objectExposedInContainer1"/> 
</container1> 

Ma questo non funziona, all'interno di component1, $scope.data è undefined perché objectExposedInContainer1 non è l'ambito corretto.

Ho due domande:

  • Perché ng-transclude s' ambito di applicazione non è un bambino di portata del suo direttiva se la direttiva ha un ambito isolato? è un insetto?
  • Se non è un bug, come può una direttiva container passare i dati al suo contenuto, se non impostando attributi come ho provato.

Ecco un esempio in cui non funziona: http://plnkr.co/edit/NDmJiRzTF9e5gw8Buht2?p=preview. Poiché Plunker è costruito con Anguar, è difficile eseguire il debugging con Batarang. Raccomando di scaricare il codice localmente. Commentare line 10 di app.js per farlo funzionare utilizzando un ambito condiviso.

+0

1) No, avete ottenuto esattamente quello che hai chiesto - campo di applicazione della direttiva è isolato. 2) Utilizzare un controller condiviso. –

+0

@Joe Gauterin, guarda questo nuovo esempio: http://plnkr.co/edit/Bv7B4OokkLi8bIctCIl3. Qui, 'container1' contiene' component1' ma senza usare 'ng-transclude'. Questa volta, anche se entrambi hanno ambiti isolati, i loro ambiti hanno la relazione genitore/figlio corretta. La presenza di 'ng-transclude' altera il risultato. – Sylvain

risposta

29

Perché l'ambito di ng-transclude non è un bambino di portata del suo direttiva se la direttiva ha un ambito isolato?

ng-transclude atti a permettere direttive di lavorare con contenuto arbitrario e ambiti isolati sono progettati per consentire direttive per incapsulare i dati.

Se ng-transclude non ha mantenuto gli ambiti come quello, qualsiasi contenuto arbitrario che si sta transcinando dovrebbe conoscere i dettagli dell'implementazione della direttiva (ad esempio, sarebbe necessario sapere cosa è disponibile sull'ambito isolato creato).

Se non è un bug, come può una direttiva container passare i dati al suo contenuto, se non impostando attributi come ho provato.

Se la direttiva del contenitore e le direttive contenute sono accoppiate, vale a dire che le hai scritte entrambe e le hai necessarie per agire insieme, devono comunicare tramite un controller condiviso.

Se la direttiva contenitore deve iniettare il contenuto nello scopo dei bambini (ad es.ng-repeat), quindi non si dovrebbe usare un ambito isolato.


La documentazione angolare è abbastanza chiaro su che cosa il comportamento dovrebbe essere:

"In una configurazione tipica del widget crea un ambito isolato, ma l'inclusione non è un bambino, ma un fratello dell'ambito isolato: questo rende possibile che il widget abbia uno stato privato e che la limitazione sia associata all'ambito genitore (pre-isolato). "

+1

Grazie per questa risposta completa. – Sylvain

+0

Ho creato un lavoro ma non sono sicuro delle migliori pratiche, spero che voi ragazzi possiate avere un po 'di tempo libero per controllarlo? Si tratta di un hack transclusivo personalizzato che garantisce la creazione di un nuovo ambito isolato per un bambino nella fase di collegamento. Questo crea la gerarchia padre -> figlio in modo che possiamo usare $ emit e $ on nei controller. https://gist.github.com/meanJim/1c3339bde5cbeac6417d – Jim

+1

Anche io ho adottato un approccio simile a @Jim e anche io non sono sicuro che sia una buona pratica. Puoi trovare un plunk qui: http://plnkr.co/edit/Ph5lMl0ol8ayXOFr7eal –

11

è possibile transclude manualmente l'elemento figlio

link: function(scope, element, attrs, ctrl, transclude) { 
    transclude(scope, function(clone, scope) { 
     element.find('.transclude-placeholder').append(clone); 
    }); 
} 
3

La risposta superiore è corretta solo per angolare fino a v1.2.

A partire da Angular v1.3 il comportamento è cambiato e ora si comporta esattamente come descritto nella parte "Mi aspettavo" della domanda, rendendo questa domanda obsoleta per Angular v1.3 +.

Fonte: https://github.com/angular/angular.js/commit/fb0c77f0b66ed757a56af13f81b943419fdcbd7f

+0

Ciao, ho appena aggiornato l'esempio alla 1.3.15 e continua a fare la stessa cosa. http://plnkr.co/edit/PGsJRngCTCzstz85V80C?p=preview. Ho provato anche con 1.4 e ho ottenuto lo stesso risultato. Commenti? – Sylvain

+0

Infatti, oggi ho fatto una domanda per la quale ho fornito una risposta da solo in base a questa risposta! http://stackoverflow.com/questions/38267288/force-scope-to-named-slot-with-ng-transclude/38273990#38273990 –

Problemi correlati