2013-04-04 8 views
10

La mia configurazione è la seguente direttiva:

<div data-directive-a data-value="#33ff33" data-checked="true"> 
    <div data-directive-b></div> 
</div> 
  • sto usando inclusione per garantire directiveB ottiene resi.
  • directiveA ha una casella di controllo che ha lo scopo di modificare qualche valore ogni volta che viene controllato.
  • questo valore deve essere accessibile nello scope directiveA e directiveB.

Sono riuscito a farlo, ma solo facendo riferimento a $$prevSibling - c'è un modo migliore?

Ecco il codice: http://jsfiddle.net/janeklb/yugQf/ (in questo esempio, facendo clic sulla casella di controllo è semplicemente lo scopo di "clear" del valore)

-

Un po 'più di profondità: I 'contenuti' di directiveA (ciò che viene incluso in esso) non è sempre directiveB. Altre direttive come directiveB finiranno anche lì. I "tipi" directiveB verranno sempre utilizzati entro directiveA.

+2

vi consiglio di utilizzare richiedere definizione della direttiva e passare regolatore genitore al controllore bambino –

+1

Perché queste direttive a tutti considerato che non fanno nulla? Se sono solo illustrativi del problema, queste direttive * dovrebbero sempre * essere usate insieme o potrebbero essere usate separatamente?Vuoi che la direttivaB sia sempre inclusa in riferimento all'ambito della direttiva A invece di un nuovo figlio del genitore? Perché direttivaA ha un ambito isolato ma la direttiva B non dichiara alcun nuovo ambito? –

+1

@JoshDavidMiller Ho aggiunto un po 'più di profondità alla descrizione sopra. Per quanto riguarda l'ambito non dichiarato su 'B' e l'ambito isolato su' A' - Non ho impostato in questo modo per nessuna ragione in particolare. Tutto quello che so è che ho bisogno di passare alcuni dati dal DOM alla direttiva (s), e il modo migliore sembrava essere 'scope: {xxx: '@'}' – jlb

risposta

12

Per evitare di unire troppo i componenti, eviterei di utilizzare $$prevSibling. La migliore soluzione dal momento che i componenti di tipo directiveB devono essere utilizzati all'interno dei componenti directiveA utilizzando require.

.directive('directiveB', function() { 
    return { 
    require: '^directiveA', 
    scope: true, 
    link: function (scope, element, attrs, directiveA) { 
     scope.obj = directiveA.getObj(); 
    } 
    }; 
}) 

Il ^require indica che da qualche parte sull'elemento della presente direttiva o su qualsiasi elemento sopra di esso nella gerarchia DOM è una direttiva chiamata directiveA, e vogliamo chiamare metodi su suo controllore.

.directive('directiveA', function() { 
    return { 
    // ... 
    controller: function ($scope) { 
     // ... 
     this.getObj = function() { 
     return $scope.obj; 
     }; 
    } 
    }; 
}) 

Così ora in directiveB è possibile utilizzare ng-model="obj.attr".

Ci sono molte varianti su questo, ma considerando la domanda generale, ritengo che questo sia l'approccio migliore. Ecco un Fiddle aggiornato: http://jsfiddle.net/yugQf/7/.

+0

Nel tuo fiddle, le proprietà dell'isolamento "attr" e "value" non vengono utilizzate e possono quindi essere rimosse. –

+0

@MarkRajcok - Hai ragione. Sono venuti dal Fiddle che ha postato e ha indicato in risposta alla mia domanda sul suo post che li voleva, ma non sono usati. Li ho rimossi allo stesso modo per evitare confusione. Ancora una volta, grazie signore per il suggerimento! –

+0

L'orologio $ nella direttiva B non è necessario. Dato che getObj() restituisce un oggetto, è sufficiente assegnarlo all'ambito di direttivaB, perché sarà un riferimento all'oggetto in directionA. Quindi tutto ciò che è necessario nella funzione di collegamento è 'scope.obj = directiveA.getObj();'. In questo [Fiddle] (http://jsfiddle.net/mrajcok/ffmC6/) ho usato 'obj2' nella direttivaB per dimostrare più chiaramente il concetto. Inoltre, nel codice di esempio sopra per direttivaB, hai 'scope: true', ma il tuo violino non ha questo. Quale preferisci/intendi? (solo curioso, funziona in entrambi i modi) –

6

@Josh menzionato nella sua risposta che

La soluzione migliore in quanto i tuoi directiveB -come componenti dovrebbero essere utilizzati entro directiveA componenti è quello di utilizzare require.

