Saltar al contenido
Understanding Scopes in AngularJS Custom Directives

Understanding Scopes in AngularJS Custom Directives

Un vistazo al uso de ámbitos compartidos, heredados y aislados cuando se trabaja con directivas en AngularJS.

8min read

En esta publicación, aprenderemos sobre diferentes tipos de alcances en las directivas personalizadas de AngularJS. Para empezar, comenzaremos con una introducción de alto nivel de directivas y, a continuación, nos centraremos en los ámbitos.

Directivas

Las directivas son uno de los componentes más importantes de AngularJS 1.X y tienen los siguientes propósitos:

  1. Para dar un significado especial al elemento existente
  2. Para crear un nuevo elemento
  3. Para manipular el DOM

Más allá de ng-app, ng-controller y ng-repeat, hay muchas directivas integradas que vienen con AngularJS, que incluyen:

  • ng-maxlength
  • ng-minlength
  • ng-pattern
  • ng-requerido
  • ng-submit
  • ng-blur
  • ng-change
  • ng-checked
  • ng-click
  • ng-mouse
  • ng-bind
  • ng-href
  • ng-init
  • ng-model
  • ng-src
  • ng-style
  • ng-app
  • ng-controller
  • ng-disabled
  • ng-cloak
  • ng-hide
  • ng-if
  • ng-repeat
  • ng-show
  • Interruptor NG
  • ng-view

Principalmente, las directivas realizan cualquiera de las siguientes tareas:

  • Manipulate DOM
  • Iterate through data
  • Controlar eventos
  • Modify CSS
  • Validate data
  • Perform Data Binding  

Aunque hay muchas directivas integradas proporcionadas por el equipo de Angular, hay ocasiones en las que es posible que deba crear sus propias directivas personalizadas. Una directiva personalizada se puede crear como un elemento, atributo, comentario o clase. En esta publicación, se puede crear una directiva personalizada muy simple como se muestra en la lista a continuación:

MyApp.directive('helloWorld', function () {
    return {
        template: "Hello IG"
    };
});

Al crear directivas personalizadas, es importante recordar:

  • El nombre de la directiva debe estar en mayúsculas y minúsculas;
  • En la vista, la directiva se puede usar separando el nombre de mayúsculas y minúsculas del camello mediante un guión, dos puntos, un guión bajo o una combinación de estos.

Scopes in Custom Directives

Los ámbitos entran en escena cuando pasamos datos a directivas personalizadas. Hay tres tipos de visores, con un par ilustrados respectivamente con la imagen:

  1. Shared scope
  2. Inherited scope
  3. Isolated scope
Hay tres tipos de visores, con un par ilustrados respectivamente

Podemos crear una directiva personalizada con un ámbito heredado estableciendo la propiedad scope en true, como se muestra en la siguiente lista:

MyApp.directive('studentDirective', function () {
    return {
        template: "
{{student.name}} is {{student.age}} years old !!
",
        replace: true,
        restrict: 'E',
        scope : true ,
        controller: function ($scope) {
            console.log($scope);
        }
    }
});

Ámbito compartido y heredado

El ámbito compartido y el ámbito heredado son relativamente más fáciles de entender. En un ámbito compartido, las directivas comparten el ámbito con el controlador incluido.

Supongamos que tenemos un controlador, como se muestra en la lista a continuación:

MyApp.controller("StudentController", [
    "$scope",
    function ($scope) {
        console.log($scope);
        $scope.student = {
            name: "dj",
            age: 32,
            subject: ["math", "geography"],
        };

        $scope.setGrade = function (student) {
            student.grade = "A+";
        };
    },
]);

Next, let’s go ahead and create a custom directive:

MyApp.directive('studentDirective', function () {
    return {
        template: "
{{student.name}} is {{student.age}} years old !!
",
        replace: true,
        restrict: 'E',
        controller: function ($scope) {
            console.log($scope);
        }
    }
});

Aquí, podemos usar la directiva studenten la vista:

<div ng-controller="StudentController">
     <student-directive> </student-directive>
</div>

