ng-repeat中的AngularJS ng-model $范围未定义

时间:2012-08-01 05:24:31

标签: angularjs

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

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

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

4 个答案:

答案 0 :(得分:45)

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

ng-repeat scopes

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

  1. @ Gloopy的回答:在父作用域上定义一个函数(子作用域可以访问它,因为ng-repeat子作用域原型继承自父作用域)并传递子作用域属性值(即postText& #39; s值)直到父母。
  2. posts数组中使用对象而不是基元。例如,
    $scope.posts = [ {type: 'tech'}, {type: 'news'}, ...];
    然后在你的ng-repeat循环中,使用
    <input type="text" ng-model="post.postText">
    因为每个数组项都是一个对象(而不是一个基元),所以每个子作用域都获得对数组posts中相应对象的引用,而不是(值的)副本。因此,post.postText在父$ scope属性posts上创建,因此它对父作用域可见。 (因此,在这种情况下,子范围只会调用savePost() - 不需要将任何值传递到父范围。)
    换句话说,如果用户键入&#34;这是技术相关的&#34;在第一个文本框中,父级中的posts数组将自动更新,如下所示:
    $scope.posts = [ {type: 'tech', postText: 'this is tech related'}, {type: 'news'}, ...];
    最后一点:在用户输入内容之前,postText属性不会添加到posts对象中。
  3. 使用ng-model="$parent.someProperty"将表单元素绑定到父作用域上的属性,而不是绑定到子作用域。这个解决方案很难为您的场景实现,而且它是一个相当脆弱的解决方案,因为它取决于范围继承的HTML结构......但我提到它是为了完整性。
  4. (@Renan在@ Gloopy的答案中提出了第四个解决方案。这是一个类似的解决方案1.但是有一个变体:使用this而不是传递一个值到我并不喜欢这种方法,因为它很难确定访问或修改哪个$ scope。我认为在$ scope上定义的函数只能访问和修改自己的$ scope更好。 )

    有关原型范围继承如何在Angular中工作的更多信息(以及更多图片),请参阅What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

答案 1 :(得分:25)

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

Here是一个更新的小提琴。

<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 :(得分:2)

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

项目控制器:

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

答案 3 :(得分:1)

将模型拆分为标题和值

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