Buscar..


Observaciones

Angular usa un árbol de ámbitos para vincular la lógica (desde controladores, directivas, etc.) a la vista y es el mecanismo principal detrás de la detección de cambios en AngularJS. Se puede encontrar una referencia más detallada para los ámbitos en docs.angularjs.org

La raíz del árbol es accesible a través del servicio inyectable $ rootScope . Todos los ámbitos de $ child heredan los métodos y las propiedades de su alcance de $ padre, permitiendo a los niños acceder a métodos sin el uso de los Servicios Angulares.

Ejemplo básico de la herencia $ 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>

En este ejemplo, la directiva ng-repeat crea un nuevo ámbito para cada uno de sus hijos recién creados.

Estos ámbitos creados son secundarios de su ámbito principal (en este caso, el ámbito creado por myController) y, por lo tanto, heredan todas sus propiedades, como persona.

Evitar heredar valores primitivos.

En javascript, la asignación de un valor no primitivo (como Objeto, Array, Función y muchos más) mantiene una referencia (una dirección en la memoria) al valor asignado.

Asignar un valor primitivo (Cadena, Número, Booleano o Símbolo) a dos variables diferentes, y cambiar una, no cambiará ambas:

var x = 5;
var y = x;
y = 6;
console.log(y === x, x, y); //false, 5, 6

Pero con un valor que no es primitiva, ya que ambas variables son simplemente mantener las referencias al mismo objeto, el cambio de una variable va a cambiar a la otra:

var x = { name : 'John Doe' };
var y = x;
y.name = 'Jhon';
console.log(x.name === y.name, x.name, y.name); //true, John, John

En angular, cuando se crea un ámbito, se le asignan todas sus propiedades principales. Sin embargo, cambiar las propiedades después solo afectará al ámbito principal si no es un valor 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>

Recuerde: en Angular, los ámbitos se pueden crear de muchas maneras (como directivas incorporadas o personalizadas, o la función $scope.$new() ), y es probable que sea imposible mantener un registro del árbol de ámbitos.

Utilizar solo valores no primitivos como propiedades de alcance lo mantendrá en el lado seguro (a menos que necesite una propiedad para no heredar, u otros casos en los que tenga conocimiento de la herencia de alcance).

Una función disponible en toda la aplicación.

Tenga cuidado, este enfoque podría considerarse como un mal diseño para las aplicaciones angulares, ya que requiere que los programadores recuerden dónde se ubican las funciones en el árbol de alcance y que sean conscientes de la herencia del alcance. En muchos casos, se preferiría inyectar un servicio ( práctica angular: uso de la herencia del alcance frente a la inyección .

Este ejemplo solo muestra cómo se puede usar la herencia de alcance para nuestras necesidades y cómo puede aprovecharla, y no las mejores prácticas para diseñar una aplicación completa.

En algunos casos, podríamos aprovechar la herencia del alcance y establecer una función como una propiedad del rootScope. De esta manera, todos los ámbitos de la aplicación (excepto los ámbitos aislados) heredarán esta función, y se puede llamar desde cualquier parte de la aplicación.

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>

Creando eventos personalizados de $ scope

Al igual que los elementos HTML normales, es posible que $ scopes tengan sus propios eventos. Los eventos de $ scope se pueden suscribir de la siguiente manera:

 $scope.$on('my-event', function(event, args) {
    console.log(args); // { custom: 'data' }
});

Si necesita anular el registro de un detector de eventos, la función $ on devolverá una función de desvinculación. Para continuar con el ejemplo anterior:

var unregisterMyEvent = $scope.$on('my-event', function(event, args) {
    console.log(args); // { custom: 'data' }
    unregisterMyEvent();
});

Hay dos formas de activar su propio evento $ scope $ broadcast y $ emit . Para notificar a los padres sobre el alcance de un evento específico, use $ emit

$scope.$emit('my-event', { custom: 'data' }); 

El ejemplo anterior activará los escuchas de eventos para my-event en el ámbito principal y continuará subiendo el árbol de ámbitos a $ rootScope a menos que un oyente llame a stopPropagation en el evento. Solo los eventos activados con $ stopPropagation pueden llamar stopPropagation

El reverso de $ emit es $ broadcast , que activará a los oyentes de eventos en todos los ámbitos secundarios del árbol de ámbitos que sean secundarios del alcance que se denominó $ broadcast .

$scope.$broadcast('my-event', { custom: 'data' });

Los eventos activados con $ broadcast no pueden ser cancelados.

Usando las funciones de $ scope

Si bien la declaración de una función en $ rootscope tiene sus ventajas, también podemos declarar una función $ scope en cualquier parte del código inyectado por el servicio $ scope. Controlador, por ejemplo.

Controlador

myApp.controller('myController', ['$scope', function($scope){
    $scope.myFunction = function () {
        alert("You are in myFunction!");
    };
}]);

Ahora puedes llamar a tu función desde el controlador usando:

$scope.myfunction();

O a través de HTML que está bajo ese controlador específico:

<div ng-controller="myController">
    <button ng-click="myFunction()"> Click me! </button>
</div>

Directiva

Una directiva angular es otro lugar donde puedes usar tu alcance:

myApp.directive('triggerFunction', function() {
    return {
        scope: {
            triggerFunction: '&'
        },
        link: function(scope, element) {
            element.bind('mouseover', function() {
                scope.triggerFunction();
            });
        }
    };
});

Y en tu código HTML bajo el mismo controlador:

<div ng-controller="myController">
    <button trigger-function="myFunction()"> Hover over me! </button>
</div>

Por supuesto, puede usar ngMouseover para la misma cosa, pero lo especial de las directivas es que puede personalizarlas de la manera que desee. Y ahora sabes cómo usar tus funciones de $ scope dentro de ellas, ¡sé creativo!

¿Cómo puede limitar el alcance de una directiva y por qué haría esto?

El alcance se utiliza como el "pegamento" que usamos para comunicarnos entre el controlador principal, la directiva y la plantilla de la directiva. Cada vez que se arranca la aplicación AngularJS, se crea un objeto rootScope. Cada ámbito creado por los controladores, directivas y servicios se hereda de forma prototípica de rootScope.

Sí, podemos limitar el alcance de una directiva. Podemos hacerlo creando un ámbito aislado para la directiva.

Hay 3 tipos de ámbitos directivos:

  1. Ámbito: Falso (Directiva utiliza su ámbito primario)
  2. Ámbito: Verdadero (la directiva adquiere un nuevo ámbito)
  3. Ámbito: {} (Directiva obtiene un nuevo ámbito aislado)

Directivas con el nuevo alcance aislado: cuando creamos un nuevo alcance aislado, no se heredará del alcance principal. Este nuevo ámbito se denomina Ámbito aislado porque está completamente separado de su ámbito principal. ¿Por qué? deberíamos usar un alcance aislado: debemos usar un alcance aislado cuando queremos crear una directiva personalizada porque nos aseguraremos de que nuestra directiva sea genérica y esté ubicada en cualquier lugar dentro de la aplicación. El ámbito principal no va a interferir con el ámbito de la directiva.

Ejemplo de alcance aislado:

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'/>"
    };
});

Hay 3 tipos de prefijos que AngularJS proporciona para el alcance aislado estos son:

  1. "@" (Enlace de texto / enlace unidireccional)
  2. "=" (Enlace directo del modelo / Enlace bidireccional)
  3. "&" (Enlace de comportamiento / Enlace de método)

Todos estos prefijos reciben datos de los atributos del elemento directivo como:

<div my-directive 
  class="directive"
  name="{{name}}" 
  reverse="reverseName()" 
  color="color" >
</div>


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow