Directiva AngularJS – Scopes

Me propongo hablar de las Directivas AngularJS y de los diferentes tipos de scopes que se pueden utilizar. Existen 3 formas principales en las que se puede pasar el scope a la directiva desde la vista invocadora (HTML):

  • Default Scope
  • Inherited Scope
  • Isolated Scope

Y el scope aislado podría ser en sí mismo:

  • Oneway
  • Twoway
  • Method Reference

Default Scope

En este tipo, el ámbito de la vista exterior sólo fluye hacia la directiva. Para decirlo de otra manera, el ámbito se pasa como «referencia» a la directiva. Todos los datos del scope estarán inmediatamente disponibles dentro de la directiva para ser consumidos. Del mismo modo, cualquier cambio realizado en el ámbito dentro de la directiva se reflejará en la vista que invoca inmediatamente.

vista y directiva vinculadas vis ámbito

Esto se consigue especificando el ámbito como

scope: false // false is the default value

en la definición de la directiva.

En el ejemplo siguiente, se vuela dentro de la directiva y cualquier cambio realizado se refleja fuera inmediatamente. Debido a que el ámbito se establece como verdadero, la directiva obtiene el ámbito como su llamador. Ahora cualquier cambio realizado en el nombre en la directiva se reflejará inmediatamente en el controlador ‘MyController’.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = "Jack";
});// usage: <div upper-case/></div>
myApp.directive('upperCase', function() {
return {
scope: false,
template: 'Name: <input ng-model="name"></input>'
}
});

El fiddle en vivo es @ https://jsfiddle.net/madhanganesh/830rn1fm/

Ambito heredado

En este tipo se hereda un nuevo ámbito de la vista. En Javascript, los objetos se heredan utilizando la herencia prototípica. Este escenario se representa en el siguiente diagrama:

Esto se consigue especificando el ámbito como

scope: true

en la definición de la directiva.

En el ejemplo de abajo puedes intentar cambiar el nombre en la directiva. Este cambio no se reflejará fuera debido al ámbito ‘heredado’. El valor sólo fluye dentro pero cualquier cambio resultará en una copia para la directiva y no se reflejará fuera.

En el ejemplo vivo de abajo, puede ver que el ‘nombre’ se vuela dentro de la directiva; pero el cambio hecho en la directiva no se reflejará fuera.

En el ejemplo de abajo, al ámbito de la directiva se le da un valor de true. Esto significa que se crea un ámbito para la directiva que «hereda» del ámbito del controlador. Según las reglas de herencia prototípicas de javascript, el objeto derivado (ámbito de la directiva) se refiere a las mismas propiedades del objeto padre (ámbito del controlador). Cualquier cambio realizado en el controlador se reflejará en la directiva, hasta que se realice un cambio en la propiedad «name» de la directiva. En ese momento se crea un nuevo objeto para la directiva y los cambios son opacos entre sí.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = "Jack";
});// usage: <div upper-case/></div>
myApp.directive('upperCase', function() {
return {
scope: true,
template: 'Name: <input ng-model="name"></input>'
}
});

Live fiddle es @ https://jsfiddle.net/madhanganesh/57sb6yg8/

Isolated Scope

En este tipo de definición de ámbito la directiva obtiene un ámbito independiente que no recibe ni devuelve ningún dato a la vista contenedora.

Esto se consigue especificando el ámbito como

scope: {}

en la definición de la directiva.

En el ejemplo de abajo el ámbito aislado se consigue pasando un objeto vacío {} a la directiva.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = "Jack";
});// usage: <div upper-case/></div>
myApp.directive('upperCase', function() {
return {
scope: {},
template: 'Name: <input ng-model="name"></input>'
}
});

El ámbito vivo es @ https://jsfiddle.net/madhanganesh/7d37w08e/

El ámbito aislado es realmente más que restringir completamente cualquier dato que se pase dentro (y fuera) de la directiva. En un extremo del espectro puede restringir completamente los datos como se muestra en el ejemplo anterior. Pero es posible pasar uno o más atributos a la directiva y capturarlos como un ámbito para la directiva. La flexibilidad viene en la forma en que el atributo pasado se interpreta dentro de la directiva. El atributo pasado a la directiva puede ser interpretado de una de las 3 formas siguientes:

  • como un oneway que se evalúa antes de pasarlo a la directiva
  • como un twoway una referencia a una propiedad en el ámbito de llamada
  • como una referencia a un método en el ámbito de llamada

