La directiva ng-if
nos permite que exista o no un tag en la página. Podríamos pensar que es similar a ng-show o ng-hide, pero éstas últimas directivas simplemente los ocultan mediante CSS mientras que ng-if
los elimina del DOM o los vuelve a añadir.
Esta directiva no debería tener mucho que explicar pero realmente tiene un detalle que la hace muy importante. Crea un nuevo $scope
heredando de nuestro $scope
del controlador. Ésto realmente tiene una importancia enorme ya que implica saber cómo funciona la herencia de $scope
en JavaScript y AngularJS.
Vamos a ver primeramente un ejemplo y comprobaremos que hay algo que funciona mal.
En el ejemplo prueba a escribir algo en el nombre y en el apellido. Verás cómo el apellido sí se modifica en las 2 líneas pero el nombre no se modifica en uno de los casos.
¿Qué hay distinto en los 2 ejemplos? Simplemente que en el modelo del apellido hay un punto y en el del nombre, no.
<!DOCTYPE html> <html ng-app="app"> <head> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.js"></script> <script src="script.js"></script> </head> <body ng-controller="PruebaController"> <input type="checkbox" ng-model="showNombre">¿Mostrar nombre? <br> <div ng-if="showNombre"> Nombre: <input ng-model="nombre" > <br> El valor de "nombre" en el $scope del "ng-if" es : {{nombre}} </div> El valor de "nombre" en el $scope del "Controlador" es : <strong>{{nombre}}</strong> <hr> <input type="checkbox" ng-model="modelo.showApellido">¿Mostrar apellido? <br> <div ng-if="modelo.showApellido"> Apellido: <input ng-model="modelo.apellido" > <br> El valor de "apellido" en el $scope del "ng-if" es : {{modelo.apellido}} </div> El valor de "apellido" en el $scope del "Controlador" es : {{modelo.apellido}} </body> </html>
{{nombre}}
hace referencia al nuevo $scope
creado dentro de la directiva ng-if
.{{nombre}}
hace referencia al $scope
del controlador.{{apellido}}
hace referencia al nuevo $scope
creado dentro de la directiva ng-if
.{{apellido}}
hace referencia al $scope
del controlador.
var app = angular.module("app", []); app.controller("PruebaController", function($scope) { $scope.nombre="Carlos"; $scope.showNombre=true; $scope.modelo={ apellido:"Perez", showApellido:true } });
nombre
no está dentro de un objeto.apellido
está dentro de un objeto.¿Recuerdas la advertencia del tema 2.4 Formulario. Decía lo siguiente:
Si el valor de tu directiva ng-model no incluye un punto es que está mal
Ahora vamos a explicar del motivo de esta advertancia.
Voy a volver a recordar que dentro de una directiva ng-if
se crea un nuevo $scope
que hereda de nuestro $scope
del controlador. Ésto significa que cuando estamos poniendo los tag <input>
con el ng-model
, el nombre de la propiedad a la que hace referencia no es a nuestro $scope
de nuestro controlador sino al nuevo $scope
que hay dentro del ng-if
. Lo bueno de todo ello es que el nuevo $scope
que hay dentro del ng-if
ha heredado todos los valores que había en el $scope
del controlador.
Lo importante ahora es comprender cómo se ha hecho dicha herencia. Es algo tan chapuza que lo que hace es copiar simplemente el valor de todas las propiedades. El problema es que si una propiedad NO es un puntero a un objeto resulta que tendremos 2 propiedades distintas que tienen ahora 2 valores independientes.
Fíjate en el diagrama UML de objetos que se ha creado. Ahora cada $scope
tiene las propiedades repetidas, pero si esa propiedad apuntaba a un objeto, en ambos casos se apunta al mismo objeto. Ahora bien, si la propiedad no era un objeto , en cada $scope
cada propiedad es independiente.
Es decir que la propiedad nombre
del $scope
del ng-if
es distinta de la propiedad nombre
del $scope
del controlador , por lo tanto un cambio en la propiedad nombre
del $scope
del ng-if
no modifica el $scope
del controlador.
Sin embargo la propiedad modelo.apellido
del $scope
del ng-if
es la misma que la propiedad modelo.apellido
del $scope
del controlador ya que ambas apuntan al mismo objeto, por lo tanto un cambio en la propiedad modelo.apellido
del $scope
del ng-if
SI modifica el $scope
del controlador.
De todo ésto se deduce que siempre deberían estar nuestras propiedades dentro de objetos y por eso la frase:
Si el valor de tu directiva ng-model no incluye un punto es que está mal
Ya que tener un punto significa que los datos están dentro de un objeto.
$scope
del ng-if
hasta que no se cambia el valor. Mientras tanto sigue apuntando al $scope
del controlador mediante la cadena de prototipos de JavaScript.
Ésto último implica que si primero se hace un cambio en la propiedad nombre
del $scope
del controlador sí que se vería reflejada en la propiedad nombre
del $scope
del ng-if
. Pero una vez se modifica la propiedad nombre
del $scope
del ng-if
ya se hacen independientes.
Cambia el ejemplo de esta forma y mira a ver lo que ocurre cuando primero cambias un input u otro del nombre.
<input type="checkbox" ng-model="showNombre">¿Mostrar nombre? <br> Nombre: <input ng-model="nombre" > <div ng-if="showNombre"> Nombre: <input ng-model="nombre" > <br> El valor de "nombre" en el $scope del "ng-if" es : {{nombre}} </div> El valor de "nombre" en el $scope del "Controlador" es : <strong>{{nombre}}</strong>Añade la línea 3 al ejemplo y mira lo que ocurre.