2012-05-23 3 views
0

knockoutjs 웹 사이트에서 샘플을 찾았습니다. 여기서는 다중 선택 목록 상자에 값을 바인딩합니다. 그러나 그들은 매우 간단한 관측 가능한 배열을 사용하고 있습니다. 사용할 수있는 나라선택한 국가.knockoutjs 복합 배열 복수 선택 목록 상자에서 데이터 바인딩

<p> 
    Choose some countries you'd like to visit: 
    <select data-bind="options: availableCountries, selectedOptions: chosenCountries" size="5" multiple="true"></select> 
</p> 

<script type="text/javascript"> 
    var viewModel = { 
     availableCountries : ko.observableArray(['France', 'Germany', 'Spain']), 
     chosenCountries : ko.observableArray(['Germany']) // Initially, only Germany is selected 
    }; 

    // ... then later ... 
    viewModel.chosenCountries.push('France'); // Now France is selected too 
</script> 

하지만 내 모델이 너무 복잡하여 모델의 일부를 json 형식으로 언급했습니다. 여기

"JobOrderDelivTranscript" : [{ 
     "TranscriptType" : { 
      "Id" : 1, 
      "Name" : null, 
      "CreatedBy" : 0, 
      "CreatedDate" : "0001-01-01T00:00:00", 
      "ModifiedBy" : 0, 
      "ModifiedDate" : "0001-01-01T00:00:00", 
      "IsActive" : false, 
      "EntityStatus" : 0, 
      "ErrorMessage" : null, 
      "ExternalID" : 0, 
      "ExternalSystemID" : 0 
     }, 
     "Id" : 1, 
     "Name" : null, 
     "CreatedBy" : 0, 
     "CreatedDate" : "0001-01-01T00:00:00", 
     "ModifiedBy" : 0, 
     "ModifiedDate" : "0001-01-01T00:00:00", 
     "IsActive" : false, 
     "EntityStatus" : 0, 
     "ErrorMessage" : null, 
     "ExternalID" : 0, 
     "ExternalSystemID" : 0 
    }, { 
     "TranscriptType" : { 
      "Id" : 2, 
      "Name" : null, 
      "CreatedBy" : 0, 
      "CreatedDate" : "0001-01-01T00:00:00", 
      "ModifiedBy" : 0, 
      "ModifiedDate" : "0001-01-01T00:00:00", 
      "IsActive" : false, 
      "EntityStatus" : 0, 
      "ErrorMessage" : null, 
      "ExternalID" : 0, 
      "ExternalSystemID" : 0 
     }, 
     "Id" : 2, 
     "Name" : null, 
     "CreatedBy" : 0, 
     "CreatedDate" : "0001-01-01T00:00:00", 
     "ModifiedBy" : 0, 
     "ModifiedDate" : "0001-01-01T00:00:00", 
     "IsActive" : false, 
     "EntityStatus" : 0, 
     "ErrorMessage" : null, 
     "ExternalID" : 0, 
     "ExternalSystemID" : 0 
    } 
] 

내 "chosenCountries"JobOrderDelivTranscript됩니다(). 첫 번째 옵션을 선택하면 JobOrderDelivTranscript() [0] .TranscriptType.Id와 매핑되어야합니다. 그들의 예제에서는 문자열 배열을 사용하고 있지만 복잡한 데이터를 바인딩해야합니다. 어떻게해야합니까?

심지어 내가 선택받을 수있는 옵션을 만들었습니다하지만 JSON 데이터가 업데이트 점점되지

ko.bindingHandlers['selectedCustomOptions'] = { 
      getSelectedValuesFromSelectNode: function (selectNode) { 
       var result = []; 
       var nodes = selectNode.childNodes; 
       for (var i = 0, j = nodes.length; i < j; i++) { 
        var node = nodes[i], tagName = ko.utils.tagNameLower(node); 
        if (tagName == "option" && node.selected) 
         result.push(ko.selectExtensions.readValue(node)); 
        else if (tagName == "optgroup") { 
         var selectedValuesFromOptGroup = ko.bindingHandlers['selectedCustomOptions'].getSelectedValuesFromSelectNode(node); 
         Array.prototype.splice.apply(result, [result.length, 0].concat(selectedValuesFromOptGroup)); // Add new entries to existing 'result' instance 
        } 
       } 
       return result; 
      }, 
      'init': function (element, valueAccessor, allBindingsAccessor) { 
       ko.utils.registerEventHandler(element, "change", function() { 
        var value = valueAccessor(); 
        var valueToWrite = ko.bindingHandlers['selectedCustomOptions'].getSelectedValuesFromSelectNode(this); 
        ko.jsonExpressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite); 
       }); 
      }, 
      'update': function (element, valueAccessor) { 
       if (ko.utils.tagNameLower(element) != "select") 
        throw new Error("values binding applies only to SELECT elements"); 

       var newValue = ko.utils.unwrapObservable(valueAccessor()); 
       if (newValue && typeof newValue.length == "number") { 
        var nodes = element.childNodes; 
        for (var i = 0, j = nodes.length; i < j; i++) { 
         var node = nodes[i]; 
         if (ko.utils.tagNameLower(node) === "option") 
          ko.utils.setOptionNodeSelectionState(node, arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0); 
        } 
       } 
      } 
     }; 

     function arrayIndexOf (array, item) { 
      if (typeof Array.prototype.indexOf == "function") 
       return Array.prototype.indexOf.call(array, item); 
      for (var i = 0, j = array.length; i < j; i++) 
       if (array[i].TranscriptType.Id() === item.Id) 
        return i; 
      return -1; 
     } 

