淘汰阵列和绑定问题

时间:2015-01-09 22:31:11

标签: knockout.js

我在击倒时遇到困难。从我的模型,我发送一个包含凭据列表的JSON对象。每个凭证都有一个" Id"," Name"和" Selected"属性。在我看来,我有2个列表。第一个显示所有凭据" Selected"值等于" false"。第二个列表显示所有具有" Selected"值等于" true"。

最初,所有项目都将包含" Selected"值等于false。当我双击列表中的项目时,"选择"值切换以便从第一个列表中删除它并添加第二个列表。我的问题是,我似乎无法使绑定正常工作。起初我能够正确填充第一个列表,我可以手动输入一个值(Id)到切换功能,这样在加载页面时,我指定的任何项目都在第二个列表中正确列出。但是,我这样做是错误的,因为我正在更改原始输入数据,而不是可观察数组,因此我的视图无法正确更新。

这就是我目前拥有它的方式。目前,当它进入toggleselected函数时,它不会检索正确的凭证(而在它使用原始的,不可观察的数据时它工作之前)。我肯定错过了什么!

MODEL(只是创建JSON的一种方法):

        private void createJsonForAllCredentials()
    {
        List<CredentialLookupDto> credentials = proxy.Credential_RetrieveAll();
        var optimizedCred = from c in credentials
                            select new
                            {
                                Name = c.Name,
                                Id = c.CredentialId,
                                Selected =
                                SelectedQualification != null && SelectedQualification.Credentials != null &&
                                SelectedQualification.Credentials.Any(p => p.CredentialId == c.CredentialId)
                            };

        this.JsonAllCredentials = JsonConvert.SerializeObject(optimizedCred);
    }

查看:

<div>
    <table>
        <tr>
            <td class="fieldName_td">
                @Html.Label("Available Credentials")
            </td>
            <td class="fieldData_td">
                <select data-bind="foreach: $root.AllCredentials" multiple="multiple" name="ddallcredentials" id="allCredentials">
                    <!-- ko if: !Selected -->
                    <option data-bind="text:Name,value:Id"></option>
                    <!-- /ko -->
                </select>
            </td>
        </tr>
    </table>
</div>

<div>
    <table>
        <tr>
            <td class="fieldName_td">
                @Html.Label("Selected Credentials")
            </td>
            <td class="fieldData_td">
                <select data-bind="foreach: $root.AllCredentials" multiple="multiple" name="ddSelectedCredentials" id="selectedCredentials">
                    <!-- ko if: Selected -->
                    <option data-bind="text:Name,value:Id"></option>
                    <!-- /ko -->
                </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>

}

视图模型:

///<reference path="~/Scripts/jquery-1.9.1.js" />
///<reference path="~/Scripts/knockout-2.2.1.js" />
///<reference path="~/Scripts/knockout.mapping-latest.js" />

var TestNWJS = TestNWJS || {};

TestNWJS.QualificationList = (function () {

//private functions
function CreateQualificationModel(allCredentialsList) {
    TestNWJS.QualificationList.ViewModel = {};
    TestNWJS.QualificationList.ViewModel.AllCredentials = ko.observableArray(allCredentialsList).extend({ notify: 'always' });
}

function toggleselected(array,id) {
    var credential = ko.utils.arrayFirst(array, function (credential) {
        var stringToInt = parseInt(id);
        return credential.Id === stringToInt;
    });

    if (credential.Selected == false) {
        credential.Selected = true;
    }
    else {
        credential.Selected = false;
    }
    return credential;
}

//public function
return {
    Init: function (allCredentialsList) {

        CreateQualificationModel(allCredentialsList);


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

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

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

})();

同样,只是为了澄清,初始列表正确加载。这个问题是当我想要双击一个项目以触发&#34;切换选择&#34;功能(双击触发器工作),该功能无法正常工作。它返回&#34;凭证&#34;的空值,这意味着我的ko.utils.arrayFirst实现不正确。还存在与绑定相关的其他问题。最后,当我传入原始数据时,我能够使一切正常工作&#34; allCredentialsList&#34;而不是&#34; TestNWJS.QualificationList.ViewModel.AllCredentials&#34;。我之所以这样做是因为&#34; TestNWJS.QualificationList.ViewModel.AllCredentials&#34;是可观察的,从而在属性发生变化时触发视图更新(在这种情况下,双击时为&#34; Selected&#34;属性)。

1 个答案:

答案 0 :(得分:3)

我可能会错过一些东西,因为我现在没有时间完全测试它,但是,是的,你错过了一些东西。 您正在尝试使用live函数中的jQuery通过DOM更新viewModel,从而绕过Knockout MVVM逻辑。

选项绑定

事实上,Knockout还有options binding专门用于此类任务。 来自文档的改编示例:

<select data-bind="options: myOptionsList,
                       optionsText: 'countryName',
                       value: myValueBinding,
                       optionsCaption: 'Choose...'"></select>

如果您的viewmodel中有value可观察对象,则myValueBinding绑定会跟踪所选选项。
options绑定在您的视图模型中为observableArrayvalue绑定将从该绑定更新。

正确使用ko.utils.arrayFirst

arrayFirst实用程序函数返回函数计算结果为true的第一个匹配项。在你的代码片段中,这是不可能的:在你的toggleSelected函数中,你只传递一个数组而没有id,所以它永远不会评估为true(id = undefined)。

   var credential = ko.utils.arrayFirst(array, function (credential) {
        var stringToInt = parseInt(id);
        return credential.Id === stringToInt;
    });

使用而不是绕过Knockout(事件处理)

不是将this.value传递给toggleSelected(对Knockout没有意义,除非你打算使用DOM作为数据通信层而不是你的viewModel。所以你应该访问选项的绑定数据ko.dataFor(),例如

$("#selectedCredentials").live('dblclick', function (e) {
   var id = ko.dataFor(this).ID, array = ko.contextFor(this).$root.AllCredentials;
   // if you have properly stored your arrays and properties, this will work:
   toggleselected(array,id);
});

如果你在select上绑定了这个,那就更容易了:

<select data-bind="event: { dblclick: toggleSelected }"></select>

您甚至不需要在视图中传递参数,因为eventdata会自动作为参数传递。在您的toggleSelected功能中,您有:

TestNWJS.QualificationList.ViewModel.toggleSelected = function(data, e) {
   var id = data.ID, array = TestNWJS.QualificationList.ViewModel.AllCredentials;
   // if you have properly stored your arrays and properties, this will work:
   toggleselected(array,id);
});