将新对象添加到集合

时间:2016-02-05 20:24:17

标签: javascript angularjs angularjs-directive

我有一个treeview指令归功于http://codepen.io/bachly/pen/KwWrzG作为我的起始块。当我向集合中添加对象时,我正在尝试更新。我可以更新对象并插入新对象,但是一旦$scoped项更新,就不会调用treeview指令。 最终,所使用的数据将来自服务,此时我只是使用模拟数据进行测试。

原始集合看起来像这样

$scope.myList = {
            children: [
              {
                  name: "Event",
                  children: [
                    {
                        name: "Event Date",
                        parent:"Event",
                        children: [
                          {
                              name: "2008",
                              filterType: '_eventStartDate',
                              parent: 'Event'
                          },
                          {
                              name: "2009",
                              filterType: '_eventStartDate',
                              parent: 'Event'
                          }
                        ]
                    },
                    {
                        name: "Event Attendee",
                        parent: "Event",
                        children: [
                          {
                              name: "Person 1",
                              filterType: '_eventAttenddeeName',
                              parent: 'Event Attendee'
                          },
                          {
                              name: "Person 2",
                              filterType: '_eventAttenddeeName',
                              parent: 'Event Attendee'
                          }
                        ]
                    }
                  ]
              }]
   };


   var TheOtherCollection = {
       children: [
         {
             name: "A New Event",
             children: [
               {
                   name: "The Other Date",
                   parent: " A New Event",
                   children: [
                     {
                         name: "2010",
                         FilterType: '_eventStartDate',
                         Parent: '_event'
                     },
                     {
                         name: "2011",
                         FilterType: '_eventStartDate',
                         Parent: '_event'
                     }
                   ]
               }
             ]
         }]
   };

使用以下指令和html

生成带有复选框的树视图
app.directive('tree', function () {
    return {
        restrict: 'E', 
        replace: true,
        scope: {
            t: '=src',
            filter: '&'
        },
        controller: 'treeController',
        template: '<ul><branch ng-repeat="c in t.children track by $index"  src="c" filter="doSomething(object, isSelected)"></branch></ul>'
    };
});

app.directive('branch', function($compile) {

    return {
        restrict: 'E', 
        replace: true, 
        scope: {
            b: '=src',
            filter: '&',
            checked: '=ngModel'
        },

            template: '<li><input type="checkbox" ng-click="innerCall()" ng-model="b.$$hashKey" ng-change="stateChanged(b.$$hashKey)" ng-hide="visible" /><a>{{ b.name }}</a></li>',
            link: function (scope, element, attrs) {

               var clicked = '';
               var hasChildren = angular.isArray(scope.b.children);
                scope.visible = hasChildren;
                if (hasChildren) {
                    element.append('<tree src="b"></tree>');
                    $compile(element.contents())(scope);
                }
                element.on('click', function(event) {
                    event.stopPropagation();
                    if (hasChildren) {
                        element.toggleClass('collapsed');
                    }
                });
                scope.stateChanged = function(b) {
                    clicked = b;
                };

                scope.innerCall = function() {
                    scope.filter({ object: scope.b, isSelected: clicked });
                };
            }
        };
    });

然后是html

  <div ng-controller="treeController">
        <tree src="myList" iobj="object" filter="doSomething(object, isSelected)"></tree>

        <a ng-click="clicked()"> link</a>
    </div>

单击复选框后,新集合将使用lodashjs

添加到现有集合中

ng-click事件

$scope.doSomething = function (object, isSelected) {
    if (isSelected) {
        var item = object;
        console.log(item);
        nestAssociation(object, $scope.myList, TheOtherCollection);
    }
}

创建新数组并将其添加到子数组

function nestAssociation(node, oldCollection, newAggregates) {
    // var item = fn(oldCollection, node.parent);
    var updatedArray = _.concat(oldCollection.children, newAggregates);
    console.log(updatedArray);
    if (updatedArray != null)
        updateMyList(updatedArray);
}

