ng-repeat中的AngularJS ng-model $ scope未定义

时间:2022-12-03 14:28:36

I apologize in advance if i'm not wording this properly. I have a textbox with ng-model inside an ng-repeat and when I try to get the textbox value it's always undefined. I just want it to display whatever I type in the corresponding textbox.

如果我没有正确措辞,我会提前道歉。我在ng-repeat中有一个带有ng-model的文本框,当我尝试获取文本框值时,它总是未定义的。我只是希望它显示我在相应文本框中输入的内容。

It seems to be an issue with the $scope, so how would I make the $scope.postText global or at the controller root level so it can be accessible?

这似乎是$ scope的一个问题,那么我如何将$ scope.postText设置为全局或控制器根级别以便它可以访问?

Here's the JSFiddle to help clear things up: http://jsfiddle.net/stevenng/9mx9B/14/

这是帮助澄清问题的JSFiddle:http://jsfiddle.net/stevenng/9mx9B/14/

4 个解决方案

#1


25  

In your click expression you can reference the postText and access it in your savePost function. If this wasn't in an ng-repeat you could access the single $scope.postText successfully but ng-repeat creates a new scope for each item.

在您的单击表达式中,您可以引用postText并在savePost函数中访问它。如果这不是ng-repeat,您可以成功访问单个$ scope.postText,但ng-repeat会为每个项目创建一个新范围。

Here is an updated fiddle.

这是一个更新的小提琴。

<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);
}

#2


45  

As @Gloopy already stated, ng-repeat creates a new child scope for each item in your posts array. Since each item of the posts array is a primitive (a string), ng-repeat also creates a post property on each child scope, and assigns each of them the appropriate value from the array. Inside the ng-repeat block is ng-model="postText". This creates a postText property on each of the child scopes. Here is what that all looks like (for 2 of the 4 child scopes):

正如@Gloopy已经说过的那样,ng-repeat为posts数组中的每个项创建一个新的子范围。由于posts数组的每个项都是一个原语(一个字符串),因此ng-repeat还会在每个子作用域上创建一个post属性,并为每个子作用域分配适当的值。 ng-repeat块内部是ng-model =“postText”。这会在每个子作用域上创建一个postText属性。以下是所有内容(4个子范围中的2个):

ng-repeat中的AngularJS ng-model $ scope未定义

When a user types some text into one of the input textboxes, the appropriate gray box will store the text. (E.g., the 2nd (from the top) gray box will store text a user types into the "tech" textbox.) The parent scope cannot see the postText properties in the child scope -- this is the problem you had. There are three common solutions:

当用户在一个输入文本框中键入一些文本时,相应的灰色框将存储文本。 (例如,第二个(从顶部)灰色框将用户键入的文本存储到“tech”文本框中。)父作用域无法在子作用域中看到postText属性 - 这就是您遇到的问题。有三种常见的解决方案:

  1. @Gloopy's answer: define a function on the parent scope (which the child scopes can access, because ng-repeat child scopes prototypically inherit from the parent scope) and pass the child scope property value (i.e., postText's value) up to the parent.
  2. @ Gloopy的答案:在父作用域上定义一个函数(子作用域可以访问它,因为ng-repeat子作用域原型继承自父作用域)并将子作用域属性值(即postText的值)传递给父作用域。
  3. Use objects instead of primitives in your posts array. E.g.,
    $scope.posts = [ {type: 'tech'}, {type: 'news'}, ...];
    Then in your ng-repeat loop, use
    <input type="text" ng-model="post.postText">
    Because each array item is an object (and not a primitive), each child scope gets a reference to the appropriate object in array posts, rather than a copy (of a value). Therefore, post.postText gets created on parent $scope property posts, and hence it is visible to the parent scope. (So, in this case the child scopes would simply call savePost() -- there would be no need to pass any values up to the parent scope.)
    In other words, if a user typed "this is tech related" into the first text box, the posts array in the parent would be automatically updated as follows:
    $scope.posts = [ {type: 'tech', postText: 'this is tech related'}, {type: 'news'}, ...];
    One last note: the postText property is not added to the posts object until the user types something.
  4. 在posts数组中使用对象而不是基元。例如,$ scope.posts = [{type:'tech'},{type:'news'},...];然后在ng-repeat循环中,使用因为每个数组项都是一个对象(而不是一个基元),每个子作用域都会获得对相应对象的引用在数组帖子中,而不是副本(值)。因此,post.postText在父$ scope属性帖子上创建,因此它对父作用域可见。 (因此,在这种情况下,子范围将简单地调用savePost() - 不需要将任何值传递到父范围。)换句话说,如果用户在第一个中输入“this is tech related”文本框中,父级中的posts数组将自动更新如下:$ scope.posts = [{type:'tech',postText:'this is tech related'},{type:'news'},... ]。最后一点:在用户输入内容之前,postText属性不会添加到posts对象。
  5. Use ng-model="$parent.someProperty" to bind the form element to a property on the parent scope, rather than on the child scope. This solution would be difficult to implement for your scenario, and it is a rather fragile solution, as it depends on the HTML structure for scope inheritance... but I mention it for completeness.
  6. 使用ng-model =“$ parent.someProperty”将表单元素绑定到父作用域上的属性,而不是绑定到子作用域。这个解决方案很难为你的场景实现,而且它是一个相当脆弱的解决方案,因为它依赖于范围继承的HTML结构......但我提到它是为了完整性。

