【问题标题】:idiomatic way of having models and looped forms in angularjs在angularjs中拥有模型和循环形式的惯用方式
【发布时间】:2013-02-03 01:00:53
【问题描述】:

如果我在 AngularJS 中使用这样的 cmets 为博客构建索引页面:

<li ng-repeat="post in posts">
    <h2>{{post.title}}
    <p>{{post.description}}</p>
    <h3>Leave a comment</h3>
    <form ng-submit="postComment()">
       <input type="hidden" value="{{post.id}}">
       Name: <input type="text"> <br>
       Comment: <textarea></textarea> <br>
       <input type="submit" value="Post comment">
    </form>
</li>

我无法弄清楚将模型与表单相关联以从控制器的postComment() 函数访问的正确方法。如果您对所有表单只使用一个模型,那么开始对一个帖子发表评论将开始对所有表单发表评论 - 除非您使用隐藏的 post.id 字段做一些奇怪的事情,但这开始感觉单调的。

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    您可以将对象传递给函数调用。

    <form ng-submit="postComment(post.id)">
    

    至于其他输入,它确实取决于具体情况,但在这种情况下,inputtextareangRepeat 内,这会创建新的范围。因此,在作用域上赋值不会影响页面上的其他元素。

    <li ng-repeat="post in posts">
        <h2>{{post.title}}
        <p>{{post.description}}</p>
        <h3>Leave a comment</h3>
        <form ng-submit="postComment(post.id, commentName, commentText)">
           Name: <input type="text" ng-model="commentName"> <br>
           Comment: <textarea ng-model="commentText"></textarea> <br>
           <input type="submit" value="Post comment">
        </form>
    </li>
    

    【讨论】:

    • 这摆脱了必须使用隐藏的post.id,但我仍然不确定该表格中inputs 的ng-model 部分应该是什么。跨度>
    • 标记为已接受,因为它回答了我的问题,但是有没有办法利用那里的双向通信? (例如,在 postComment 中完成的 AJAX 调用中添加 errmsg 字段或清除提交时的表单?)
    • 如果是我,我不会将原语附加到范围,而是创建一个客户端模型层(通过服务),对帖子的域“问题”进行建模并为特定帖子发布 cmets,并将该模型中的值附加到范围。说得通? (我在this answer 中提到了这一点)
    • 或者,创建一个指令(类似于postComment)来封装必要的逻辑,并在必要时利用服务。
    • 或者(再次),另一个想法是拥有另一个控制器,例如PostsCommentsController,传递一个帖子或帖子 ID 并将逻辑封装在其中。然后每个帖子都有一个PostsCommentController。 (回想起来,如果我在做实验,我可能会从这里开始)
    【解决方案2】:

    有没有办法利用那里的双向通信? (例如,从 postComment 中完成的 AJAX 调用中添加 errmsg 字段或在提交时清除表单?)

    我建议一个带有自己控制器的指令。通过这种方法,comment 模型被封装在指令中。该指令需要两条信息:1)postID 2)调用什么函数来保存评论。为了支持显示从服务器返回的错误消息,回调函数与注释一起传递。这允许控制器在尝试保存操作后向指令提供任何错误消息或它可能需要的任何其他信息。

    app.directive('commentForm', function() {
      var template = '<form name="commentForm" '
        + 'ng-submit="save({comment: comment, callbackFn: callbackFn})">'
        + '<h3>Leave a comment</h3>'
        + 'Name: <input type="text" ng-model="comment.name" name="commentName"> <br>'
        + '<span class="error" ng-show="commentForm.commentName.$error.myError">Error</span><br>'
        + 'Comment: <textarea ng-model="comment.text"></textarea> <br>'
        + '<input type="submit" value="Save comment">'
        + '</form>';
      return {
        restrict: 'E',
        template: template,
        scope: { postId: '@', save: '&' },
        controller: function($scope) {
          $scope.callbackFn = function(args) {
            console.log('callback', args);
            if(args.error.name) {
              $scope.commentForm.commentName.$setValidity("myError", false);
            } else {
              // clear form
              $scope.comment.name = '';
              $scope.comment.text = '';
            }
          };
        }
      };
    });
    
    
    app.controller('MainCtrl', function($scope, $timeout) {
      $scope.post = {id: 1};
      $scope.saveComment = function(comment, callbackFn) {
        console.log('saving...', comment);
        // Call $http here... then call the callback.
        // We'll simulate doing something with a timeout.
        $timeout(function() {
          if(comment.name === "name") {
            callbackFn( {error: {name: 'try again'}} );
          } else {
            callbackFn( {error: {}} );
          }
       }, 1500)
      }
    });
    

    如下使用:

    <comment-form post-id="{{post.id}}" save="saveComment(comment, callbackFn)"></comment-form>
    

    请注意与“&”语法相关的有些奇怪的语法:当在 HTML 中使用该指令时,您需要为 saveComment() 函数指定参数。在指令/模板中,对象/映射用于将每个参数名称与其值相关联。该值是本地/指令范围属性。

    Plnkr。在 plnkr 中,我使用 1.5 秒的 $timeout 模拟了一个 AJAX 帖子。如果您在名称文本框中输入name 并单击保存按钮,您将在 1.5 秒内收到错误消息。否则,表单会在 1.5 秒后清除。

    取决于你想走多远......你也可以将你的帖子模板封装到一个指令中:

    <li ng-repeat="post in posts">
       <post=post></post>
       <comment-form ...></comment-form>
    </li>
    

    您还可以将评论表单放在 post 指令模板中,进一步简化 HTML:

    <li ng-repeat="post in posts">
       <post=post></post>
    </li>
    

    你也可以有一个 post-list 指令,它的模板将包含 ng-repeat,将 HTML 简化为单个元素:

    <post-list posts=posts></post-list>
    

    我个人还没有决定自定义指令应该走多远。我会对人们对此的任何 cmets 非常感兴趣。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-08
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-13
      相关资源
      最近更新 更多