2012-09-13 8 views
7

Per prendere confidenza con AngularJS, ho deciso di giocare con uno degli esempi, in particolare aggiungendo semplicemente una schermata "completa" all'esempio Todo, quando l'utente è entrato in 5 scenari utilizza un interruttore per passare a un altro div. Il codice è disponibile qui http://jsfiddle.net/FWCHU/1/ se è di qualche utilità.AngularJS, ambito di collegamento di una scatola interruttore?

Tuttavia, sembra che ogni caso di commutazione abbia il proprio ambito ($ scope.todoText non è disponibile), tuttavia è possibile accedervi utilizzando "this" dall'interno di addTodo() in questo caso. Fin qui tutto bene, ma diciamo che voglio accedere a todoText (che è all'interno del caso-interruttore) al di fuori del caso di commutazione, come potrei fare per farlo? Posso associare forse l'ambito del caso al modello, è accessibile in altro modo o dovrebbe essere risolto in qualche altro modo?

PS. Sono non cercando di trovare QUALSIASI soluzione al codice di cui sopra, sono abbastanza sicuro di sapere come risolverlo senza utilizzare le case-serie, voglio capire come funzionano gli ambiti in questo caso!

risposta

7

Mark ha dato ottimi consigli! Assicurati di controllare anche il AngularJS Batarang Chrome Extension per vedere i vari ambiti e i loro valori (tra le altre cose). Nota che non sembra funzionare bene con jsFiddle.

Non sono sicuro di come accedere direttamente agli ambiti interni, ma qui è un modo per accedere allo stesso testo nell'ambito esterno legandosi a un oggetto anziché a una primitiva.

1) dichiarare todoText come oggetto invece di una primitiva nel controllore:

$scope.todoText = {text: ''}; 

2) Bind per todoText.text invece di todoText:

<form ng-submit="addTodo()"> 
    <input type="text" ng-model="todoText.text" size="30" placeholder="add new todo here"> 
    <input class="btn-primary" type="submit" value="add"> 
</form> 

3) Modificare le funzioni esistenti per utilizzare todoText.text:

$scope.addTodo = function() { 
    $scope.todos.push({text:$scope.todoText.text, done:false, width: Math.floor(Math.random() * 100) + 50}); 
    $scope.todoText.text = ''; 
}; 

Dai uno sguardo allo this fiddle e nota che il testo visualizzato sotto la casella di testo quando digiti qualcosa sta accedendo allo todoText.text sull'ambito esterno.

Se si modifica il codice per utilizzare una primitiva (come in this fiddle) l'ambito genitore todoText non rifletterà alcuna modifica apportata alla casella di testo. Questo probabilmente dipende più dal modo in cui JavaScript copia i valori di riferimento (vedi this post per maggiori informazioni) e meno una cosa specifica di AngularJS.

+0

Grazie! Questo è esattamente ciò che stavo cercando, la ragione per cui todoText funziona quando lo si lega come oggetto (todoText.text) è che cerca un attributo oggetto esistente che presumo, in qualsiasi ambito genitore? Al contrario di "todoText" dove verrà creato nell'ambito corrente? – Andreas

+2

Non ho guardato il codice AngularJS ma presumo che quando viene creato un nuovo scope i valori vengano copiati nello scope figlio. Con una primitiva si ottiene una copia del valore stesso mentre con un oggetto copia il valore del riferimento che punta allo stesso oggetto. I primitivi sono immutabili, quindi se i cambiamenti primitivi nello scope secondario viene creato un nuovo valore non collegato al valore primitivo del genitore. Per un oggetto, il riferimento in entrambi gli ambiti padre e figlio sono gli stessi, quindi qualsiasi modifica alle proprietà è visibile in entrambi. Questo violino mostra ciò che sto cercando di spiegare: http://jsfiddle.net/uQzyh/ – Gloopy

+0

@Gloopy che ha davvero molto senso. – Andreas

5

Update2: Ora che so qualcosa di più su AngularJS, ecco una risposta molto migliore.

