2015-01-13 5 views
0

내 viewmodel에 따라 뷰를 업데이트하는 데 어려움이 있습니다. 내가하는 일을 요약하면 : 나는 아이템 (AllCredentials)의 배열을 가지고있다. 항목의 속성 중 하나는 "IsSelected"값입니다 (true 또는 false). 항목 값이 false (AllCredentials 배열을 만들 때 기본값) 일 때 항목은 "UnselectedCredentials"목록에 나타납니다. 이 목록의 항목을 두 번 클릭하면 "IsSelected"값이 토글되어 다른 "SelectedCredentials"목록에 나타납니다.넉 아웃 계산 된 배열이 올바르게 업데이트되지 않습니다.

내가 테스트 할 때 두 번 클릭했을 때 "IsSelected"값이 올바르게 토글되고 있지만 계산 된 배열 (2 개 중 2 개는 각각 2 개 목록에 해당)은 그에 따라 추가/제거되지 않습니다. "UnselectedCredentials"목록에서 항목을 두 번 클릭하면 "IsSelected"값이 false에서 true로 전환되어 목록에서 제거되고 "SelectedCredentials"목록에 추가됩니다. 여기

내 코드입니다 :

뷰 모델 :

var TestNWJS = TestNWJS || {}; 

TestNWJS.QualificationList = (function() { 

//private functions 

function FindUnselectedCredentials() { //function to populate UnselectedCredentials list 

    var filtering = ko.utils.arrayFilter(TestNWJS.QualificationList.ViewModel.AllCredentials(), function (item) { 
     return item.IsSelected === false; 
    }); 

    return filtering; 
} 

function FindSelectedCredentials() { //function to populate SelectedCredentials list 

    var filtering = ko.utils.arrayFilter(TestNWJS.QualificationList.ViewModel.AllCredentials(), function (item) { 
     return item.IsSelected === true; 
    }); 

    return filtering; 
} 

function CreateQualificationModel(allCredentialsList) { 
    TestNWJS.QualificationList.ViewModel = {}; 

    TestNWJS.QualificationList.ViewModel.AllCredentials = ko.observableArray(allCredentialsList); 

    TestNWJS.QualificationList.ViewModel.UnselectedCredentials = ko.computed(FindUnselectedCredentials, this); 
    TestNWJS.QualificationList.ViewModel.SelectedCredentials = ko.computed(FindSelectedCredentials, this); 

    TestNWJS.QualificationList.ViewModel.AllCredentials.extend({ notify: 'always' }); 
    TestNWJS.QualificationList.ViewModel.UnselectedCredentials.extend({ notify: 'always' }); 
    TestNWJS.QualificationList.ViewModel.SelectedCredentials.extend({ notify: 'always' }); 
} 

function toggleselected(id) { 
    var match = ko.utils.arrayFirst(TestNWJS.QualificationList.ViewModel.AllCredentials(), function (item) { 
     id = parseInt(id); 
     return id === item.Id; 
    }); 

    match.IsSelected = !match.IsSelected; 
    return match; 
} 

//public function 
return { 

    Init: function (allCredentialsList) { 
     CreateQualificationModel(allCredentialsList); 

     //when you select something from the dropdown this will happen. 
     $("select[name='QualificationFilter']").change(function (e) { 
      var id = $(this).val(); 
      e.preventDefault(); 
      var form = $(e.target).parents("form"); 
      var url = window.location.href.substr(0, window.location.href.lastIndexOf("QualificationList") + 17) 
      form.attr("action", url + "?Id=" + id); 
      form.submit(); 
     }); 

     $("#UnselectedCredentialsList").live('dblclick', function (e) { 
      toggleselected(this.value); 
     }); 

     $("#SelectedCredentialsList").live('dblclick', function (e) { 
      toggleselected(this.value); 
     }); 

     ko.applyBindings(TestNWJS.QualificationList.ViewModel); 
    } 
} 

})(); 

보기 :

<div> 
    <table> 
     <tr> 
      <td class="fieldName_td"> 
       @Html.Label("Available Credentials") 
      </td> 
      <td class="fieldData_td"> 
       <select data-bind="options: UnselectedCredentials, 
            optionsText: 'Name', 
            optionsValue: 'Id'" 
            size="10" multiple="multiple" id="UnselectedCredentialsList"></select> 
      </td> 
     </tr> 
    </table> 
</div> 

<div> 
    <table> 
     <tr> 
      <td class="fieldName_td"> 
       @Html.Label("Selected Credentials") 
      </td> 
      <td class="fieldData_td"> 
       <select data-bind="options: SelectedCredentials, 
            optionsText: 'Name', 
            optionsValue: 'Id'" 
            size="10" multiple="multiple" id="SelectedCredentialsList"></select> 
      </td> 
     </tr> 
    </table> 