(A fourth solution was presented by @Renan in comments on @Gloopy's answer. This is a like solution 1., but with a variation: this is used instead of passing a value up to the parent. I'm not a fan of this approach as it makes it difficult to determine which $scope is being accessed or modified. I think it is better that functions defined on $scope only access and modify their own $scope.)

(@Renan在评论@ Gloopy的答案时提出了第四个解决方案。这是一个类似的解决方案1.但是有一个变化:这是用来代替将值传递给父级。我不是这个的粉丝方法,因为它很难确定访问或修改哪个$ scope。我认为在$ scope上定义的函数最好只访问和修改它们自己的$ scope。)

For more information (and lots more pictures) about how prototypal scope inheritance works in Angular, see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

有关原型范围继承如何在Angular中工作的更多信息(以及更多图片),请参阅AngularJS中范围原型/原型继承的细微差别是什么?

#3


2  

This may be a late answer. Please refer this fiddle. http://jsfiddle.net/X5gd2/ Please refer to the firebug's console, when u click on the links after typing some texts in the text box. The idea is to have a itemcontroller for each of the view that is repeated inside the ng-repeat.

这可能是一个迟到的答案。请参考这个小提琴。 http://jsfiddle.net/X5gd2/当您在文本框中键入一些文本后单击链接时,请参阅firebug的控制台。我们的想法是为每个在ng-repeat内重复的视图设置一个itemcontroller。

The item controller:

物品控制器:

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

#4


1  

Split the model up into heading and value

将模型拆分为标题和值

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 below..

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..

看看这个小提琴..

#1


25  

In your click expression you can reference the postText and access it in your savePost function. If this wasn't in an ng-repeat you could access the single $scope.postText successfully but ng-repeat creates a new scope for each item.

在您的单击表达式中,您可以引用postText并在savePost函数中访问它。如果这不是ng-repeat,您可以成功访问单个$ scope.postText,但ng-repeat会为每个项目创建一个新范围。

Here is an updated fiddle.

这是一个更新的小提琴。

<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);
}

#2


45  

As @Gloopy already stated, ng-repeat creates a new child scope for each item in your posts array. Since each item of the posts array is a primitive (a string), ng-repeat also creates a post property on each child scope, and assigns each of them the appropriate value from the array. Inside the ng-repeat block is ng-model="postText". This creates a postText property on each of the child scopes. Here is what that all looks like (for 2 of the 4 child scopes):

正如@Gloopy已经说过的那样,ng-repeat为posts数组中的每个项创建一个新的子范围。由于posts数组的每个项都是一个原语(一个字符串),因此ng-repeat还会在每个子作用域上创建一个post属性,并为每个子作用域分配适当的值。 ng-repeat块内部是ng-model =“postText”。这会在每个子作用域上创建一个postText属性。以下是所有内容(4个子范围中的2个):

ng-repeat中的AngularJS ng-model $ scope未定义

When a user types some text into one of the input textboxes, the appropriate gray box will store the text. (E.g., the 2nd (from the top) gray box will store text a user types into the "tech" textbox.) The parent scope cannot see the postText properties in the child scope -- this is the problem you had. There are three common solutions:

