2012-09-13 19 views
7

Para controlar AngularJS decidí jugar con uno de los ejemplos, específicamente, simplemente agregando una pantalla "completa" al ejemplo de Todo, cuando el usuario ingresó 5 todos usa una caja de conmutadores para cambiar a otro div. El código está disponible aquí http://jsfiddle.net/FWCHU/1/ si es de alguna utilidad.AngularJS, enlace el alcance de una caja de interruptores?

Sin embargo, parece que cada switch-case tiene su propio alcance ($ scope.todoText no está disponible), sin embargo se puede acceder usando "this" desde addTodo() en este caso. Hasta ahora todo bien, pero digo que quiero acceder a todoText (que está dentro de la caja del conmutador) fuera de la caja del conmutador, ¿cómo voy a hacer eso? ¿Puedo vincular el alcance del conmutador con el modelo? ¿Se puede acceder de alguna otra forma o se debe resolver de otra forma?

PS. Estoy no tratando de encontrar CUALQUIER solución al código anterior, estoy bastante seguro de que sé cómo resolverlo sin usar conmutadores, ¡quiero entender cómo funcionan los alcances en este caso!

Respuesta

7

Mark tiene algunas sugerencias! Asegúrese de consultar también AngularJS Batarang Chrome Extension para ver los distintos ámbitos y sus valores (entre otras cosas). Tenga en cuenta que no parece funcionar bien con jsFiddle.

No estoy seguro de cómo acceder a los ámbitos internos directamente, pero esta es una forma de acceder al mismo texto en el ámbito externo mediante el enlace a un objeto en lugar de a una primitiva.

1) Declarar todoText como un objeto en lugar de una primitiva en su controlador:

$scope.todoText = {text: ''}; 

2) Enlazar a todoText.text en lugar de sólo todoText:

<form ng-submit="addTodo()"> 
    <input type="text" ng-model="todoText.text" size="30" placeholder="add new todo here"> 
    <input class="btn-primary" type="submit" value="add"> 
</form> 

3) Modificar las funciones existentes a use todoText.text:

$scope.addTodo = function() { 
    $scope.todos.push({text:$scope.todoText.text, done:false, width: Math.floor(Math.random() * 100) + 50}); 
    $scope.todoText.text = ''; 
}; 

Eche un vistazo a this fiddle y tenga en cuenta que el texto que se muestra debajo del cuadro de texto cuando ingresa algo está accediendo al todoText.text en el ámbito externo.

Si cambia el código para utilizar una primitiva (como en this fiddle), el ámbito principal todoText no reflejará los cambios que realice en el cuadro de texto. Es probable que esto tenga más que ver con cómo JavaScript copia los valores de referencia (consulte this post para obtener más información) y menos algo específico de AngularJS.

+0

¡Gracias! Eso es exactamente lo que estaba buscando, ¿por qué todoTexto funciona cuando lo vincula como un objeto (todoText.text) es que busca un objeto-atributo existente, supongo, en cualquier ámbito principal? ¿A diferencia de "todoText" donde se creará en el ámbito actual? – Andreas

+2

No he observado el código AngularJS pero supongo que cuando se crea un nuevo ámbito, los valores se copian en el ámbito secundario. Con una primitiva obtienes una copia del valor en sí, mientras que con un objeto copia el valor de la referencia que apunta al mismo objeto. Las primitivas son inmutables, por lo que si se modifican las primitivas en el ámbito secundario, se crea un nuevo valor que no está vinculado al valor primitivo del padre. Para un objeto, la referencia en los ámbitos padre e hijo es la misma, por lo que los cambios en las propiedades son visibles en ambos. Este violín muestra lo que estoy tratando de explicar: http://jsfiddle.net/uQzyh/ – Gloopy

+0

@Gloopy que tiene mucho sentido en realidad. – Andreas

5

Update2: Ahora que sé un poco más sobre AngularJS, esta es una respuesta mucho mejor.

decir que quiero acceder todoText (que está dentro del switch de los casos) fuera del switch de los casos, ¿cómo voy a ir haciendo eso?