ho accarezzato con questo e credo che un controllore sulla directiveA è l'unica soluzione (così +1 Josh). Ecco cosa gli scopi simile utilizzando violino del PO: (. Reverse la freccia marrone e si dispone di $$ previousSibling invece di $$ nextSibling) scopes picture

Oltre $$previousSibling, portata 004 non ha alcun percorso di isolare scope 003.Notare che l'ambito 004 è l'ambito transcluso creato da directiveA e dal momento che directiveB non crea un nuovo ambito, questo ambito viene anche utilizzato da directiveB.

Poiché l'oggetto che si desidera condividere con directiveB viene creato nel controller directiveA, non è possibile utilizzare gli attributi per condividere i dati tra le direttive.


Creare un modello all'interno di una direttiva e quindi condividerlo con il mondo esterno è piuttosto atipico. Normalmente, ti consigliamo di definire i tuoi modelli al di fuori delle tue direttive e anche al di fuori dei tuoi controller (listen for a few minutes to Misko). I servizi sono spesso un buon posto per memorizzare i tuoi modelli/dati. I controllori dovrebbero normalmente fare riferimento alle parti del/i modello/i che devono essere proiettate nella vista a cui sono associate.

Per semplicità, ho intenzione di definire il modello su un controller, quindi le direttive accederanno entrambi a questo modello nel modo normale. Per scopi pedagogici, directiveA utilizzerà comunque un ambito isolato e directiveB creerà un nuovo ambito figlio utilizzando scope: new come nella risposta di @ Josh. Ma qualsiasi tipo (isolare, nuovo figlio, nessun nuovo ambito) e la combinazione funzioneranno, ora che abbiamo il modello definito in un ambito genitore.

Ctrl:

$scope.model = {value: '#33ff33', checkedState = true}; 

HTML:

<div ng-controller="NoTouchPrevSibling"> 
    <div data-directive-a data-value="model.value" data-checked="model.checkedState"> 
     <div data-directive-b></div> 
    </div> 

Per altri motivi pedagogici, ho optato per passare directiveA le due proprietà modello come attributi separati, ma la anche l'intero modello/oggetto poteva essere passato. Poiché direttivaB creerà un ambito secondario, non è necessario passare alcun attributo poiché ha accesso a tutte le proprietà dell'ambito padre/controllore.

direttive:

app.directive('directiveA', function() { 
    return { 
     template: '<div>' 
      + 'inside parent directive: {{checkedState}}' 
      + '<input type="checkbox" ng-model="checkedState" />' 
      + '<div ng-transclude></div>' 
      + '</div>', 
     transclude: true, 
     replace: true, 
     scope: { 
       value: '=', 
       checkedState: '=checked' 
      }, 
    }; 
}); 
app.directive('directiveB', function() { 
    return { 
     template: '<div>' 
      + '<span>inside transcluded directive: {{model.checkedState}}</span>' 
      + '<input type="text" ng-model="model.value" />' 
      + '</div>', 
     replace: true, 
     scope: true 
    }; 
}); 

Mirini:

scopes

Si noti che la portata del bambino directiveB (006) eredita da portata transclusa di directiveA (005).

Dopo aver fatto clic sulla casella di controllo e modificando il valore nella casella di testo:

scopes after interaction

Si noti che le maniglie angolari aggiornamento delle proprietà dell'ambito isolare. Normale JavaScript prototypal inheritance fornisce l'accesso child scope della direttiva B allo model nell'ambito del controller (003).

Fiddle

+0

+1 Illustrazione molto bella! Apprezzo sempre i diagrammi di ereditarietà inclusi nelle risposte relative all'ambito. –

+0

+1 Grazie per gli schemi Mark: ho accettato la risposta di Josh come prima, ma il tuo contributo è molto apprezzato. – jlb

+1

@jlb, Josh ha fornito la vera risposta, quindi merita sicuramente l'accettazione. Stavo pensando alla tua (eccellente) domanda un'altra mattina. Mi ha infastidito il fatto che siamo costretti ad usare la soluzione 'require'. Aggiungerò alcuni pensieri aggiuntivi (e diagrammi) alla mia risposta (quando avrò un po 'di tempo). Per dare una rapida carrellata però: la creazione di un modello all'interno di una direttiva e la sua condivisione all'esterno è piuttosto atipica. Il modo più tipico è avere un controller che faccia riferimento a un modello, che può quindi essere condiviso con tutte le direttive figlio/discendente. –

Problemi correlati