【问题标题】:Group same json attribute in an array在数组中分组相同的 json 属性
【发布时间】:2015-05-05 07:38:39
【问题描述】:

我将解释我需要什么。我有一个 JSON,我在其中执行一些操作,包括动态创建一些输入。例子在这里:

jsfiddle

实际上,当我创建一个输入时(只需点击列表中的一个项目,例如“asd1”),它会用新值填充一个新的 JSON。我需要的是将相同的项目分组到一个唯一的数组中。所以,这是它现在创建的 JSON:

{  
   "objects":[  
      {  
         "name":"firstObj",
         "attributes":[  
            {  
               "attrname":"asd1",
               "attrValue":"aaaDDD",
               "attrType":"text",
               "clicks":1
            },
            {  
               "attrname":"asd1",
               "attrValue":"qwe",
               "attrType":"text",
               "clicks":2
            }
         ]
      }
   ]
}

应该是这样的:

{  
   "objects":[  
      {  
         "name":"firstObj",
         "attributes":[  
            {  
               "attrname":"asd1",
               "attrValue":[  
                  "aaaDDD",
                  "qwe"
               ],
               "attrType":"text",
               "clicks":2
            }
         ]
      }
   ]
}

我已将attrValue 分组到一个数组中,因为我从“asd1”attrname 创建了两次相同的输入。我怎么能做到?顺便说一下,这里有一些代码:

Javascript:

var myApp = angular.module('myApp',[]);

myApp.controller("mycontroller", ["$scope", "$http",
    function($scope, $http){

        $scope.getItems = {
    "data": [
        {
            "label": "first",
            "objects": [
                {
                    "name": "firstObj",
                    "attributes": [
                        {
                            "attrname": "asd1",
                            "attrValue": "",
                            "attrType":"text"
                        },
                        {
                            "attrname": "asd2",
                            "attrValue": "",
                            "attrType":"text"
                        }
                    ]
                }
            ],
            "key": "bolla"
        },
        {
            "label": "second",
            "objects": [
                {
                    "name": "secondObj",
                    "attributes": [
                        {
                            "attrname": "asd",
                            "attrValue": "",
                            "attrType":"text"
                        },
                        {
                            "attrname": "asd3",
                            "attrValue": "",
                            "attrType":"text"
                        }
                    ]
                }
            ],
            "key": "2"
        }
    ]

};
    $scope.filterSelected = $scope.getItems.data[0].objects;

        $scope.myNewArray = {
            objects: [

            ]
        }

        $scope.createjson = function(attribute, items) {
            var obj = {};
            obj.name = angular.copy(attribute);
            obj.attributes = [];
            obj.attributes.push(angular.copy(items));
            return obj;
        }

        $scope.checkIfAttributeExists = function(attribute) {        
            for(var i=0; i<$scope.myNewArray.objects.length; i++) {                
                if($scope.myNewArray.objects[i]["name"] == attribute) {
                    return i;
                }
            }
            return -1;
        }

        $scope.pushItems = function pushItems(attribute, items) {
            if (items.clicks) {
                items.clicks++
            } else {
                items.clicks = 1
            }
            var index = $scope.checkIfAttributeExists(attribute);
            if(index == -1) {
                var obj = $scope.createjson(attribute, items);
                $scope.myNewArray.objects.push(angular.copy(obj));
            }
            else {
                $scope.myNewArray.objects[index].attributes.push(angular.copy(items));
            }


            //console.log($scope.myNewArray);
        }

        // remove function
    $scope.removeItem=function(attribute){
        attribute.clicks--;
        var idx = $scope.myNewArray.objects.indexOf(attribute);
        $scope.myNewArray.objects.splice(idx, 1);
    }

        $scope.showNewJson = function() {
            return $scope.myNewArray;
        }
}]);

HTML:

<div ng-app='myApp' ng-controller='mycontroller'>

    <div data-ng-repeat="item in myNewArray.objects track by $index">
        <div data-ng-repeat="attr in item.attributes track by $index">
        <div ng-if="attr.attrType == 'text'" >
            <input id="form-f{{$index}}" type="text" placeholder="{{attr.attrname}}" data-ng-model="attr.attrValue"/> <button ng-click="removeItem(attr)">Remove</button>
        </div>
        </div>
    </div>
    <div data-ng-repeat="object in getItems.data">
        <div data-ng-repeat="att in object.objects">
            <ul ng-repeat="data in att.attributes">
                <li>
                    <a ng-click="pushItems(att.name, data)">{{data.attrname}}</a>
                    <span>({{data.clicks}})</span>
                </li>
            </ul>
        </div>

    </div>


    <p>{{showNewJson()}}</p>
