0

我的背景主要是 asp.net/c#,而且我是 Durandal/Knockout 的新手。我正在尝试构建一个视图以显示对象列表,并在选择一个项目后显示所选项目的数据。我的问题是,无论选择什么项目,返回的数据始终是最后一项的数据。

下面是我的看法,

...未显示标记

<div data-bind="visible: convenios().length > 0" style="height:30px">
Pesquisa retornou <span  data-bind="text: convenios().length"></span> conveniados.
</div>
<div class="row-fluid">
    <section  class="grd-convenio" data-bind="foreach: convenios" style="width:25%; height:300px; overflow-y: scroll">
        <article>
        <div class="grd-convenio-detalhe"  title="Clique para alterar">
            <span class="grd-convenio-nome" data-bind="text: nome"></span>
            <span class="grd-convenio-id" data-bind="text: id"></span><br/>
            <span class="grd-convenio-cidade" data-bind="text: cidade"></span>
            <span class="grd-convenio-ativo" data-bind="text: servicosativos"></span>
        </div>
        </article>        

    </section>
</div>

和我的视图模型的一部分:

var convenio = function (id, nome, cidade, cnpjcpf, servicosativos) {

    self = this;

    self.idformatado = ko.observable("[" + id + "]");
    self.id = ko.observable(id);
    self.nome = ko.observable(nome);
    self.cidade = ko.observable(cidade);
    self.cnpjcpf = ko.observable(cnpjcpf);
    self.servicosativos = ko.observable(servicosativos);
    self.estiloativo = ko.computed(function () {
        if (self.servicosativos() > 0)
            return 'grd-convenio-detalhe-ativo';
        else
            return 'grd-convenio-detalhe-inativo';
    });
    self.convenioselecionado = ko.observable("");
    return self;

};

var convenios = ko.observableArray([]);
var tamanho = ko.observable("0");
var convenioselecionado = ko.observable("");
var pesquisacodigo = ko.observable("");
var pesquisanome = ko.observable("");
var pesquisacidade = ko.observable("");

var filtrar = function () {

 ... Retrieve data from Database and pushes data into convenios observablearray
            $.each(resultado.pesquisa.retorno, function (i, item) {
                convenios.push(new convenio(item.idconveniado, item.nome, item.cidade, item.cnpjcpf, item.servicosativos));
            });


};

alterarCadastro = function (selecionado) {
    if (selecionado && selecionado.id()) {
        alert(selecionado.nome());
    }
};


var viewAttached = function(view) {
    bindEventToList(view, '.grd-convenio-detalhe', alterarCadastro);
};

var bindEventToList = function (rootSelector, selector, callback, eventName) {
    var eName = eventName || 'click';
    $(rootSelector).on(eName, selector, function () {
        var selecionado = ko.dataFor(this);
        callback(selecionado);
        return false;
    });
};


return {
    convenios: convenios,
    filtrar: filtrar,
    tamanho: tamanho,
    pesquisacodigo: pesquisacodigo,
    pesquisanome: pesquisanome,
    pesquisacidade: pesquisacidade,
    alterarCadastro: alterarCadastro,
    displayName: 'Convênio',
    viewAttached: viewAttached

}

});});

该视图按预期显示,但是当我选择任何项目时,bindEventTolist 函数中返回的数据(ko.datafor)始终是最后一个项目的数据。我究竟做错了什么?这是处理这类应用程序的好方法吗?TIA。

4

2 回答 2

0

如果您想在单击项目时显示新视图,您可以使用 splat 将新的项目视图路由添加到 durandal 路由器,例如 router.mapNav('item/:id'),然后更改您的标记以包含链接到新路线。像这样的东西:

<section  class="grd-convenio" data-bind="foreach: convenios" style="width:25%; height:300px; overflow-y: scroll">
        <article>
        <a class="grd-convenio-detalhe" title="Clique para alterar" data-bind="attr: {href: '#/item/' + $data.id}">
            <span class="grd-convenio-nome" data-bind="text: nome"></span>
            <span class="grd-convenio-id" data-bind="text: id"></span><br/>
            <span class="grd-convenio-cidade" data-bind="text: cidade"></span>
            <span class="grd-convenio-ativo" data-bind="text: servicosativos"></span>
        </a>
        </article>        

    </section>

我个人更喜欢这种解决方案,因为它遵循单一责任原则,将所有项目特定逻辑交给新路由的视图模型。

于 2013-06-26T14:17:48.203 回答
0

http://jsfiddle.net/yQgAm/8/

我已经更新了你的小提琴,但花了相当长的时间:)

你让它变得比它需要的更困难,所以我试图在你的代码上添加一些标记,以显示我所做的更改,如果我能全部记住的话。我回去做的最重要的事情之一是使用 camelCase 重命名您的方法,以确保不存在拼写错误。接下来,我从您的 viewModel 中取出了 parter 函数,因为它是一个独立的类,不需要在其中定义。

然后我给你的视图模型一个带有 self = this 的范围。这只是让视图模型知道它内部的任何东西都有一个自我。前任被定义为这个范围的一部分。

接下来,由于我不是 jsFiddle 大师,而您试图同时使用 jQuery ($.each) 和 KnockOut (ko.),我将 $.each 替换为一个名为 ko.utils.arrayForEach() 的 KnockOut 实用程序,它基本上是相同的事物。

我怀疑当您在代码中使用 $.each 执行 forEach 循环时,您将值设置为 selectedPartner 的值,然后当您执行 showSelectedPartner 时,它只是显示您在 forEach 循环中设置的最后一个值。

如果您想获取一些原始代码并重新使用它,我建议做的最重要的事情是删除对这么多库的依赖。你会因为(假设)同时学习 jQuery、Knockout 和 Durandal 而试图理解基本的 JavaScript 而感到困惑。一次迈出一步,否则你最终会得到很多代码,这些代码会做一些你不能 100% 确定原因的事情。

function partner(id, name) {
    var self = this;
    self.id = ko.observable(id);
    self.pName = ko.observable(name);
}

function viewmodel() {
   var self = this;
   self.initialdata = ko.observableArray([
       { id: 1, name: "name1" } ,
       { id: 2, name: "name2" } ,
       { id: 3, name: "name3" } ,
       { id: 4, name: "name4" } ,
   ]);

    self.partners = ko.observableArray();  
    self.selectedPartner = ko.observable();  

    self.loadData = function () {
        self.partners([]);
        ko.utils.arrayForEach(self.initialdata(), function (item) {
            self.partners.push(new partner(item.id, item.name));
        });
    };
    self.showSelectedPartner = function (selected) {
        alert(selected.pName());
    }
}

ko.applyBindings(new viewmodel());

还有你的看法

<section>
    <div>
        <button data-bind="click: loadData">Load Data</button>
    </div>
    <div data-bind="visible: partners().length > 0" >Query returned <span data-bind="text: partners().length"></span> records</div>
    <div>
        <section data-bind="foreach: partners" >
            <article>
                <div title="Click to Update" data-bind="click: $parent.showSelectedPartner"> <span data-bind="text: id"></span>  
 <span data-bind="text: pName"></span>
                </div>
            </article>
        </section>
    </div>
</section>

我在您的 div 上放置了一个单击绑定,因为 viewAttached 是一种 Durandal 方法,它让路由器知道视图已完成附加并且它可以做一些事情。您创建的 bindToEventList 只是说如果单击了您命名的该类的任何内容,就会触发该方法。这一切都很好用而且效率更高,但如果你只是在学习 KnockOut,我建议你先学习绑定是如何工作的。

于 2013-06-27T01:15:40.370 回答