【问题标题】:How to get selected item data?如何获取所选项目数据?
【发布时间】:2013-06-27 09:22:20
【问题描述】:

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

【问题讨论】:

  • 返回最后一项的数据是什么意思?您的警报设置为显示单击的任何内容,但不会对该数据执行任何操作。
  • @kadumel 这是问题所在。警报始终显示 last 项的属性“nome”,而不是实际单击的项的属性“nome”。我需要获取单击项目的 id 以显示其数据,但由于我总是得到最后一个项目的数据,所以我还没有做任何事情。我只是显示返回的“名称”的警报。
  • 由于语言差异,遵循代码有点困难,但出于所有意图和目的,您的 alert() 应该显示当前对象。您能否创建一个重现此问题的小提琴,以便我们查看后台发生的情况?
  • 对不起@kadumel。尽管 js 代码没问题,但我无法使小提琴工作。你知道,我对所有这些工具都是新手。但是如果你想看看 [fiddle] (jsfiddle.net/zenute/yQgAm/4)。我相信它会帮助你理解。我点击的任何项目,警报总是返回'name4'。
  • @kadumel ,我在小提琴 [new fiddle] (jsfiddle.net/zenute/yQgAm/6) 中做了一个小改动

标签: knockout.js


【解决方案1】:

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

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

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

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

接下来,由于我不是 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,我建议你先学习绑定是如何工作的。

【讨论】:

  • 非常感谢。我非常感谢您的提示和建议。使用您的 jsFiddle,我设法修复并运行了我的原始代码。我打算在不久的将来在 Durandal/Knockout 中开发应用程序,我需要快速学习它。我会在这个主题上做更多的阅读。谢谢@Kadumel。
  • 我确实理解了 Durandal 代码并且对它感到满意。我只是不知道应该使用哪个,单击绑定或 Durandal 事件处理程序。顺便说一句,真正修复我的原始代码的是将 initialData 声明为可观察数组。再次感谢您。
  • 酷它回答了你的问题,你可以接受答案。祝你好运
【解决方案2】:

如果您想在单击项目时显示新视图,您可以使用 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>

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

【讨论】:

  • 谢谢@jaq316。它可能是创建一个视图来处理该项目的解决方案,但我真正想要找到的是一种将对象“convenio”绑定到单击的元素的方法。 ko.dataFor(this);始终返回集合中的最后一个“convenio”对象,而不是单击的对象。
猜你喜欢
  • 2019-02-18
  • 1970-01-01
  • 1970-01-01
  • 2018-04-22
  • 2013-08-06
  • 1970-01-01
  • 1970-01-01
  • 2018-11-11
  • 2013-05-31
相关资源
最近更新 更多