Angular:异步推送到递归生成的数组

时间:2016-10-27 02:23:27

标签: javascript angularjs recursion

快速解释:这是一个简单的应用程序,旨在重新创建Reddit,因此每个帖子(我称之为"节点")的评论都包含一个评论数组(nodeList),并且每个注释可以在此列表中包含任意数量的节点。我想要做的是在当前的ng-repeat对象" nodeList"中添加一条注释,以便我可以添加注释而不刷新。

这个递归模板可以工作,但只有当我刷新页面时才会这样,所以它不会被推入ng-repeat的当前范围。我已经对$ index进行了一些研究,但由于它是递归生成的,因此无法知道嵌套数组树的深度。

我尝试的是$scope.x.nodeList = [],然后推送一个新的"节点"进入那个,想到" x"是ng-repeat中的新$ scope,但这不起作用。

控制器:

redditLite.controller('post', function($routeParams, $scope, $http) {
    var postId = $routeParams.id;
    var controller = this;
    var postComment = {};
    var node = {};
    $scope.show = true;
    $scope.addComment = {};
    $scope.post = {};
    $scope.x = {};
    $scope.x.nodeList = [];

controller.comment = function(parentId) {
    postComment.comment = $scope.addComment.body;
    postComment.parentId = parentId;
    postComment.rootPostId = $scope.post.id;

    $http.post('add-comment',postComment, config).then(function(response) {
        node = response.data;
        $scope.x.nodeList.push(node);
    });
  }
});

HTML:

<script type="text/ng-template" id="postTree">

    <div class="username">
        {{x.username}}
    </div>

    <div class="body">
        {{x.body}}
    </div>

    <div class="metrics">
        <ul>
            <li>
                Likes: {{x.likes}}
                <br>
                <button class="like-button" ng-click="controller.likeNode(x.nodeId); x.likes = x.likes + 1">Like</button>
            </li>
            <li>
                Comments: {{x.cmmnts}}
                <br>
                <button class="comment-button" ng-click="show = !show" ng-show="show">Comment!</button>

                <div class="comment-field" ng-hide="show">
                    <input type="text" placeholder="Enter a comment." ng-model="addComment.body">
                    <br>
                    <button ng-click="controller.comment(x.nodeId); show = !show">Submit</button>
                    <br>
                    <button ng-click="show = !show">Cancel</button>
                </div>
            </li>
            <li>
                Date: {{x.submit_date}}
            </li>
        </ul>
    </div>

    <div class="nodes">
        <ul ng-if="x.nodeList" ng-model="x.nodeList">
            <li ng-repeat="x in x.nodeList" ng-include="'postTree'"></li>
        </ul>
    </div>

</script>


<div class="post">

    <div class="username">
        {{post.username}}
    </div>

    <div class="body">
        {{post.body}}
    </div>

    <div class="metrics">
        <ul>
            <li>
                Likes: {{post.likes}}
                <br>
                <button class="like-button" ng-click="controller.like(post.id); post.likes = post.likes + 1">Like</button>
            </li>

            <li>
                Comments: {{post.cmmnts}}
                <br>
                <button class="comment-button" ng-click="show = !show" ng-show="show">Comment!</button>

                <div class="comment-field" ng-hide="show">
                    <input type="text" placeholder="Enter a comment." ng-model="addComment.body">
                    <br>
                    <button ng-click="controller.comment(post.id); show = !show">Submit</button>
                    <br>
                    <button ng-click="show = !show">Cancel</button>
                </div>

            </li>

            <li>
                Date: {{post.submit_date}}
            </li>

        </ul>
    </div>
</div>


<ul class="master-list">
    <li ng-repeat="x in post.nodeList" ng-include="'postTree'"></li>
</ul>

JSON format example

需要处理一些缺少的逻辑,但是现在我试图将对象推入数组,无论该数组在其他对象中的嵌套程度如何。

编辑:我已经将JSON结构的图像作为参考包含在内,可以看出每个节点对象都可以包含一个节点对象数组,所以这是我试图推送的数组新节点进入。

