2016-05-13 22 views
4

试图了解JavaScript并写入对象。我这里有一个对象:如何搜索JavaScript对象并更改值

{ 
    "name":"", 
    "children":[ 
     { 
     "name":"Level 1", 
     "children":[ 
      { 
       "name":"Level 2", 
       "children":[ 
        { 
        "name":"Level 3", 
        "children":[ 
         { 
          "name":"Level 4", 
          "children":[ 
           { 
           "name":"Speed", 
           "children":null, 
           "id":6 
           } 
          ], 
          "id":5 
         } 
        ], 
        "id":4 
        } 
       ], 
       "id":3 
      } 
     ], 
     "id":2 
     }, 
     { 
     "name":"Level 1", 
     "children":[ 
      { 
       "name":"Level 2", 
       "children":[ 
        { 
        "name":"Level 3", 
        "children":[ 
         { 
          "name":"Level 4", 
          "children":[ 
           { 
           "name":"Cost", 
           "children":null, 
           "id":11 
           } 
          ], 
          "id":10 
         } 
        ], 
        "id":9 
        } 
       ], 
       "id":8 
      } 
     ], 
     "id":7 
     }, 
     { 
     "name":"Level 1", 
     "children":[ 
      { 
       "name":"Level 2", 
       "children":[ 
        { 
        "name":"Level 3", 
        "children":[ 
         { 
          "name":"Level 4", 
          "children":[ 
           { 
           "name":"Manufacturability", 
           "children":null, 
           "id":16 
           } 
          ], 
          "id":15 
         } 
        ], 
        "id":14 
        } 
       ], 
       "id":13 
      } 
     ], 
     "id":12 
     } 
    ], 
    "id":1 
} 

,我想了解如何寻找一个给定的id值,并改变其name价值。

在我的情况,我知道我可以使用d.idd.name用下面的代码访问的值(这是一个小部件显示的一部分; name值填充它)

var jstring = this.model.get('value') ? this.model.get('value') : "{}"; 
// where 'value' = demo.json 

var root = JSON.parse(jstring) 
var g = this.g = svg.selectAll("g") 
    .data(partition.nodes(root)) 
    .enter().append("g"); 
var path = this.path = g.append("path") 
     .attr("d", arc) 
     .style("fill", function(d) { 
     d.active = d.active ? true : false 
     return d.active || d.center ? color[1] : color[0]; 
       }) 
     .on("dblclick",dblclick); 
var text = this.text = g.append("text") 
       .attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; }) 
       .attr("x", function(d) { return y(d.y); }) 
       .attr("dx", "6") // margin 
       .attr("dy", ".35em") // vertical-align 
       .text(function(d) { return d.name; }); 

例如,如果我点击窗口小部件上的某个区域,我可以通过将其值设置为d.name来填充输入框,它给了我正确的值。

