如何获取所选项目数据?

时间:2013-06-26 00:24:44

标签: knockout.js

我的背景主要是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>

和我的viewmodel的一部分:

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。

2 个答案:

答案 0 :(得分: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>

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

答案 1 :(得分:0)

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

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

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

然后我给你的视图模型一个范围self = this。这只是让视图模型知道其中的任何内容都是自我的。前身被定义为此范围的一部分。

接下来,由于我不是jsFiddle master并且你试图同时使用jQuery($ .each)和KnockOut(ko。),我将$ .each替换为一个名为ko.utils.arrayForEach()的KnockOut实用程序。是一回事。

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

如果您想要使用一些原始代码并重新使用它,我建议做的最重要的事情是删除对这么多库的依赖。在尝试理解基本JavaScript的同时,(假设)学习jQuery,Knockout和Durandal,你会让自己感到困惑。一步一步,或者你最终会得到很多代码,这些代码可以做你不能完全理解的事情。

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,我建议先学习绑定是如何工作的。