</div>

PS:我使用 Angularjs

【问题讨论】:

  • 如果你想改变$scope.myNewArray你也需要改变标记
  • 或者您只想创建具有新结构的新数组?
  • sidenote:我想,你的 remove 按钮工作错误
  • @Grundy 检查我在任务中创建的两个 JSON。第一个,你看到现在是什么。第二个是应该是什么。如果我在“asd1”上单击 3 次,它会创建 3 个输入,对吗?当我在这 3 个输入中添加一些值时,我需要创建一个类似于第二个的结构。所以 attrValue 将被分组到一个数组中,并插入值。
  • @Grundy 是的,删除不起作用:(

标签: javascript arrays json angularjs


【解决方案1】:

我非常想让它变得更容易,结果却很困难:-)

首先:我更改输出文本框的标记

<div data-ng-repeat="item in myNewArray.objects track by $index">
  <div data-ng-repeat="attr in item.attributes track by $index">
    <div ng-if="attr.attrType == 'text'">
      <div data-ng-repeat="attrVal in attr.attrValues track by $index">
        <input id="form-f{{$index}}" type="text" placeholder="{{attr.attrname}}" data-ng-model="attr.attrValues[$index]" />
        <button ng-click="removeItem(item,attr, $index)">Remove</button>
      </div>
    </div>
  </div>
</div>

现在为每个属性值添加了文本框

第二:添加一些查找元素的函数:findAttributesInGetItemsByNamefindElemByField

第三:改变removeItem函数为新结构

$scope.removeItem = function(item, attr, $index) {
    var obj = findAttributesInGetItemsByName($scope.getItems.data, item.    
    if (obj) {
        var objAttr = findElemByField(obj.attributes, "attrname", attr.attrname);
        if (objAttr) {
            objAttr.clicks -= 1;
            if (!objAttr.clicks) delete objAttr.clicks;
        }
    }
    attr.clicks -= 1;
    attr.attrValues.splice($index, 1);
    if (!attr.attrValues.length) {
        var idx = objects.indexOf(item);
        objects.splice(idx, 1);
    }
}

最后更改 pushItems 以获得新结构

$scope.pushItems = function pushItems(attribute, items) {
    console.log(items, attribute);
    items.clicks = (items.clicks || 0) + 1;
    currentObj = findElemByField(objects, "name", attribute);
    if (currentObj) {
        var curAttr = findElemByField(currentObj.attributes, "attrname", items.attrname);
        if (curAttr) {
            curAttr.attrValues.push("");
            curAttr.clicks += 1;
        } else {
            currentObj.attributes.push(createItems(items));
        }
    } else {
        objects.push({
            name: attribute,
            attributes: [
                createItems(items)
            ]
        });
    }
};

代码看起来很丑,但它可以工作:-)

var myApp = angular.module('myApp', []);