사용자 정의 바인딩했습니다.

간단한 방법이 있습니까?

미리 감사드립니다.

답변

1

나는 당신의 질문을 이해하지만 당신은 selectedOptions 바인딩으로 복잡한 객체에 바인딩하려고하는 것 같습니다. 원하는 것을 할 수있는 두 가지 방법이 있습니다. 첫 번째는 optionsValue 바인딩을 계산과 결합하여 바인딩 ID를 객체 루트 수준까지 끌어 올리는 것입니다. 불행히도 optionsValue 바인딩은 루트에서만 작동하므로 optionsValue: 'TranscriptType.Id'이 작동하지 않습니다.

<p>Choose some countries you'd like to visit:</p> 
<select data-bind="options: availableCountries, optionsText: optionsText, 
     optionsValue: 'id', selectedOptions: 
     chosenCountries" size="5" multiple="true"></select> 

<p data-bind="text: ko.toJSON(chosenCountries)"> 
</p> 

var JobOrderDelivTranscript = function(id) { 
    var self = this; 
    this.TranscriptType = { 
     Id : id 
    } 
    this.id = ko.computed(function() { 
     return self.TranscriptType.Id 
    }); 
}; 

http://jsfiddle.net/madcapnmckay/6K6kH/

두 번째 방법은 경우 KO 평등을 테스트하기 위해 객체 참조를 사용하는 optionsValue를 사용하지 않는 것입니다. selectedCounties 배열에서 동일한 객체 참조를 유지하는 한 모든 것이 작동합니다.

http://jsfiddle.net/madcapnmckay/hmsqf/

두 가지 방법

var viewModel = function() { 
    var self = this; 
    this.availableCountries = ko.observableArray([ 
     new JobOrderDelivTranscript("Some Transcript 1"), 
     new JobOrderDelivTranscript("Some Transcript 2"), 
     new JobOrderDelivTranscript("Some Transcript 3")]); 

    this.chosenCountries = ko.observableArray([ self.availableCountries()[0] ]); 

    this.optionsText = function(option) { 
     return option.TranscriptType.Id; 
    };   
}; 

var vm = new viewModel(); 
vm.chosenCountries.push(vm.availableCountries()[1]); 

은 장점과 단점을 가지고, 그것은 올바른 적합 특정 상황에 따라 달라집니다.

편집

당신이 문서 here under "Advanced Usage"에 포함되는 매핑 옵션을 사용해야합니다 매핑 플러그인과 같은 일을합니다.

다음은 적응할 수 있어야하는 예입니다. 코드를 구성하기 위해

http://jsfiddle.net/madcapnmckay/hmsqf/2/

더 나는이 논리가 descrete 블록에 포함 할 수 있습니다 내가 주문과 예에서처럼 많은 자바 스크립트 클래스를 만드는 것이 좋습니다. 나는 또한 오래된 jquery 선택기를 사용하지 않는 것이 좋습니다, KO로 많은 초보자는 두 가지를 섞어도 괜찮다고 생각합니다. 필자의 견해로는 뷰 모델과 뷰 사이의 관심의 분리가 희석되고 있습니다.click 바인딩을 사용할 수있는 경우 $(selector).click을 사용해야하는 이유는 무엇입니까?

희망이 도움이됩니다.

+0

빠른 답장을 보내 주셔서 감사합니다. jsfiddle [link] http://jsfiddle.net/nanda/uVjUv/1/에서 샘플 애플리케이션을 찾으십시오. 매핑 모델을 사용하고 있습니다. 나는 여러개의 joborder를 가지고 있으며 각각의 주문에는 목록 상자가 있습니다. 목록 상자를 바인딩해야합니다. 다시 한 번 감사드립니다 – Nanda

+0

@Nanda - 내 대답이 도움이 되었습니까? 나는 당신의 jsfiddle에서 무슨 일이 벌어지고 있는지 정말로 이해할 수 없다. 나는 매핑 플러그인으로 보여준 것을하기를 원할 경우 데이터를 올바르게 형성하기 위해 mappingOptions를 사용해야 할 것이라고 말하고 싶다. – madcapnmckay

+0

정말 도움이되었습니다. 녹아웃 고급 바인딩에 대한 명확성이 더 있습니다. 내가 수동 viewmodel을 사용하고있는 경우에는 코드를 따라갈 수 있습니다. 하지만 매핑 플러그인을 사용하고 있으며 녹아웃 및 매핑을위한 초보자입니다. 따라서 고급 옵션을 사용할 수 없습니다. 하지만 나는 시도해 볼 것이다. 매핑에 대한 아이디어가 있다면 의견을 공유하십시오. madcapnmckay 정말 고마워. – Nanda

관련 문제