3 个答案:

答案 0 :(得分:2)

我已成功完成了几次这样的递归模板化操作。如果我记得,在相同的html标签上使用ng-repeat和ng-include是有问题的。尝试将div中的内容包装在div中,从li元素中删除ng-include 属性,然后在li元素中添加ng-include 元素。此外,您基本上已经添加了两次模板,一次用于根项目,然后再次添加递归行为。如果将post变量包装在标记中的数组中,则应该只能有一个模板(脚本一个)。

<script type="text/ng-template" id="postTree">
    <div>
        ...
        <div class="nodes">
            <ul ng-if="x.nodeList" ng-model="x.nodeList">
                <li ng-repeat="x in x.nodeList">
                    <ng-include src="'postTree'"></ng-include>
                </li>
            </ul>
        </div>
    </div>
</script>

<ul class="master-list">
    <li ng-repeat="x in [ post ]">
        <ng-include src="'postTree'"></ng-include>
    </li>
</ul>

<强>更新

单击评论时,将父级发送到函数而不是父级id。这样,您可以在$ http帖子完成后将孩子推到它的父母身上。

JS:

angular
.module('redditLite', [])
.controller('post', function($scope, $http) {
  var controller = this;
  $scope.show = true;
  $scope.post = {
    id: 1,
    parentId: null,
    username: 'jeff',
    body: 'my fantastic comment',
    likes: 152,
    submit_date: new Date(),
    nodeList: []
  };

  $scope.comment = function(parent) {
    var postComment = {
      id: 2,
      parentId: parent.id,
      username: 'jeff',
      body: parent.addComment,
      likes: 0,
      submit_date: new Date(),
      nodeList: []
    };
    console.log('adding comment', postComment, parent)
    $http.post('add-comment',postComment, config).then(function(response) {
        var node = response.data;
        parent.nodeList.push(node);
    });
  }
});

HTML

<script type="text/ng-template" id="postTree">
    <div>
        <div class="username">
            {{x.username}}
        </div>

        <div class="body">
            {{x.body}}
        </div>

        <div class="metrics">
            <ul>
                <li>
                    Likes: {{x.likes}}
                    <br>
                    <button class="like-button" ng-click="controller.likeNode(x.nodeId); x.likes = x.likes + 1">Like</button>
                </li>
                <li>
                    Comments: {{x.nodeList.length}}
                    <br>
                    <button class="comment-button" ng-click="show = !show" ng-show="show">Comment!</button>

                    <div class="comment-field" ng-hide="show">
                        <input type="text" placeholder="Enter a comment." ng-model="x.addComment">
                        <br>
                        <button ng-click="comment(x); show = !show">Submit</button>
                        <br>
                        <button ng-click="show = !show">Cancel</button>
                    </div>
                </li>
                <li>
                    Date: {{x.submit_date}}
                </li>
            </ul>
        </div>

        <div class="nodes">
            <ul ng-if="x.nodeList" ng-model="x.nodeList">
                <li ng-repeat="x in x.nodeList">
                    <ng-include src="'postTree'"></ng-include>
                </li>
            </ul>
        </div>
    </div>
</script>
<ul class="master-list">
  <li ng-init="x = post">
    <div ng-include="'postTree'"></div>
  </li>
</ul>

Plunker:

https://plnkr.co/edit/X40JoHduKYy12QPuLBCo?p=preview

答案 1 :(得分:0)

你可能会受到词汇范围的伤害。基本上是:

$http.post('add-comment',postComment, config).then(function(response) {
 node = response.data;
    $scope.x.nodeList.push(node); //this $scope is not actually your $scope
});

尝试做:

var vm = this;
$http.post('add-comment',postComment, config).then(function(response) {
 node = response.data;
    vm.$scope.x.nodeList.push(node); //should be the right scope.
})

如果这不起作用,请尝试仔细检查绑定。未正常更新的值意味着绑定不正确。

答案 2 :(得分:0)

尝试使用$scope.x.nodeList.concat([node]);而不是推送值,这样可以避免对象中的突变。