function dblclick(d) 
      { 


        var input = document.getElementById("name"); 
        input.value = d.name; 


        $("#dialog").dialog(
        { 

        buttons: { 
         Save: function() { 
         d.name = input.value; 

        var newString = JSON.stringify(root, function(key, val) { 

         if (Array.isArray(val)){ 
          return val 
         } 
         if (val != null && typeof val == "object") { 
          val = _.pick(val, 'name', 'children', 'id'); 
          if(d.id == val.id){ 

           input.value = d.name; 
          console.log(d.name) 
          } 

          val.children = Array.isArray(val.children) ? val.children : []; 

          return val 
         } 
         return val 
        }) 
        self.model.set('value', newString) 
        self.update() 
        console.log(newString) 

我发现了一个类似的问题here,但我不明白如何应用答案修改我的JSON。

另外这里是我尝试过的一把小提琴:http://jsfiddle.net/CVvW4/237/。我跟着另一个问题的答案,但我的实施是错误的。

+0

你究竟想达到什么目的?您的点击事件处理程序代码在哪里?你可以说得更详细点吗? – iulian

+0

你在数据树中搜索某个'id'值吗?如果是这样,您将需要递归调用搜索函数。 – C14L

+0

@iulian我遗漏了它,因为我认为它会代码太多,但我会编辑它以添加它 – c2bh2016

回答

3
  • 你jsonStr已经是一个JSON对象,无需字符串化和解析它
  • 你有一个嵌套的结构,找到的东西,你需要一个递归函数

这里是如何找到一个节点给予其ID:

var root = jsonStr 

function findById(node, id) { 
    if (node.id == id) return node; // we found the node with the id given, return it 
    var result = null; // if the id wasn´t the one we were looking, we need to look if it is in its children 
    if (node.children) { 
    for (var i = 0; i < node.children.length && result == null; i++) { 
     result = findById(node.children[i], id) 
    } 
    } 
    return result; // return null if it wasn´t in its children, return the node if it was 
} 

console.log(findById(root, 16)) 

现在,更改其名称,你可以简单地做:

findById(root, 16).name = 'asd'; 
+0

感谢您的详细解释,现在更有意义。我将你的函数添加到了我的click事件中,并且在控制台中我可以看到newString和root的正确值变化,但是jstring变量不会改变。你可以看一下吗? https://jsfiddle.net/baqxh3sf/ – c2bh2016

+0

@ c2bh2016尝试使用self.model.get('value')而不是console.log(jstring) – juvian

+0

我刚刚尝试过,部件没有改变。任何其他建议? – c2bh2016

0

我真的很喜欢@juvian提供的接受的答案,我投了票。

我提供这个来展示如何命名子数组和我们希望匹配的节点上的属性。我也通过类型保护数组迭代。

我在这里提供了一些关于JSON,JavaScript对象以及什么时候解析的细节,何时不通过提供每个解析的例子来解析。

请注意,我添加了一个小函数typeName以协助发现名称,因此我们不试图迭代与我们正在搜索的属性同名的非数组类型(空字符串,字符串等) 。

注:我并不能防止对searchFor值的属性的类型匹配,但如果这是重要的,串"1" VS号1你可以使用typeName如把在增强。

例播放使用:https://jsfiddle.net/MarkSchultheiss/s4sxy4f6/

这里是一个精简版,我试图将名称分配给它之前检查成功:https://jsfiddle.net/MarkSchultheiss/s4sxy4f6/1/

代码和对象,以显示类型

// this is just a string, but special as it is a JSON string and can be parsed 
var myJSON = '{"children":[{"children":[{"children":[{"children":[{"children":[{"children":null,"id":6,"name":"Speed"}],"id":5,"name":"Level 4"}],"id":4,"name":"Level 3"}],"id":3,"name":"Level 2"}],"id":2,"name":"Level 1"},{"children":[{"children":[{"children":[{"children":[{"children":null,"id":11,"name":"Cost"}],"id":10,"name":"Level 4"}],"id":9,"name":"Level 3"}],"id":8,"name":"Level 2"}],"id":7,"name":"Level 1"},{"children":[{"children":[{"children":[{"children":[{"children":null,"id":16,"name":"Manufacturability"}],"id":15,"name":"Level 4"}],"id":14,"name":"Level 3"}],"id":13,"name":"Level 2"}],"id":12,"name":"Level 1"}],"_default":{},"id":1,"name":""}'; 

// This is a JavaScript Object 
var myObject = { 
    "children": [{ 
    "children": [{ 
     "children": [{ 
     "children": [{ 
      "children": [{ 
      "children": null, 
      "id": 6, 
      "name": "Speed" 
      }], 
      "id": 5, 
      "name": "Level 4" 
     }], 
     "id": 4, 
     "name": "Level 3" 
     }], 
     "id": 3, 
     "name": "Level 2" 
    }], 
    "id": 2, 
    "name": "Level 1" 
    }, { 
    "children": [{ 
     "children": [{ 
     "children": [{ 
      "children": [{ 
      "children": null, 
      "id": 11, 
      "name": "Cost" 
      }], 
      "id": 10, 
      "name": "Level 4" 
     }], 
     "id": 9, 
     "name": "Level 3" 
     }], 
     "id": 8, 
     "name": "Level 2" 
    }], 
    "id": 7, 
    "name": "Level 1" 
    }, { 
    "children": [{ 
     "children": [{ 
     "children": [{ 
      "children": [{ 
      "children": null, 
      "id": 16, 
      "name": "Manufacturability" 
      }], 
      "id": 15, 
      "name": "Level 4" 
     }], 
     "id": 14, 
     "name": "Level 3" 
     }], 
     "id": 13, 
     "name": "Level 2" 
    }], 
    "id": 12, 
    "name": "Level 1" 
    }], 
    "_default": {}, 
    "id": 1, 
    "name": "" 
}; 

// just to get the name of the objects type from the object prototype 
function typeName(obj) { 
    // splits and returns second part of string such as "[object Array]" returns the "Array" removing the closing bracket 
    return Object.prototype.toString.call(obj).match(/.* (.*)\]/)[1]; 
} 
// show some type names to assist with object "type" education 
console.log("myJSON:" + typeName(myJSON)); // String 
console.log("myObject:" + typeName(myObject)); // Object 
console.log("Children of object:" + typeName(myObject.children)); // Array 

console.log("Children Type:" + typeof myObject["children"] + " typeName:" + typeName(myObject.children)); 
console.log(Object.keys(myObject)); // thus we can get the string "children" from the object with Object.keys(myObject)[0] 

var root = JSON.stringify(myObject); // create string of object 
console.log("root:" + typeName(root)); // String 

var newObject = JSON.parse(myJSON); // create new object of string 

// create function with private name to call internally 
// done this way to allow for external modification of the name without need to change the code inside it. 
var findByProperty = function findNext(node, searchValue, propertyName, childName) { 
    if (node.hasOwnProperty(propertyName) && node[propertyName] == searchValue) return node; // node found return it 
    var result = null; 
    // has child array by the name and it is non-empty array 
    if (node.hasOwnProperty(childName) && typeName(node[childName]) === 'Array' && node[childName].length) { 
    for (var i = 0; i < node[childName].length && result == null; i++) { 
     result = findNext(node[childName][i], searchValue, propertyName, childName); 
    } 
    } 
    return result; // return null if not in children, return the node if it was 
} 
var searchFor = 16; 
console.log('searchFor is a type of:'+typeName(searchFor)); 
var propertyName = "id"; 
var childrenArrayName = "children"; 

// show how we can return the found node then modify it 
var found = findByProperty(myObject, searchFor, propertyName, childrenArrayName); 
found.name = 'Freddy'; 
console.log(myObject); 
console.log(myObject["children"][2]["children"][0]["children"][0]["children"][0]["children"][0].name); // logs "Freddy" 

var secondfound = findByProperty(newObject, searchFor, propertyName, childrenArrayName); 
secondfound.name = 'Walter';// modify the object via the node 
console.log(newObject); 
console.log(newObject["children"][2]["children"][0]["children"][0]["children"][0]["children"][0].name); // logs "Walter" 
// just to show that the actual object is the one found 
console.log(secondfound.name === newObject["children"][2]["children"][0]["children"][0]["children"][0]["children"][0].name); // logs true 

这里是控制台日志的输出:

myJSON:String 
VM78:125 myObject:Object 
VM78:126 Children of object:Array 
VM78:128 Children Type:object typeName:Array 
VM78:129 ["children", "_default", "id", "name"] 
VM78:132 root:String 
VM205:148 searchFor is a type of:Number 
VM281:153 Object {children: Array[3], _default: Object, id: 1, name: ""} 
VM281:154 Freddy 
VM337:158 Object {children: Array[3], _default: Object, id: 1, name: ""} 
VM337:159 Walter 
VM344:160 true