2012-08-01 12 views
19

Pido disculpas por adelantado si no estoy redactando esto correctamente. Tengo un cuadro de texto con ng-model dentro de un ng-repeat y cuando trato de obtener el valor del cuadro de texto siempre es undefined. Solo quiero que muestre lo que escribo en el cuadro de texto correspondiente.

Parece ser un problema con el $scope, entonces, ¿cómo podría hacer que el $scope.postText sea global o en el nivel raíz del controlador para que pueda ser accesible?

Aquí está la jsFiddle para ayudar a aclarar las cosas: http://jsfiddle.net/stevenng/9mx9B/14/

Respuesta

25

En el clic de expresión puede hacer referencia al postText y acceder a ella en su función savePost. Si no estaba en una repetición ng, puede acceder al único $scope.postText con éxito, pero ng-repeat crea un nuevo alcance para cada elemento.

Here es un violín actualizado.

<div ng-repeat="post in posts"> 
    <strong>{{post}}</strong> 
    <input type="text" ng-model="postText"> 
    <a href="#" ng-click="savePost(postText)">save post</a> 
</div> 

$scope.savePost = function(post){ 
    alert('post stuff in textbox: ' + post); 
} 
+0

¿Cómo conseguir este violín para trabajar? http://jsfiddle.net/stevenng/VnQqH/5/ – Steve

+9

http://jsfiddle.net/VnQqH/6/ use 'this' para referirse al alcance actual real –

+0

Gracias Renan que ayuda mucho. Lo obtuve funcionando pasando 2 objetos como este 'save post'. ¡Pero usar un simple 'esto' es mucho mejor! – Steve

45

Como ya se ha dicho @Gloopy, ng-repetición crea un nuevo ámbito secundario para cada elemento de la matriz posts. Como cada elemento de la matriz posts es una primitiva (una cadena), ng-repeat también crea una propiedad post en cada ámbito secundario y les asigna a cada uno el valor apropiado de la matriz. Dentro del bloque ng-repeat está ng-model="postText". Esto crea una propiedad postText en cada uno de los ámbitos secundarios. Esto es lo que todo parece (para 2 de los 4 ámbitos secundarios):

ng-repeat scopes

Cuando un usuario escribe un texto en uno de los cuadros de texto de entrada, la caja gris apropiado almacenar el texto. (Por ejemplo, el segundo recuadro gris (desde arriba) almacenará el texto que un usuario escribe en el cuadro de texto "tecnológico".) El ámbito principal no puede ver las propiedades de postTexto en el ámbito secundario: este es el problema que tenía. Hay tres soluciones comunes:

  1. @ respuesta de Gloopy: definir una función en el ámbito primario (que los ámbitos secundarios pueden acceder, porque NG-repetición niño alcances prototípica heredan del alcance de los padres) y pasa la propiedad ámbito secundario valor (es decir, el valor de postText) hasta el padre.
  2. Usa objetos en lugar de primitivos en tu matriz posts. Por ejemplo,
    $scope.posts = [ {type: 'tech'}, {type: 'news'}, ...];
    Luego, en su bucle ng-repetición, utilice
    <input type="text" ng-model="post.postText">
    Debido a que cada elemento de la matriz es un objeto (y no una primitiva), cada ámbito secundario obtiene una referencia al objeto apropiado en array posts, en lugar de una copia (de un valor). Por lo tanto, post.postText se crea en la propiedad padre $ scope posts y, por lo tanto, es visible para el ámbito primario. (Entonces, en este caso, los ámbitos secundarios simplemente llamarían al savePost(); no habría necesidad de pasar ningún valor hasta el alcance principal).
    En otras palabras, si un usuario tipeó "esto está relacionado con la tecnología" en el primer cuadro de texto, la matriz posts en el elemento primario se actualizará automáticamente de la siguiente manera:

    Una última nota: la propiedad postTexto no se agrega al objeto de mensajes hasta que el usuario escriba algo.
  3. Utilice ng-model="$parent.someProperty" para vincular el elemento de formulario a una propiedad en el ámbito principal, en lugar de hacerlo en el ámbito secundario.Esta solución sería difícil de implementar para su escenario, y es una solución bastante frágil, ya que depende de la estructura HTML para la herencia del alcance ... pero lo menciono para que esté completo. .

(Una cuarta solución fue presentada por @Renan en los comentarios sobre la respuesta de @ Gloopy Esta es una solución como 1., pero con una variante: this se utiliza en lugar de pasar un valor depende de los padres I'. No soy partidario de este enfoque, ya que dificulta determinar qué $ scope se accede o modifica. Creo que es mejor que las funciones definidas en $ scope solo accedan y modifiquen su propio $ scope.)

Para obtener más información información (y muchas más imágenes) sobre cómo funciona la herencia del alcance prototípico en Angular, vea What are the nuances of scope prototypal/prototypical inheritance in AngularJS?

+0

No veo cómo en 2 puedes llamar a savePost() sin pasar nada. ¿Cómo se referiría a un alcance hijo específico sin pasar el objeto o índice hijo? –

+0

@Dean, buen punto. Podría recorrer las "publicaciones" y determinar cuál (es) cambió (por ejemplo, si solo deseaba un botón "guardar"). O puede pasar 'post.type' como argumento, si quiere un enlace" guardar publicación "para cada publicación. –

+0

El diagrama podría ser aún mejor si representó un diagrama de la parte sobre el ParentScope que no puede ver el texto escrito en los cuadros. Dibuje una línea roja o alguna otra forma para mostrar que las cosas ingresadas en el cuadro no son visibles para el Padre. –

2

Esto puede ser una respuesta tardía. Por favor refiérase a este violín. http://jsfiddle.net/X5gd2/ Consulte la consola de Firebug, cuando hace clic en los enlaces después de escribir algunos textos en el cuadro de texto. La idea es tener un controlador de elementos para cada vista que se repita dentro de ng-repeat.

El controlador artículo:

function postItemController($scope){ 
    $scope.savePost = function(){ 
     console.log($scope.postText + " which belongs to " + $scope.post +" will be saved") 
    } 
} 
1

Dividir el modelo arriba en el rumbo y valor por debajo

angular.module('MyApp',[]); 

function PostCtrl($scope) { 
    $scope.posts = [{heading:'tech',value:''}, {heading:'news',value:''},  {heading:'sports',value:''},{heading:'health',value:''}]; 

    $scope.savePost = function(post){ 
     alert('post stuff in textbox: ' + post); 
    } 
} 

HTML ..

<div ng-app="MyApp"> 
    <div ng-controller="PostCtrl"> 
     <div ng-repeat="post in posts"> 
      <strong>{{post.heading}}</strong> 
      <input type="text" ng-model="post.value"> 
      <a href="#" ng-click="savePost(post.value)">save post</a> 
     </div> 
    </div> 
</div> 

Check out this Fiddle..