</div> 
} 
@section scripts { 
    @Scripts.Render("~/Scripts/knockout-2.2.1.js", "~/jscripts/Administration/Interfaces/QualificationList.js", "~/Scripts/knockout.mapping-latest.js") 

<script type="text/javascript"> 
    $(function() { 
     TestNWJS.QualificationList.Init(@Html.Raw(Model.JsonAllCredentials)); 
    }) 
</script> 

} 

그냥 명확히하기 위해, 페이지의 초기로드에서 "UnselectedCredentials"목록이 나타나고있다 (즉, 처음에는 모든 것이 나타납니다) "IsSelected"값이 false 인 AllCredentials 배열의 모든 자격 증명이 나타납니다. 내가 겪고있는 문제는 뷰를 (및 잠재적으로 viewmodel) 값을 전환하려면 두 번 클릭 트리거 후 올바르게 업데이트되지 않는 관련이 있습니다.

답변

1

문제는 JSON 데이터의 초기로드 일 수 있다고 생각합니다. 내가 잘못 본 적이 없다면 Knockout은 자동으로 JSON 객체의 속성을 관찰 가능하게 만들지 않습니다. observableArray는 항목이 배열에 추가되거나 제거 될 때만 표시되며 배열 내의 항목이 변경되는지 여부는 알 수 없습니다. JSON 데이터의 디시리얼라이저를 작성하거나 관찰 가능 어레이에 JSON 데이터를 전달하기 전에 JSON 데이터의 요소를 제공 할 수있는 생성자 함수 (모든 특성을 관찰 가능하게 함)로 Credential 클래스를 작성해야 할 수도 있습니다.

Knockout Mapping Plugin을 살펴보십시오. 도움이 될 것입니다

viewmodel에 제약이 있는지 확실하지 않지만 약간 단순화하는 것이 좋습니다. 다중 배열을 사용하고 항목을 앞뒤로 이동할 이유가 없습니다. 더 간단한 구현은 Selection 속성이 true인지 false인지에 따라 테이블에 표시하는 단일 배열을 갖는 것입니다. 이처럼 : 당신의 ViewModel에서

<div> 
    <table> 
     <tr> 
      <td class="fieldName_td"> 
       @Html.Label("Available Credentials") 
      </td> 
      <td class="fieldData_td"> 
       <table data-bind="foreach:Credentials"> 
        <!-- ko if: !Selected --> 
        <tr> 
         <td data-bind="text><select data-bind="text: Name, $root.click: toggleSelected></td> 
        </tr> 
       </table> 
      </td> 
     </tr> 
    </table> 
</div> 

<div> 
    <table> 
     <tr> 
      <td class="fieldName_td"> 
       @Html.Label("Selected Credentials") 
      </td> 
      <td class="fieldData_td"> 
       <table data-bind="foreach:Credentials"> 
        <!-- ko if: Selected --> 
        <tr> 
         <td data-bind="text><select data-bind="text: Name, $root.click: toggleSelected></td> 
        </tr> 
       </table> 
      </td> 
     </tr> 
    </table> 
</div> 
} 

, 선택한만큼 (다음 뷰 모델이해야하는 유일한 일 (관찰뿐만 아니라해야 자격 증명의 각 속성) 하나 개의 관찰 배열의 모든 자격 증명을 넣고 속성은) 관측 단순히 선택하는 사람들을 위해 배열을 필터링, 선택한 자격 증명을 사용 할 때, 그리고

toggleSelection = function(credential) { 
    credential.Selected = !credential.Selected; 
} 

입니다.

행운을 빈다.

편집 : 자격 증명 클래스에 관한 유일한 속성과 같이 보일 수 있습니다, 이름 및 선택 가정 :

function Credential(name, selected) { 
    this.Name = ko.observable(name); 
    this.Selected = ko.observable(selected); 
} 

을 그리고 할 수 있습니다 JSON 데이터의 배열을 순환

var Credentials = ko.observableArray(); 
credentialsFromJson.forEach(function(c) { 
    var credential = new Credential(c.Name, c.Selected); 
    Credentials.push(credential); 
} 

그것은 각 속성을 관찰 가능하게 만듭니다. 보고 싶은 속성이 많은 경우 위에서 언급 한 ko.mapping 플러그인을 확인하십시오.

이 정보가 도움이됩니까? 코드를 올바르게 읽는다면 KO가보고있는 일이 없기 때문에 계산 된 배열이 업데이트되지 않고 Selected 속성을 관찰 가능하게 만들어서 수정해야합니다.

+0

생성자 함수를 사용하여 자격 증명 클래스를 만드는 것이 무엇을 의미하는지 명확히 할 수 있습니까? 그게 내 전망 모델에 있겠 니? – John

+0

예. 설명 할 답변을 업데이트하고 있습니다. – Beartums

+0

귀찮은 일은 싫지만 credentialFromJson.forEach (function (c) { var credential = new 자격 증명 (c.Name, c.Selected)) Credentials.push (자격 증명); } 제대로 작동하도록. 나는 그것을 내 Init 함수에 배치하고 자체의 개인 함수에 넣으려고했지만 거기에 구문 오류가있는 것, 그 기대 ')' – John

관련 문제