0

如果我在 AngularJS 中为博客构建索引页面,并带有如下评论:

<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字段做了一些奇怪的事情,但这开始让人感觉不习惯。

4

2 回答 2

2

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

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

至于其他输入,它确实取决于情况,但在这种情况下,inputandtextarea位于 an 内ngRepeat,这会创建新的范围。因此,分配给范围上的值不会影响页面上的其他元素。

<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>
于 2013-02-03T01:02:50.873 回答
1

is there any way of taking advantage of the two way communication there? (e.g. add an errmsg field from an AJAX call done in postComment or clear the form on submit?)

I suggest a directive with its own controller. With this approach, the comment model is encapsulated in the directive. The directive needs two pieces of information: 1) the postID 2) what function to call to save the comment. To support showing an error message returned from the server, a callback function is passed along with the comment. This allows the controller to feed the directive any error messages or any other information it might need after a save operation attempt.

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

Use as follows:

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

Note the somewhat odd syntax related to the '&' syntax: when the directive is used in the HTML, you specify arguments for the saveComment() function. In the directive/template, an object/map is used to associate each argument name with its value. The value is a local/directive scope property.

Plnkr. In the plnkr I simulated an AJAX post using a $timeout of 1.5 seconds. If you enter name in the name textbox and click the save button, you'll get an error in 1.5 seconds. Otherwise the form clears after 1.5 seconds.

Depending on how far you want to take this... you could encapsulate your post template into a directive too:

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

You could also put the comment-form inside the post directive template, simplifying the HTML even further:

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

You could also have a post-list directive, and its template would contain the ng-repeat, reducing the HTML to a single element:

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

I personally haven't decided how far one should go with custom directives yet. I would be very interested in any comments people have about this.

于 2013-02-03T04:55:59.053 回答