dire che voglio accedere todoText (che si trova all'interno dello switch-caso) al di fuori dello switch-caso, come dovrei andare a fare che?

Non esiste alcun modo per gli ambiti padre di accedere agli ambiti figlio. (Una delle ragioni di questa limitazione, according to Angular developers, è più facile per la gestione della memoria di ambiti.) (Beh, si potrebbe usare $$ e $$ childHead childTail per accedere portata bambino, ma non si dovrebbe!)

Can Forse leghiamo l'ambito del caso al modello forse, è accessibile in qualche altro modo o dovrebbe essere risolto in qualche altro modo ?

Ci sono tre modi comuni per accedere al modello di genitore dall'ambito bambino:

  1. Do ciò che suggerisce @Gloopy: creare un oggetto nel campo di applicazione genitore, quindi fare riferimento alla proprietà su tale oggetto nella portata del bambino.
  2. Utilizzare $ parent nello scenario figlio per accedere all'ambito padre e alle sue proprietà, anche primitive.
  3. chiamare un metodo sulla portata genitore

Per convertire il vostro violino per usare $ genitore:

<input type="text" ng-model="$parent.todoText" ... 

$scope.addTodo = function() { 
    $scope.todos.push({text: $scope.todoText, ... 
    $scope.todoText = ''; 

Come ho già detto in sede di commento risposta, ng-repeat di gloopy e ng-switch sia avere il nuovo ambito figlio ereditare prototipicamente dall'ambito padre. ng-repeat copia anche la variabile loop/item nel nuovo scope figlio (e le sfumature che @Gloopy descrive con primitive vs oggetto si applica). ng-switch non copia nulla dall'ambito genitore.

Per vedere ciò che l'ambito interno/figlio sembra, aggiungere il seguente dopo il ng-switch-quando:

<a ng-click="showScope($event)">show scope</a> 

e aggiungere questo al controller:

$scope.showScope = function(e) { 
    console.log(angular.element(e.srcElement).scope()); 
} 

Update1: (barrature aggiunte ai consigli errati, [] aggiunte per chiarezza)

Per questo scenario, dove AngularJS sta creando ulteriori ambiti interni (impl icitly), e tu non vuoi veramente/bisogno di un altro controller, mi piace la soluzione di Gloopy. Un servizio (quello che ho suggerito originariamente sotto) è [il modo sbagliato per farlo] probabilmente overkill qui. Mi piace anche che la soluzione di Gloopy non richieda l'uso di "this" nei metodi del controller.

risposta originale: (barratura aggiunto al cattivo consiglio, [s 'aggiunto per chiarezza])

Per vedere dove vengono creati ambiti (se non hai provato questo già, è a portata di mano):

.ng-scope { margin: 4px; border: 1px dashed red } 

Per accedere todoText fuori del switch-case (quindi al di fuori della sua portata), si sta chiedendo in sostanza la comunicazione inter-controllore, dal momento che più ambiti sono coinvolti. Hai alcune opzioni, ma un servizio è probabilmente il migliore. Archiviare i dati (che devono essere condivisi) all'interno del servizio e iniettare quel servizio in ogni controller che ha bisogno di accedere ai dati.

Per il vostro esempio specifico, penso che avreste bisogno di collegare un controller a ogni caso di commutazione e di iniettarvi il servizio, per ottenere l'accesso ai dati condivisi.

Vedere anche AngularJS: How can I pass variables between controllers?.

Le altre opzioni:

Utilizzando $ portata $ genitore nel perimetro interno è [un modo per fare questo - vedi sopra Update2] non raccomandato, da allora un controller sarebbe fare ipotesi su come. i dati sono presentati.

L'utilizzo di $ rootScope non è consigliato, ad eccezione forse di semplici applicazioni una tantum. Che i dati condivisi possano iniziare a vivere da soli, e $ rootScope non è il posto giusto per farlo. I servizi sono più facili da riutilizzare, aggiungere comportamenti, ecc.

Utilizzare $ scope. $ Emit è un'altra opzione, ma sembra disordinata e un po 'strana: emettere eventi per condividere dati (invece di comportarsi da trigger).

[L'utilizzo di un oggetto nell'area di genitore è probabilmente la cosa migliore - vedere @ risposta di gloopy.]

+0

Vorrei accettare anche questa risposta, ma purtroppo non posso. Ho scelto di accettare l'altro semplicemente perché in realtà presenta una soluzione. Ma le tue informazioni sono d'oro puro, molte grazie! – Andreas

Problemi correlati