【问题标题】:AngularJS ng-model $scope in ng-repeat is undefinedng-repeat 中的 AngularJS ng-model $scope 未定义
【发布时间】:2012-08-01 05:24:31
【问题描述】:

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

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

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

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    正如@Gloopy 所述,ng-repeat 为posts 数组中的每个项目创建一个新的子范围。由于posts 数组中的每一项都是一个原语(一个字符串),ng-repeat 还在每个子作用域上创建一个post 属性,并从数组中为它们中的每一个分配适当的值。 ng-repeat 块内部是ng-model="postText"。这会在每个子作用域上创建一个 postText 属性。这是所有的样子(对于 4 个子作用域中的 2 个):

    当用户在其中一个输入文本框中键入一些文本时,相应的灰色框将存储该文本。 (例如,第二个(从顶部开始)灰色框会将用户键入的文本存储到“技术”文本框中。)父范围无法看到子范围中的 postText 属性 - 这是您遇到的问题。常见的解决方法有以下三种:

    1. @Gloopy 的回答:在父作用域上定义一个函数(子作用域可以访问,因为 ng-repeat 子作用域原型从父作用域继承)并将子作用域属性值(即 postText 的值)传递到父母。
    2. 在posts 数组中使用对象而不是原语。例如,
      $scope.posts = [ {type: 'tech'}, {type: 'news'}, ...];
      然后在你的 ng-repeat 循环中,使用
      <input type="text" ng-model="post.postText">
      因为每个数组项都是一个对象(而不是原始对象),所以每个子作用域都获得对数组posts 中适当对象的引用,而不是(值的)副本。因此,post.postText 在父 $scope 属性 posts 上创建,因此它对父范围可见。 (因此,在这种情况下,子范围将简单地调用 savePost() - 无需将任何值传递给父范围。)
      换句话说,如果用户在第一个文本框中键入“这是技术相关的”,则父级中的 posts 数组将自动更新如下:
      $scope.posts = [ {type: 'tech', postText: 'this is tech related'}, {type: 'news'}, ...];
      最后一点:postText在用户输入内容之前,不会将属性添加到帖子对象中。
    3. 使用ng-model="$parent.someProperty" 将表单元素绑定到父作用域上的属性,而不是子作用域上的属性。对于您的方案,该解决方案很难实施,而且它是一个相当脆弱的解决方案,因为它依赖于 HTML 结构来进行范围继承......但我提到它是为了完整性。

    (@Renan 在 cmets 中在 @Gloopy 的回答中提出了第四个解决方案。这与解决方案 1 类似,但有一个变化:使用 this 而不是将值传递给父级。我是不喜欢这种方法,因为它很难确定正在访问或修改哪个 $scope。我认为在 $scope 上定义的函数最好只访问和修改自己的 $scope。)

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

    【讨论】:

    • 我没有看到如何在 2 中调用 savePost() 而不传递任何内容。在不传递子对象或索引的情况下如何引用特定的子范围?
    • @Dean,说得好。您可以遍历posts 并确定更改了哪些(例如,如果您只想要一个“保存”按钮)。或者,如果您希望每个帖子都有一个“保存帖子”链接,您可以将 post.type 作为参数传递。
    • 如果您绘制关于 ParentScope 无法看到输入框中的文本的部分,图表可能会更好。画一条红线或其他方式表明在框中输入的内容对父级不可见。
    • @MarkRajcok 我有类似的情况,我在一组对象(发票)上使用 ng-repeat。每个重复发票都有一个输入字段,用于填充父发票内的另一个子对象数组(发票行)。添加发票行后,我还需要清除文本框。我现在要做的是,除了发票中的发票行数组之外,我在发票中还有一个临时发票输入属性,我使用 ng-model='invoice.invoice-input' 绑定它。然后在将 invoice-line 添加到 invoice.invoice-lines 数组后清除它。这是针对这种情况的正确方法吗?
    • @Tru,您应该创建一个新的 Stack Overflow 问题/帖子并展示您当前的设计/代码。然后多人可以评论它并提供建议。
    【解决方案2】:

    在您的点击表达式中,您可以引用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);
    }
    

    【讨论】:

    • 感谢 Renan 帮了大忙。我通过传入 2 个像这样的对象来让它工作 'save post'。但是使用简单的“this”会更好!
    • 可行,但如何通过脚本设置值?我正在寻找类似 $scope.postText = "abv"
    • 如果我理解您的问题,一种方法是使用 ng-init 设置 postText 的初始值,如 this example 中一样。我更愿意更改绑定的数据类型以包含 this example 中的帖子文本。
    【解决方案3】:

    这可能是一个迟到的答案。请参考这个小提琴。 http://jsfiddle.net/X5gd2/ 请参考萤火虫的控制台,当你在文本框中输入一些文本后点击链接。这个想法是为在 ng-repeat 中重复的每个视图都有一个 itemcontroller。

    项目控制器:

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

    【讨论】:

      【解决方案4】:

      将模型拆分为标题和值

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

      【讨论】:

        猜你喜欢
        • 2014-10-11
        • 1970-01-01
        • 2017-11-19
        • 2015-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-02
        • 1970-01-01
        相关资源
        最近更新 更多