myApp.controller("mycontroller", ["$scope", "$http",
  function($scope, $http) {

    $scope.getItems = {
      "data": [{
        "label": "first",
        "objects": [{
          "name": "firstObj",
          "attributes": [{
            "attrname": "asd1",
            "attrValue": "",
            "attrType": "text"
          }, {
            "attrname": "asd2",
            "attrValue": "",
            "attrType": "text"
          }]
        }],
        "key": "bolla"
      }, {
        "label": "second",
        "objects": [{
          "name": "secondObj",
          "attributes": [{
            "attrname": "asd",
            "attrValue": "",
            "attrType": "text"
          }, {
            "attrname": "asd3",
            "attrValue": "",
            "attrType": "text"
          }]
        }],
        "key": "2"
      }]

    };

    function findAttributesInGetItemsByName(getItemsData, name) {
      for (var i = 0, len = getItemsData.length; i < len; i++) {
        for (var j = 0, jlen = getItemsData[i].objects.length; j < jlen; j++) {
          var o = getItemsData[i].objects[j];
          if (o.name == name) return o;
        }
      }
      return null;
    }

    $scope.filterSelected = $scope.getItems.data[0].objects;

    $scope.myNewArray = {
      objects: [

      ]
    };

    function findElemByField(objects, field, value) {
      for (var i = 0, len = objects.length; i < len; i++) {
        if (objects[i][field] == value) return objects[i];
      }
      return null;
    }

    function createItems(items) {
      return {
        attrname: items.attrname,
        attrType: "text",
        clicks: 1,
        attrValues: [""]
      }
    }

    var objects = $scope.myNewArray.objects;
    $scope.pushItems = function pushItems(attribute, items) {
      console.log(items, attribute);
      items.clicks = (items.clicks || 0) + 1;
      currentObj = findElemByField(objects, "name", attribute);
      if (currentObj) {
        var curAttr = findElemByField(currentObj.attributes, "attrname", items.attrname);
        if (curAttr) {
          curAttr.attrValues.push("");
          curAttr.clicks += 1;
        } else
          currentObj.attributes.push(createItems(items));
      } else {
        objects.push({
          name: attribute,
          attributes: [
            createItems(items)
          ]
        })
      }

    };

    // remove function
    $scope.removeItem = function(item, attr, $index) {
      var obj = findAttributesInGetItemsByName($scope.getItems.data, item.name);
      if (obj) {
        var objAttr = findElemByField(obj.attributes, "attrname", attr.attrname);
        if (objAttr) {
          objAttr.clicks -= 1;
          if (!objAttr.clicks) delete objAttr.clicks;
        }
      }
      attr.clicks -= 1;
      attr.attrValues.splice($index, 1);
      if (!attr.attrValues.length) {
        var idx = objects.indexOf(item);
        objects.splice(idx, 1);
      }
    }

    $scope.showNewJson = function() {
      return $scope.myNewArray;
    }
  }
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
<div ng-app='myApp' ng-controller='mycontroller'>

  <div data-ng-repeat="item in myNewArray.objects track by $index">
    <div data-ng-repeat="attr in item.attributes track by $index">
      <div ng-if="attr.attrType == 'text'">
        <div data-ng-repeat="attrVal in attr.attrValues track by $index">
          <input id="form-f{{$index}}" type="text" placeholder="{{attr.attrname}}" data-ng-model="attr.attrValues[$index]" />
          <button ng-click="removeItem(item,attr, $index)">Remove</button>
        </div>
      </div>
    </div>
  </div>
  <div data-ng-repeat="object in getItems.data">
    <div data-ng-repeat="att in object.objects">
      <ul ng-repeat="data in att.attributes">
        <li>
          <a href="#" ng-click="pushItems(att.name, data)">{{data.attrname}}</a>
          <span>({{data.clicks}})</span>
        </li>
      </ul>
    </div>

  </div>


  <p>{{showNewJson()}}</p>
</div>

【讨论】:

  • 你是个天才!看起来很完美!
【解决方案2】:

这可以通过简单地使用哈希来完成。请注意,我使用 jQuery 来复制对象,这样我就不会更改原始对象。你可以使用angular.extend

var obj = {  
   "objects":[  
      {  
         "name":"firstObj",
         "attributes":[  
            {  
               "attrname":"asd1",
               "attrValue":"aaaDDD",
               "attrType":"text",
               "clicks":1
            },
            {  
               "attrname":"asd1",
               "attrValue":"qwe",
               "attrType":"text",
               "clicks":2
            }
         ]
      }
   ]
}

var attrs = obj.objects[0].attributes;
var newAttrs = [];
var nameHash = {};
for(var i=0; i<attrs.length; i++){
    var name = attrs[i].attrname;
    if(nameHash[name]){
        nameHash[name].attrValue.push(attrs[i].attrValue);
    } else {
        var newObj = $.extend({}, attrs[i]);
        newObj.attrValue = [newObj.attrValue];
        newAttrs.push(newObj);
        nameHash[name] = newObj;
    }

}

console.log('newAttrs : ', newAttrs)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

【讨论】:

  • 你能提供更新我的jsfiddle吗?只是想了解它是否有效:) 谢谢。
  • 它不起作用..如果它卡在:[{"attrname":"asd1","attrValue":["value1","value2"],"attrType":"text" ,"clicks":n}] 不变..
  • 我只为第一个属性调用它,请根据需要调用该函数。是否需要合并所有对象属性?
  • 这可以通过遍历完整数据来完成。检查这个jsfiddle.net/vuqcopm7/40
猜你喜欢
  • 2023-02-05
  • 2015-02-04
  • 2022-11-25
  • 2022-08-17
  • 1970-01-01
  • 2012-06-27
  • 2017-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多