我可以在输出中看到我有一个新对象,但我无法更新树视图。我已经在指令中尝试在指令中的click事件上添加$ compile(元素),但由于数组没有构建,所以没有任何改变。

我是否需要在此指令中添加$ watch,如果是,还是有其他方法可以让指令重新呈现并显示新的嵌套集合吗?

更新

根据一些反馈和问题,这里有一个关于这个问题的更多细节。我所看到的问题不在指令中,只要围绕问题移动数据,一旦将数组添加到现有模型,我就无法重新渲染树视图。 以下链接is a working plunker显示项目当前的工作原理。 运行chrome dev工具我可以在输出中看到模型在选中复选框后更新 enter image description here

当我看到对象被更新时,指令永远不会更新以显示添加到对象的新数组。这是我需要帮助理解的部分。

提前致谢

2 个答案:

答案 0 :(得分:4)

您将函数传递给内部指令(这是最佳做法),但您可以访问scope.filter。不是doSomethingFunction。这个是undefined

filter="doSomething(object, isSelected)"
 =&GT;
filter="filter(object, isSelected)"

app.directive('tree', function () {
    return {
        restrict: 'E', 
        replace: true,
        scope: {
            t: '=src',
            filter: '&'
        },
        controller: 'treeController',
        template: '<ul>  
                    <branch ng-repeat="c in t.children track by $index"       
                   src="c" filter="filter(object, isSelected)">  
                    </branch>  
                  </ul>'
    };
});

下一步:

您永远无法访问angularJS中的$$个变量,因为它们是私有的。也许你应该从你的数据库中创建一个......但是$$hashkey似乎是一个简单的解决方案。

checked属性可能会抛出错误,因为树指令模板上不存在ngModel。 (之前至少放?

复选框不能包含$$ hashkey作为模型 Ng-change和ng-click将始终同时被调用,使用最简单的。

app.directive('branch', function($compile) {

    return {
        restrict: 'E', 
        replace: true, 
        scope: {
            b: '=src',
            filter: '&'
        },

            template: '<li><input type="checkbox" ng-click="innerCall(b.$$hashKey)" ng-model="isChecked" ng-hide="visible" /><a>{{ b.name }}</a></li>',
            link: function (scope, element, attrs) {

               scope.isChecked = false;
               var hasChildren = angular.isArray(scope.b.children);
                scope.visible = hasChildren;
                if (hasChildren) {
                    element.append('<tree src="b"></tree>');
                    $compile(element.contents())(scope);
                }
                element.on('click', function(event) {
                    event.stopPropagation();
                    if (hasChildren) {
                        element.toggleClass('collapsed');
                    }
                });

                scope.innerCall = function(hash) {
                    if(scope.isChecked){
                       scope.filter({ object: scope.b, isSelected: hash });
                    }

                };
            }
        };
    });

更新

treeController指令和tree视图中的index.html相同。 这是导致视图不更新的原因!

我删除了指令中的那个,否则你将为每个孩子配备一个控制器  您在控制器中看到了良好的console.log消息,但它在ONE指令的控制器中 您没有访问index.html的控制器。

然后我修复了孩子之间的filter函数通信:

添加新tree时,您忘记传达过滤功能:

element.append('<tree src="b" filter="filter({ object: object, isSelected: isSelected })"></tree>');

此外,在您的父指令模板中,您还需要哈希来向函数发送参数:
filter="filter({ object: object, isSelected: isSelected })"

我编辑了您的Plunker HERE,但没有根据我上面的评论更改代码 (我不确定你写的是不是你想要的,因为你没有评论我宁愿不改变它,所以你仍然快速地执行你的代码)
但是现在看来正在更新! 我认为根据你的需要进行一些调试,上面的评论应该足够了。

编辑2
您忘记返回属性为chrilden的对象。您返回了一个导致该问题的数组。

function updateMyList(data) {
      var transformed = { children : data };
        $scope.myList = transformed;
    }

这是一个有效的PLUNKER

答案 1 :(得分:0)

添加

后尝试$ scope。$ apply()