Actualizar la variable de alcance principal en AngularJS

113

Tengo dos controladores, uno envuelto dentro del otro. Ahora sé que el alcance secundario hereda propiedades del alcance principal, pero ¿hay alguna forma de actualizar la variable del alcance principal? Hasta ahora no me he encontrado con ninguna solución obvia.

En mi situación, tengo un controlador de calendario dentro de un formulario. Me gustaría actualizar las fechas de inicio y finalización del ámbito principal (que es el formulario) para que el formulario tenga las fechas de inicio y finalización cuando se envíe.

Malcr001
fuente
Parece que su controlador de calendario debería ser una directiva.
Jonás

Respuestas:

193

Necesita usar un objeto (no una primitiva) en el alcance principal y luego podrá actualizarlo directamente desde el alcance secundario

Padre:

app.controller('ctrlParent',function($scope){
    $scope.parentprimitive = "someprimitive";
    $scope.parentobj = {};
    $scope.parentobj.parentproperty = "someproperty";
});

Niño:

app.controller('ctrlChild',function($scope){
    $scope.parentprimitive = "this will NOT modify the parent"; //new child scope variable
    $scope.parentobj.parentproperty = "this WILL modify the parent";
});

Demostración de trabajo : http://jsfiddle.net/sh0ber/xxNxj/

Consulte ¿Cuáles son los matices de la herencia prototípica / prototípica de alcance en AngularJS?

Dan
fuente
1
Recibo este error cuando intento implementar esto: 'No se puede establecer la propiedad' parentproperty 'de undefined'.
Malcr001
¿Puedes publicar tu código? Está funcionando en la demostración de violín. Si su control de calendario usa un alcance aislado, no heredará del alcance principal, por lo que deberá pasar el valor al alcance de la directiva.
Dan
Lo siento, olvidé esta pregunta. Lo acepté porque finalmente logré hacerlo funcionar con la ayuda de esta respuesta.
Malcr001
Entiendo que poner el {{parentobj.parentproperty}} en el elemento div ctrlParent es lo que declara el objeto parentobj y establece este objeto como en el alcance ctrlParent. ¿Es esta una suposición correcta?
Stephane
1
Gracias, esto funciona! Definitivamente debería leer sobre esto (herencia prototípica y primitivas). ¿Puedes recomendar una buena lectura que explique un poco más que tu enlace SO?
jvannistelrooy
116

Hay una forma más de hacer esta tarea y no usar la $scope.$parentvariable.

Simplemente prepare un método para cambiar el valor en el ámbito principal y úselo en el hijo uno. Me gusta esto:

app.controller('ctrlParent',function($scope) {
  $scope.simpleValue = 'x';
  $scope.changeSimpleValue = function(newVal) {
    $scope.simpleValue = newVal;
  };
});

app.controller('ctrlChild',function($scope){
    $scope.changeSimpleValue('y');
});

También funciona y le da más control sobre los cambios de valor.

A continuación, puede también llamar al método incluso en HTML como: <a ng-click="changeSimpleValue('y')" href="#">click me!</a>.

Ravbaker
fuente
1
¡Buena solución! esto funciona porque cuando algo no se encuentra en el $ scope actual, Angular busca en el $ parent. docs.angularjs.org/guide/scope (consulte 'Jerarquías de alcance').
Elo
Me gusta esta respuesta, no es necesario crear un objeto innecesario.
grimmdude
3
Futuros lectores: Todos estos comentarios de chocar los cinco están un poco equivocados. La creación de dos funciones de establecimiento (que son "objetos innecesarios") para cada variable es un torpe e innecesario kludge de herencia y no es la forma angular. Misko Hevery, el creador de Angular, da una charla en la que enseña "Siempre que tienes un ng-model, debe haber un punto en alguna parte. Si no tienes un punto, lo estás haciendo mal". Misko video @ 29:19
Dan
¿Cómo puedo aplicar esta solución usando la sintaxis controllerAS?
niran
6

Esto también funciona (pero no estoy seguro de si sigue las mejores prácticas o no)

app.controller('ctrlParent',function($scope) {
    $scope.simpleValue = 'x';
});

app.controller('ctrlChild',function($scope){
    $scope.$parent.simpleValue = 'y';
});
DynamicNate
fuente
1
Tiene razón, usar $ scope. $ Parent.value funcionará en la mayoría de los casos, sin embargo, por lo general, no es la mejor idea usarlo de manera extensiva, ya que puede ser difícil de administrar en proyectos más grandes y complicados.
Alex Johnson
4

Cuando asigna un atributo primitivo a un ámbito, siempre es local al ámbito (posiblemente creado sobre la marcha), incluso si un ámbito padre tiene un atributo con el mismo nombre. Esta es una decisión de diseño, y una buena en mi humilde opinión.

Si necesita cambiar alguna primitiva (ints, booleanos, cadenas) en el alcance principal, desde la vista, necesita que sea un atributo de otro objeto en ese alcance, por lo que la asignación puede leer:

<a ng-click="viewData.myAttr = 4">Click me!</a>

y, a su vez:

  1. consigue el viewData objeto de cualquier ámbito en el que esté definido
  2. asigne 4 a su myAttratributo.
reescrito
fuente
4

Para acceder a las variables declaradas en el padre, debemos usar $ parent en el controlador secundario o en el archivo de plantilla

En controlador

$scope.$parent.varaiable_name

En plantilla html

ng-model="$parent.varaiable_name"
Nibu
fuente