当用户在一个输入文本框中键入一些文本时,相应的灰色框将存储文本。 (例如,第二个(从顶部)灰色框将用户键入的文本存储到“tech”文本框中。)父作用域无法在子作用域中看到postText属性 - 这就是您遇到的问题。有三种常见的解决方案:

  1. @Gloopy's answer: define a function on the parent scope (which the child scopes can access, because ng-repeat child scopes prototypically inherit from the parent scope) and pass the child scope property value (i.e., postText's value) up to the parent.
  2. @ Gloopy的答案:在父作用域上定义一个函数(子作用域可以访问它,因为ng-repeat子作用域原型继承自父作用域)并将子作用域属性值(即postText的值)传递给父作用域。
  3. Use objects instead of primitives in your posts array. E.g.,
    $scope.posts = [ {type: 'tech'}, {type: 'news'}, ...];
    Then in your ng-repeat loop, use
    <input type="text" ng-model="post.postText">
    Because each array item is an object (and not a primitive), each child scope gets a reference to the appropriate object in array posts, rather than a copy (of a value). Therefore, post.postText gets created on parent $scope property posts, and hence it is visible to the parent scope. (So, in this case the child scopes would simply call savePost() -- there would be no need to pass any values up to the parent scope.)
    In other words, if a user typed "this is tech related" into the first text box, the posts array in the parent would be automatically updated as follows:
    $scope.posts = [ {type: 'tech', postText: 'this is tech related'}, {type: 'news'}, ...];
    One last note: the postText property is not added to the posts object until the user types something.
  4. 在posts数组中使用对象而不是基元。例如,$ scope.posts = [{type:'tech'},{type:'news'},...];然后在ng-repeat循环中,使用因为每个数组项都是一个对象(而不是一个基元),每个子作用域都会获得对相应对象的引用在数组帖子中,而不是副本(值)。因此,post.postText在父$ scope属性帖子上创建,因此它对父作用域可见。 (因此,在这种情况下,子范围将简单地调用savePost() - 不需要将任何值传递到父范围。)换句话说,如果用户在第一个中输入“this is tech related”文本框中,父级中的posts数组将自动更新如下:$ scope.posts = [{type:'tech',postText:'this is tech related'},{type:'news'},... ]。最后一点:在用户输入内容之前,postText属性不会添加到posts对象。
  5. Use ng-model="$parent.someProperty" to bind the form element to a property on the parent scope, rather than on the child scope. This solution would be difficult to implement for your scenario, and it is a rather fragile solution, as it depends on the HTML structure for scope inheritance... but I mention it for completeness.
  6. 使用ng-model =“$ parent.someProperty”将表单元素绑定到父作用域上的属性,而不是绑定到子作用域。这个解决方案很难为你的场景实现,而且它是一个相当脆弱的解决方案,因为它依赖于范围继承的HTML结构......但我提到它是为了完整性。

(A fourth solution was presented by @Renan in comments on @Gloopy's answer. This is a like solution 1., but with a variation: this is used instead of passing a value up to the parent. I'm not a fan of this approach as it makes it difficult to determine which $scope is being accessed or modified. I think it is better that functions defined on $scope only access and modify their own $scope.)

(@Renan在评论@ Gloopy的答案时提出了第四个解决方案。这是一个类似的解决方案1.但是有一个变化:这是用来代替将值传递给父级。我不是这个的粉丝方法,因为它很难确定访问或修改哪个$ scope。我认为在$ scope上定义的函数最好只访问和修改它们自己的$ scope。)

For more information (and lots more pictures) about how prototypal scope inheritance works in Angular, see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

有关原型范围继承如何在Angular中工作的更多信息(以及更多图片),请参阅AngularJS中范围原型/原型继承的细微差别是什么?

#3


2  

This may be a late answer. Please refer this fiddle. http://jsfiddle.net/X5gd2/ Please refer to the firebug's console, when u click on the links after typing some texts in the text box. The idea is to have a itemcontroller for each of the view that is repeated inside the ng-repeat.

这可能是一个迟到的答案。请参考这个小提琴。 http://jsfiddle.net/X5gd2/当您在文本框中键入一些文本后单击链接时,请参阅firebug的控制台。我们的想法是为每个在ng-repeat内重复的视图设置一个itemcontroller。

The item controller:

物品控制器:

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

#4


1  

Split the model up into heading and value

将模型拆分为标题和值

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 below..

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..

看看这个小提琴..