【问题标题】:Provide different views automatically to data自动为数据提供不同的视图
【发布时间】:2015-05-20 14:18:03
【问题描述】:

使用 AngularJS,假设数组 $scope.data.children 具有以下结构的项:

{
 "sku" : "<sku>",
 "selected" : <boolean>,
 "children" : []
}

是否有一种简单的方法可以引用所有 selected = true 子级,最好以 $scope.data.components 表示?

例如,如果

[
    {"sku" : "A","selected" : true, "children":[
      {"sku" : "A1","selected" : true, "children":[]},
      {"sku" : "A2","selected" : false, "children":[]}
    ]},
    {"sku" : "B","selected" : false, "children":[
      {"sku" : "B1","selected" : false, "children":[]},
      {"sku" : "B2","selected" : false, "children":[]}
    ]},
    {"sku" : "C","selected" : true, "children":[
      {"sku" : "C1","selected" : true, "children":[]},
      {"sku" : "C2","selected" : false, "children":[]}
    ]},
    {"sku" : "D","selected" : false, "children":[
      {"sku" : "D1","selected" : false, "children":[]},
      {"sku" : "D2","selected" : false, "children":[]}
    ]}
]

然后

$scope.data.components = [
    {"sku" : "A","selected" : true, "children":[
      {"sku" : "A1","selected" : true, "children":[]},
    },
    {"sku" : "C","selected" : true, "children":[
      {"sku" : "C1","selected" : true, "children":[]}
    }
]

如果$scope.data.children 更新为[{"sku" : "D","selected" : true}]

然后$scope.data.components =

[
    {"sku" : "A","selected" : true, "children":[
      {"sku" : "A1","selected" : true, "children":[]},
    },
    {"sku" : "C","selected" : true, "children":[
      {"sku" : "C1","selected" : true, "children":[]}
    },
    {"sku" : "D","selected" : true, "children":[
      {"sku" : "D2","selected" : true, "children":[]}
    }
]

总结一下需求:

  1. 实时视图 - 对 $scope.data.children$scope.data.components 的更改应立即反映在两者上。
  2. children 元素的任何深度都应检查selected == true
  3. 一旦检测到错误,就不应检查子子项。
  4. (可选,但如果可能的话最好)任何对component 的引用将只显示childrenselected == true。因此,如果在node 处可以使用对"sku":"A" 对象的引用,那么node.components 将返回node.children 其中"sku":"A" 的孩子的select == true

【问题讨论】:

    标签: javascript angularjs data-binding


    【解决方案1】:

    使用您给定的示例 json,我尝试了一种使用 forEach in angularjs 的实现

    我只是循环了children array and constructed the component array when needed

    angular.forEach($scope.children, function(child) {
     var grandChildValue = 0; //value to check for component node already exist
    
      angular.forEach(child.children, function(grandChild) {
       if(grandChild.selected) {
    
          if(grandChildValue != 0) {
             // if node already exist means it will be added to children from here
    
            angular.forEach($scope.components, function(comp){
              if(comp.sku == child.sku) {
                comp.children.push(grandChild);
              }
            });
            return;
          }
        //if node doesn't exist, it will create the node in component array & children inserted
        grandChildValue++;
        $scope.components.push({
          "sku" : child.sku,
          "selected": child.selected,
          "children":[grandChild]
        });
      }
     });
    });
    

    这是您的代码的工作插件,

    http://embed.plnkr.co/Yv6BaLQQY03TMsnv0yHk/preview

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      我们有一个对象数组,每个对象都有一个对象数组,依此类推。这看起来像一个树数组,树中的每个节点都可以有任意数量的子节点,每个子节点都可以有任意数量的子节点,依此类推。所以问题是关于遍历树并只选择“选择”的节点。如果遇到未选中的节点,我们不会检查它的子节点。

      所以我们将遍历数组,并为每棵树检查是否选择了根节点,如果是,我们对其子节点执行相同的过程并返回树。

      var reduceTreeArray = function (trees) {
          return trees.reduce(function (acc, tree) { // walk over the array
              tree = getSelectedTree(tree);
              if (tree) { // check if we have at least one node
                  acc.push(tree);
              }
              return acc; // acc stands for accumulator
          }, []);
      };
      
      var getSelectedTree = function (node) {
          if (node.selected) {
              return {
                  sku: node.sku,
                  selected: true,
                  children: reduceTreeArray(node.children) // walk over its children
              };
          }
          return false; 
      };
      
      var selectedTrees = reduceTreeArray(trees);
      

      这两个相互递归的函数给出了期望的结果,树可以任意深,但请记住,您可以达到调用堆栈大小。

      现在关于实时取景。既然我们可以使用 angular,让我们使用$scope.$watch 方法在数据结构发生变化时得到通知并重新计算树。所以:

      $scope.$watch('data.children', function (newChildren) {
          $scope.data.components = reduceTreeArray(newChildren);
      }, true);
      

      请注意,我将 true 值作为第二个参数传递。这是因为我们必须进行深度观察,因此即使对象内部的值发生更改,我们也会收到通知,例如当有人更改对象上的 selected 值时。

      这是一个plunker 上面的东西。

      【讨论】:

        猜你喜欢
        • 2016-06-07
        • 2020-06-29
        • 2011-05-27
        • 2012-08-31
        • 2011-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多