2014-06-06 3 views
2

두 번 전에 질문을 받았지만 여전히이 문제에 대한 해결책을 찾을 수 없다는 것을 알고 있습니다. (나는 단지 2 주 전에 KO를 사용하기 시작했습니다.)회피 TypeError : 원형 구조체를 JSON으로 변환

각 VM은 VM의 관찰 가능에 바인딩 된 여러 개의 필드가 있습니다. 사용자가 GO 버튼을 클릭하면 입력 한 모든 필드를 JSON 문자열로 변환하고 서버로 보내려고합니다. 이것은 뷰 모델이다 (? I이 오른쪽 표현한있다)

function ViewModel() { 
    var self = this; 

    function searchVar() { 
     self.users = ko.observable(); 
     self.fromdate = ko.observable(); 
     self.todate = ko.observable(); 
     self.eqpname = ko.observable(); 
     self.maker = ko.observable(); 
     self.model = ko.observable(); 
     self.makercode = ko.observable(); 
     self.partname = ko.observable(); 
     self.vendor = ko.observable(); 
    } 

    self.searchVars = ko.observableArray(); 

    self.addSearchVar = function (vm) { 
     self.searchVars.removeAll(); 
     self.searchVars.push(vm); 
     //console.log(vm); 
     var data = ko.toJSON(self.searchVars); 
     alert(data); 
    }; 

    var sv = new searchVar(); //not really using this 

} 
    var vm = new ViewModel(); 

여기에서의 문제 addSearchVar 기능 다시 searchVars 어레이에 대한 참조를 생성하고이 원형 기준 오차를 생성하는 것 때문이다. 이 작업을 수행하는 더 좋은 방법이 있습니까? (중첩 모델을 사용해 보았지만 내 머리를 감쌀 수는 없습니다).

마크 업은 거의 표준입니다. data-bind:"value: [fieldname]" 등. 내가 동적으로 만든 구성 요소를 많이 가지고 있기 때문에 내 ko.applyBindings(vm) 바로 페이지의 하단에 배치. 버튼 속성은 다음과 같습니다. <input type="button" id="btnGo" value="Go" style="background-color:#CCFFCC" data-bind="click: addSearchVar" />

통찰력을 높이세요. 감사. /aj

답변

0

json이 뷰 모델을 인코딩하기 직전에 순환 참조를 제거/교체하여 이러한 문제를 방지 할 수 있습니다.

if (typeof JSON.decycle !== 'function') { 
    JSON.decycle = function decycle(object) { 
     'use strict'; 

// Make a deep copy of an object or array, assuring that there is at most 
// one instance of each object or array in the resulting structure. The 
// duplicate references (which might be forming cycles) are replaced with 
// an object of the form 
//  {$ref: PATH} 
// where the PATH is a JSONPath string that locates the first occurance. 
// So, 
//  var a = []; 
//  a[0] = a; 
//  return JSON.stringify(JSON.decycle(a)); 
// produces the string '[{"$ref":"$"}]'. 

// JSONPath is used to locate the unique object. $ indicates the top level of 
// the object or array. [NUMBER] or [STRING] indicates a child member or 
// property. 

     var objects = [], // Keep a reference to each unique object or array 
      paths = [];  // Keep the path to each unique object or array 

     return (function derez(value, path) { 

// The derez recurses through the object, producing the deep copy. 

      var i,   // The loop counter 
       name,  // Property name 
       nu;   // The new object or array 

// typeof null === 'object', so go on if this value is really an object but not 
// one of the weird builtin objects. 

      if (typeof value === 'object' && value !== null && 
        !(value instanceof Boolean) && 
        !(value instanceof Date) && 
        !(value instanceof Number) && 
        !(value instanceof RegExp) && 
        !(value instanceof String)) { 

// If the value is an object or array, look to see if we have already 
// encountered it. If so, return a $ref/path object. This is a hard way, 
// linear search that will get slower as the number of unique objects grows. 

       for (i = 0; i < objects.length; i += 1) { 
        if (objects[i] === value) { 
         return {$ref: paths[i]}; 
        } 
       } 

// Otherwise, accumulate the unique value and its path. 

       objects.push(value); 
       paths.push(path); 

// If it is an array, replicate the array. 

       if (Object.prototype.toString.apply(value) === '[object Array]') { 
        nu = []; 
        for (i = 0; i < value.length; i += 1) { 
         nu[i] = derez(value[i], path + '[' + i + ']'); 
        } 
       } else { 

// If it is an object, replicate the object. 

        nu = {}; 
        for (name in value) { 
         if (Object.prototype.hasOwnProperty.call(value, name)) { 
          nu[name] = derez(value[name], 
           path + '[' + JSON.stringify(name) + ']'); 
         } 
        } 
       } 
       return nu; 
      } 
      return value; 
     }(object, '$')); 
    }; 
} 

https://github.com/douglascrockford/JSON-js/blob/master/cycle.js

이 기준 값으로 모든 순환 참조를 대체 :이 작업을 수행하는 한 가지 방법은 더글러스 'JSON.decycle가 사용하고 있습니다. 귀하의 경우에는

이처럼 사용하십시오 : 또 다른 옵션은

var data = JSON.stringify(JSON.decycle(ko.toJS(self.searchVars))); 

을 모든 cirular 참조 제거 : 다음

JSON.stringifyOnce = function (obj, replacer, space) { 
    var cache = []; 
    var json = JSON.stringify(obj, function(key, value) { 
     if (typeof value === 'object' && value !== null) { 
      if (cache.indexOf(value) !== -1) { 
       // circular reference found, discard key 
       return; 
      } 
      // store value in our collection 
      cache.push(value); 
     } 
     return replacer ? replacer(key, value) : value; 
    }, space); 
    cache = null; 
    return json; 
}; 

그리고 :

var data = JSON.stringifyOnce(ko.toJS(self.searchVars)); 
+0

이 일을 매력처럼! 정말 고마워! – user3713861

+0

당신은 환영합니다 :) – sroes

관련 문제