En el fragmento anterior, estamos usando la directiva dentro del div, donde la directiva ng-controller se establece en StudentController. Dado que no hemos establecido ningún valor para la propiedad scope en la directiva, de forma predeterminada funciona en el modo de alcance compartido. Las directivas pueden acceder a las propiedades asociadas al ámbito del controlador. Cualquier cambio en las propiedades de la directiva se reflejaría en el controlador y viceversa. También notará que estoy imprimiendo el identificador de ámbito tanto para el controlador como para la directiva, y ambos identificadores deben ser los mismos.

Los cambios en las propiedades de la directiva se reflejarían en el controlador y viceversa

Hay un problema con el ámbito compartido: no podemos pasar datos explícitamente a la directiva; La Directiva toma directamente los datos del controlador adjunto.

En el ámbito heredado, la directiva hereda el ámbito del controlador. Echemos un vistazo a cómo crear una directiva con alcance heredado a continuación:

MyApp.directive('studentDirective', function () {
    return {
        template: "
{{student.name}} is {{student.age}} years old !!
",
        replace: true,
        restrict: 'E',
        scope : true ,
        controller: function ($scope) {
            console.log($scope);
        }
    }
});

Un ámbito heredado es muy útil en directivas personalizadas anidadas.

Isolated Scope

En el ámbito aislado, la directiva no comparte un ámbito con el controlador; Tanto la directiva como el controlador tienen su propio alcance. Los datos, sin embargo, se pueden pasar al ámbito de la directiva de tres maneras posibles.

  1. Los datos se pueden pasar como una cadena mediante el literal de cadena @
  2. Los datos se pueden pasar como un objeto mediante el literal = string
  3. 3. Los datos se pueden pasar como una función del literal & string
En el ámbito aislado, la directiva no comparte un ámbito con el controlador; Tanto la directiva como el controlador tienen su propio alcance.

Un alcance aislado es muy importante porque nos permite pasar diferentes datos al controlador. Para entenderlo mejor, supongamos que tenemos un controlador como el que se enumera a continuación:

MyApp.controller("ProductController", function ($scope) {
    $scope.product1 = {
        name: 'Phone',
        price: '100',
        stock: true
    };
    $scope.product2 = {
        name: 'TV',
        price: '1000',
        stock: false
    };
    $scope.product3 = {
        name: 'Laptop',
        price: '800',
        stock: false
    };
 
    $scope.ShowData = function () {
        alert("Display Data");
    }
 
});

Como puedes ver aquí, tenemos tres productos diferentes, y queremos transmitirlo de manera diferente.

Pasar datos como una cadena

En el ámbito aislado, podemos pasar datos como una cadena mediante el literal de cadena @. Podemos crear una directiva personalizada que acepte la cadena como parámetro de entrada, como se muestra en la lista a continuación:

MyApp.directive('inventoryProduct', function () {
    return {
        restrict: 'E',
        scope: {
            name: '@',
            price:'@'
        },
        template: '
{{name}} costs {{price}} $
Change name
'
    };
});

En la lista anterior, estamos pasando dos parámetros de cadena usando el @ literal, lo que significa que se pasará una cadena en la variable name y price.  La directiva se puede usar en la vista donde, en el ejemplo, verá que estamos pasando un valor de cadena para name y el price en la directiva.

<div ng-controller="ProductController">
    <h1>{{product1.name}}</h1>
    <inventory-product name="{{product1.name}}" price="{{product1.price}}"></inventory-product>
</div>

Al ejecutar la aplicación, deberíamos poder ver el nombre y el precio del producto1.

Al ejecutar la aplicación, deberíamos poder ver el nombre y el precio

Cuando hacemos clic en el botón Cambiar nombre, solo se cambiará el nombre de la directiva y el objeto product1 de ProductController no se verá afectado debido al alcance aislado.

haga clic en el botón Cambiar nombre, solo se cambiará el nombre de la directiva y el objeto product1 de ProductController no se verá afectado debido al alcance aislado