No hay forma de que los ámbitos principales accedan a los ámbitos secundarios. (Una razón para esta restricción, according to Angular developers, es más fácil para la gestión de la memoria de ámbitos.) (Bueno, se podría utilizar $$ $$ childHead y childTail acceder ámbito secundario, pero no se debe!)

Puede Puedo vincular el alcance del conmutador con el modelo, tal vez, ¿está accesible de alguna otra manera o debería resolverse de alguna otra manera ?

Hay tres formas comunes de acceso al modelo padre del alcance del niño:

  1. Haz lo que sugiere @Gloopy: crear un objeto en el ámbito primario, a continuación, se refieren a las propiedades de ese objeto en el alcance del niño
  2. Use $ parent en el ámbito secundario para acceder al ámbito primario y sus propiedades, incluso las primitivas.
  3. llamar a un método en el ámbito padre

para convertir su violín a utilizar $ matriz:

<input type="text" ng-model="$parent.todoText" ... 

$scope.addTodo = function() { 
    $scope.todos.push({text: $scope.todoText, ... 
    $scope.todoText = ''; 

Como ya he mencionado en los comentarios sobre la respuesta, ng-repetición de Gloopy y ng-switch tanto hacer que el alcance del nuevo hijo herede prototípicamente del alcance principal. ng-repeat también copia la variable/elemento de bucle al nuevo ámbito hijo (y se aplican los matices que @Gloopy describe con las primitivas frente al objeto). ng-switch no copia nada desde el alcance principal.

Para ver cuál es el alcance interno/niño se parece, añadir lo siguiente después de la ng de conmutador cuando:

<a ng-click="showScope($event)">show scope</a> 

y añadir a su controlador:

$scope.showScope = function(e) { 
    console.log(angular.element(e.srcElement).scope()); 
} 

Update1: (tachado añadido a un mal consejo, [] se ha agregado para mayor claridad)

Para este escenario, donde AngularJS está creando ámbitos internos adicionales (impl) icitly), y realmente no quiere/necesita otro controlador, me gusta la solución de Gloopy. Un servicio (lo que originalmente sugerí a continuación) es [la forma incorrecta de hacerlo] probablemente excedido aquí. También me gusta que la solución de Gloopy no requiera el uso de 'esto' en los métodos del controlador.

respuesta original: (tachados añadido a un mal consejo, [ 's añadido para mayor claridad])

para ver donde se están creando ámbitos (si no se ha probado a hacer esto, es útil):

.ng-scope { margin: 4px; border: 1px dashed red } 

Para acceder a todoText fuera del switch de los casos (por lo tanto fuera de su alcance), básicamente estás preguntando acerca de la comunicación entre controladores, ya que múltiples campos de acción están involucrados. Tienes algunas opciones, pero un servicio es probablemente el mejor. Almacene los datos (que deben compartirse) dentro del servicio e inyecte ese servicio en cada controlador que necesite acceso a los datos.

Para su ejemplo específico, creo que debería conectar un controlador a cada switch-case e inyectar el servicio en él, para obtener acceso a los datos compartidos.

Véase también AngularJS: How can I pass variables between controllers?.

Las otras opciones:

Usando $ $ ámbito de los padres en el ámbito interno es [una forma de hacer esto - véase más arriba Update2] no es recomendable, ya continuación, un controlador sería hacer suposiciones acerca de cómo. los datos son presentados.

No se recomienda el uso de $ rootScope, excepto tal vez para aplicaciones simples y únicas. Es posible que los datos compartidos comiencen a cobrar vida propia, y $ rootScope no es el lugar adecuado para que eso suceda. Los servicios son más fáciles de reutilizar, agregar comportamiento, etc.

Usar $ scope. $ Emitir es otra opción, pero parece desordenada y un poco extraña: emitir eventos para compartir datos (en lugar de desencadenar el comportamiento).

[Uso de un objeto en el ámbito primario es probablemente el mejor - véase la respuesta de @ Gloopy.]

+0

Me gustaría aceptar esta respuesta también, pero lamentablemente no puedo. Elegí aceptar el otro simplemente porque en realidad presenta una solución. Pero tu información es oro puro, ¡muchas gracias! – Andreas

Cuestiones relacionadas