AngularJS
Ambiti $ angolari
Ricerca…
Osservazioni
Angular utilizza un albero di ambiti per collegare la logica (da controller, direttive, ecc.) Alla vista e costituisce il meccanismo principale alla base del rilevamento dei cambiamenti in AngularJS. Un riferimento più dettagliato per gli ambiti può essere trovato su docs.angularjs.org
La radice dell'albero è accessibile tramite il servizio inject-$ $ rootScope . Tutti gli ambiti child $ ereditano i metodi e le proprietà del proprio scope $ scope, consentendo ai bambini l'accesso ai metodi senza l'uso di Angular Services.
Esempio di base dell'eredità $ scope
angular.module('app', [])
.controller('myController', ['$scope', function($scope){
$scope.person = { name: 'John Doe' };
}]);
<div ng-app="app" ng-conroller="myController">
<input ng-model="person.name" />
<div ng-repeat="number in [0,1,2,3]">
{{person.name}} {{number}}
</div>
</div>
In questo esempio, la direttiva ng-repeat crea un nuovo ambito per ciascuno dei suoi figli appena creati.
Questi ambiti creati sono figli del loro ambito genitore (in questo caso l'ambito creato da myController) e, pertanto, ereditano tutte le sue proporzioni, come la persona.
Evita di ereditare i valori primitivi
In javascript, assegnando un valore non primitivo (come Oggetto, Matrice, Funzione e molti altri), mantiene un riferimento (un indirizzo in memoria) al valore assegnato.
Assegnare un valore primitivo (String, Number, Boolean o Symbol) a due variabili diverse e cambiarne uno, non cambierà entrambi:
var x = 5;
var y = x;
y = 6;
console.log(y === x, x, y); //false, 5, 6
Ma con un valore non primitivo, poiché entrambe le variabili mantengono semplicemente i riferimenti allo stesso oggetto, cambiando una variabile si cambia l'altra:
var x = { name : 'John Doe' };
var y = x;
y.name = 'Jhon';
console.log(x.name === y.name, x.name, y.name); //true, John, John
In angolare, quando viene creato un ambito, vengono assegnate tutte le proprietà del suo genitore. Tuttavia, cambiando le proprietà in seguito, si influirà solo sull'ambito genitore se si tratta di un valore non primitivo:
angular.module('app', [])
.controller('myController', ['$scope', function($scope){
$scope.person = { name: 'John Doe' }; //non-primitive
$scope.name = 'Jhon Doe'; //primitive
}])
.controller('myController1', ['$scope', function($scope){}]);
<div ng-app="app" ng-controller="myController">
binding to input works: {{person.name}}<br/>
binding to input does not work: {{name}}<br/>
<div ng-controller="myController1">
<input ng-model="person.name" />
<input ng-model="name" />
</div>
</div>
Ricorda: in Gli ambiti angolari possono essere creati in molti modi (come le direttive incorporate o personalizzate, o la funzione $scope.$new()
) e tenere traccia della struttura ad albero è probabilmente impossibile.
Usando solo valori non primitivi come proprietà dell'ambito ti manterrai al sicuro (a meno che tu non abbia bisogno di una proprietà da non ereditare, o di altri casi in cui sei a conoscenza dell'ereditarietà dell'ambito).
Una funzione disponibile nell'intera app
Attenzione, questo approccio potrebbe essere considerato come una cattiva progettazione per le app angolari, dal momento che richiede ai programmatori di ricordare sia dove le funzioni sono posizionate nella struttura ad albero, sia a conoscenza dell'ereditarietà dell'ambito. In molti casi sarebbe preferibile iniettare un servizio ( pratica angolare - utilizzando l'ereditarietà dell'ambito rispetto all'iniezione) .
Questo esempio mostra solo come l'ereditarietà dell'ambito può essere utilizzata per le nostre esigenze e il modo in cui puoi trarne vantaggio, e non le migliori pratiche di progettazione di un'intera app.
In alcuni casi, potremmo sfruttare l'ereditarietà dell'ambito e impostare una funzione come proprietà di rootScope. In questo modo, tutti gli ambiti nell'app (tranne gli ambiti isolati) erediteranno questa funzione e potranno essere richiamati da qualsiasi punto dell'app.
angular.module('app', [])
.run(['$rootScope', function($rootScope){
var messages = []
$rootScope.addMessage = function(msg){
messages.push(msg);
}
}]);
<div ng-app="app">
<a ng-click="addMessage('hello world!')">it could be accsessed from here</a>
<div ng-include="inner.html"></div>
</div>
inner.html:
<div>
<button ng-click="addMessage('page')">and from here to!</button>
</div>
Creazione di eventi $ scope personalizzati
Come i normali elementi HTML, è possibile che gli ambiti $ abbiano i propri eventi. Gli eventi $ scope possono essere sottoscritti utilizzando la seguente modalità:
$scope.$on('my-event', function(event, args) {
console.log(args); // { custom: 'data' }
});
Se è necessario annullare la registrazione di un listener di eventi, la funzione $ on restituirà una funzione non vincolante. Per continuare con l'esempio precedente:
var unregisterMyEvent = $scope.$on('my-event', function(event, args) {
console.log(args); // { custom: 'data' }
unregisterMyEvent();
});
Esistono due modi per attivare il proprio evento $ scope $ broadcast e $ emit personalizzati . Per notificare il / i genitore / i di un ambito di un evento specifico, usa $ emit
$scope.$emit('my-event', { custom: 'data' });
L'esempio precedente attiverà qualsiasi listener di eventi per il my-event
nello scope parent e continuerà la struttura dell'oscilloscopio su $ rootScope a meno che un listener non chiami stopPropagation
sull'evento. Solo gli eventi attivati con $ emit possono chiamare stopPropagation
Il retro di $ emit è $ broadcast , che attiverà qualsiasi listener di eventi su tutti gli ambiti figlio nella struttura ad albero che sono figli dello scope che ha chiamato $ broadcast .
$scope.$broadcast('my-event', { custom: 'data' });
Gli eventi attivati con $ broadcast non possono essere annullati.
Usando le funzioni $ scope
Mentre dichiarare una funzione in $ rootcope ha i suoi vantaggi, possiamo anche dichiarare una funzione $ scope qualsiasi parte del codice che viene iniettata dal servizio $ scope. Controller, per esempio.
controllore
myApp.controller('myController', ['$scope', function($scope){
$scope.myFunction = function () {
alert("You are in myFunction!");
};
}]);
Ora puoi chiamare la tua funzione dal controller usando:
$scope.myfunction();
O tramite HTML che si trova sotto quel controller specifico:
<div ng-controller="myController">
<button ng-click="myFunction()"> Click me! </button>
</div>
Direttiva
Una direttiva angolare è un altro punto in cui puoi utilizzare il tuo ambito:
myApp.directive('triggerFunction', function() {
return {
scope: {
triggerFunction: '&'
},
link: function(scope, element) {
element.bind('mouseover', function() {
scope.triggerFunction();
});
}
};
});
E nel tuo codice HTML sotto lo stesso controller:
<div ng-controller="myController">
<button trigger-function="myFunction()"> Hover over me! </button>
</div>
Naturalmente, è possibile utilizzare ngMouseover per la stessa cosa, ma ciò che è speciale delle direttive è che è possibile personalizzarle nel modo desiderato. E ora sai come usare le tue funzioni $ scope al loro interno, sii creativo!
Come puoi limitare l'ambito di applicazione a una direttiva e perché dovresti farlo?
Scope è usato come "colla" che usiamo per comunicare tra il controllore genitore, la direttiva e il modello di direttiva. Ogni volta che l'applicazione AngularJS viene sottoposta a boot, viene creato un oggetto rootScope. Ogni ambito creato da controllori, direttive e servizi è prototipicamente ereditato da rootScope.
Sì, possiamo limitare l'ambito su una direttiva. Possiamo farlo creando un ambito isolato per la direttiva.
Esistono 3 tipi di ambiti direttive:
- Ambito: False (la direttiva usa il suo ambito genitore)
- Ambito: True (la direttiva ottiene un nuovo ambito)
- Ambito: {} (la direttiva ottiene un nuovo ambito isolato)
Direttive con il nuovo ambito isolato: quando creiamo un nuovo ambito isolato, esso non verrà ereditato dall'ambito principale. Questo nuovo ambito si chiama ambito isolato perché è completamente separato dall'ambito principale. Perché? dovremmo usare un ambito isolato: dovremmo usare un ambito isolato quando vogliamo creare una direttiva personalizzata perché farà in modo che la nostra direttiva sia generica e posizionata ovunque all'interno dell'applicazione. L'ambito genitore non interferirà con l'ambito della direttiva.
Esempio di ambito isolato:
var app = angular.module("test",[]);
app.controller("Ctrl1",function($scope){
$scope.name = "Prateek";
$scope.reverseName = function(){
$scope.name = $scope.name.split('').reverse().join('');
};
});
app.directive("myDirective", function(){
return {
restrict: "EA",
scope: {},
template: "<div>Your name is : {{name}}</div>"+
"Change your name : <input type='text' ng-model='name'/>"
};
});
Esistono 3 tipi di prefissi che AngularJS fornisce per l'ambito isolato:
- "@" (Rilegatura del testo / rilegatura unidirezionale)
- "=" (Rilegatura diretta del modello / rilegatura bidirezionale)
- "&" (Binding del comportamento / binding del metodo)
Tutti questi prefissi ricevono i dati dagli attributi dell'elemento direttiva come:
<div my-directive
class="directive"
name="{{name}}"
reverse="reverseName()"
color="color" >
</div>