También hay que tener en cuenta que cuando pasamos datos en un ámbito aislado como una cadena, se pasan de forma unidireccional, por lo que cualquier cambio en el ámbito del controlador se reflejará en la directiva. Sin embargo, un cambio en la directiva no se reflejaría en el controlador.

Pass Data As an Object

En el ámbito aislado, podemos pasar datos como un objeto usando el literal de cadena =. Podemos crear una directiva personalizada que aceptará un objeto como parámetro de entrada como se muestra en la lista a continuación:

MyApp.directive('inventoryProduct', function () {
    return {
        restrict: 'E',
        scope: {
            data: '='
        },
        template: '
{{data.name}} costs {{data.price}} $
Change name
'
    };
});

En la lista anterior, estamos pasando un parámetro de objeto usando el =literal. Aquí, el objeto se pasará a la variable de datos. La directiva se puede utilizar en la vista como se muestra en el listado a continuación. Como vemos, estamos pasando un valor de objeto para una variable de datos en la directiva.

<div ng-controller="ProductController">
    <h1>{{product1.name}}</h1>
    <inventory-product data="product1"></inventory-product>
    <h1>{{product2.name}}</h1>
    <inventory-product data="product2"></inventory-product>
    <h1>{{product3.name}}</h1>
    <inventory-product data="product3"></inventory-product>
</div>

Según la lista, estamos usando las directivas tres veces y pasando tres objetos distintos como entrada. Al ejecutar, veremos la salida como se muestra a continuación:

Según la lista, estamos usando las directivas tres veces y pasando tres objetos distintos como entrada.

Pasar el objeto en el ámbito aislado funciona en modo de enlace bidireccional, lo que significa que cualquier cambio en la directiva se reflejaría en el controlador incluido. Digamos que pasamos el producto1 dos veces, como se muestra en el listado a continuación:

<div ng-controller="ProductController">
    <inventory-product data="product1"></inventory-product>
    <inventory-product data="product1"></inventory-product>
</div>

Cuando ejecutamos la aplicación, se pasará el mismo objeto a ambas instancias de la directiva.

Cuando ejecutamos la aplicación, se pasará el mismo objeto a ambas instancias de la directiva.

Al hacer clic en cualquiera de los botones Cambiar nombre, se cambiará el nombre de la instancia de las directivas porque se pasa el mismo objeto y el paso de un objeto funciona en modo bidireccional. Cualquier cambio en la directiva se reflejaría en el controlador adjunto y viceversa.

Al hacer clic en cualquiera de los botones Cambiar nombre, se cambiará el nombre de ambas instancias de las directivas, ya que se pasa el mismo objeto

Calling an External Function

Podemos llamar a una función externa en la directiva adjunta usando la variable literal &. Como se indica con ProductController, hay una función ShowData(). Esta función se puede llamar en una directiva personalizada modificando la directiva como se muestra a continuación:

MyApp.directive('inventoryProduct', function () {
    return {
        restrict: 'E',
        scope: {
            data: '&',         
        },
        template: '
{{data.name}} costs {{data.price}} $
Change name
'
    };
});

Aquí, la directiva se puede usar en la vista como se muestra aquí:

<div ng-controller="ProductController">
  <inventory-product data="ShowData()"></inventory-product>
</div>

Conclusión

En esta publicación, comenzamos con una comprensión básica de las directivas y luego pasamos a los ámbitos, donde aprendimos sobre:

  1. Ámbito compartido: la directiva y los controladores comparten el ámbito y los datos. No podemos pasar datos explícitamente a la directiva.
  2. Ámbito heredado: hereda el ámbito del controlador. No podemos pasar datos explícitamente a la directiva.
  3. Ámbito aislado: la directiva y los controladores no comparten los datos y el ámbito. Podemos pasar datos como una cadena o un objeto explícitamente a la directiva.

Espero que encuentres útil esta publicación, y después de trabajar por tu cuenta con directivas, echa un vistazo a nuestro conjunto avanzado de controles y componentes de interfaz de usuario HTML5 y JavaScript, Ignite UI. ¡Puedes descargar IgniteUI ahora y ver lo que puede hacer por ti! ¡Gracias por leer!

Solicitar una demostración