Expresión

El llamador de la directiva puede pasar explícitamente un valor como se muestra a continuación:

<div my-directive name='{{name}}' />
// an expression is passed to the directive

La forma en que se captura dentro de la directiva es:

scope: {
name: '@name'
}

@ símbolo le dice a angular que considere el atributo name como una expresión y la evalúe antes de asignar el valor a la propiedad text. Debido a que la expresión se evalúa, es un enlace unidireccional y cualquier actualización realizada en el valor dentro de la directiva no se reflejará fuera.

En el ejemplo siguiente, vea que la propiedad name se pasa a la directiva. Esta es una expresión que se evalúa y se asigna al ámbito aislado de la directiva. Esto significa que el valor «Jack» es evaluado y asignado como texto dentro de la directiva.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = 'Jack';
});
// usage: <div my-directive name='{{name}}' />
myApp.directive('upperCase', function() {
return {
scope: {
name: '@name'
},
template: 'Name: <input ng-model="name"></input>'
}
});

El fiddle en vivo es @ https://jsfiddle.net/madhanganesh/ybzcryt0/4/

Debido a que name es un texto en la directiva los cambios son locales a la directiva y no se comparte nada con el controlador padre.

Dos vías (referencia a la propiedad)

El llamante de la directiva puede pasar una referencia a una propiedad a la directiva, como en:

<div my-directive name='data.name' />
// a property reference to the directive

La forma en que se captura dentro de la directiva es:

scope: {
name: '=name'
}

= símbolo le dice a angular para considerar el atributo nombre como una referencia a la propiedad específica del ámbito de llamada. Así que el valor se pasa a la directiva y cualquier cambio realizado en el atributo se refleja fuera inmediatamente.

En el ejemplo siguiente, ver que la propiedad nombre se pasa a la directiva. Esta es una referencia a la propiedad name en el ámbito padre.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = 'Jack';
});
myApp.directive('upperCase', function() {
return {
scope: {
name: '=name'
},
template: 'Name: <input ng-model="name"></input>'
}
});

Live fiddle es @ https://jsfiddle.net/madhanganesh/o74nvcj3/1/

Debido a que name es una referencia a la propiedad en el controlador cualquier cambio en cualquiera de los dos lados se reflejará en ambos.

Referencia al método

La forma en que se pasa desde la vista de llamada es:

<div my-directive nameFn="getName()" />
// a method reference is passed to the directive

La forma en que se captura dentro de la directiva es:

scope: {
nameFn: '& nameFn'
}

&el símbolo le dice a angular que considere el atributo nameFn como una referencia al método específico del ámbito de llamada. Este método puede entonces ser ejecutado desde dentro de la directiva cuando sea necesario.

En el ejemplo siguiente, se puede ver que la propiedad nameFn es un método cuya referencia se pasa dentro de la directiva. Esta función se ejecuta desde la directiva pero se evalúa en el contexto del ámbito de llamada.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = 'Jack';
$scope.getName = function() {
return $scope.name;
}
});
myApp.directive('upperCase', function() {
return {
scope: {
nameCb: '&name'
},
//template: 'Name: <input ng-model="nameFn()"></input>'
template: 'Name: {{textCb()}}'
}
});

La función en vivo es @ https://jsfiddle.net/madhanganesh/6w4msr5k/1/

Resumen

Como puedes ver el ámbito de la directiva es bastante exhaustivo, el siguiente resumen captura las posibilidades y su significado.

  • Por defecto : La directiva obtiene el mismo ámbito que su vista contenedora
  • Heredado: La directiva obtiene un ámbito que se hereda del ámbito de la vista contenedora
  • Isolated: La directiva obtiene un ámbito que es independiente de la vista contenedora

Y dentro del ámbito aislado hay 3 posibilidades:

Oneway : El atributo de la directiva se considera como una expresión y se evalúa antes de asignar a la propiedad específica del ámbito aislado de la directiva