Knockout JS ObservableArray具有多对多关系 [英] Knockout JS ObservableArray with many-to-many relationships

查看:75
本文介绍了Knockout JS ObservableArray具有多对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Knockout.js创建一个访客列表应用程序,到目前为止,事情正在顺利进行。但是我有一个最佳实践问题。我的应用程序有几种不同类型的对象:其中包含guest和tags。客人可以拥有多个标签,标签可以包含多个客人。在应用程序的不同位置,我需要单独显示两个数组。例如,我有一个访客视图,其中可以看到所有访客及其相关标签,我还有一个标签视图,其中可以看到所有标签及其关联的客人。目前,我为客户添加标签的代码如下所示:

  var tag = function(opts) {
this.guests = ko.observableArray()

//这里的其他标签代码...
}

var guest = function(opts) ){
this.tags = ko.observableArray()
//这里的其他访客代码...

var self =这个

这个。 addTag = function(tag){
self.tags.push(tag)
tag.guests.push(self)
}
}

我知道除了独立更新每个observableArray之外,必须有更好的方法在Knockout中进行这种多对多关系。这也导致了一种递归的app结构,其中guest有一个标签属性/数组,其中包含一个标签,该标签包含一个guest属性/数组,其中包含一个guest,它有一个标签属性......你得到了图片。 / p>

现在,ViewModel结构如下:

   -  Parent对象
- 来宾ObservableArray
- 访客对象
- 标签对象作为Guest的属性
- 标签ObservableArray
- 标签对象
- 访客对象作为属性标签

所以我想我的问题有两个:1)有没有更好的方法来构建我的ViewModel避免递归数组? 2)如何更好地使用Knockout.js以干燥方式更新我的ViewModel,而不是分别更新标签数组和来宾数组?谢谢!

解决方案

可能有其他方法可以做到这一点,但这种方法具有非常小的重复,而不会牺牲正确的建模。服务器在生成这种格式的数据时应该没有问题。



这是一个(粗略的样式)小提琴。请注意,单击标记或来宾将导致其下方的选择更新(默认选择第一个)。



基本上,按ID存储关系,并使用计算数组来表示关联。这是一个基本的viewmodel:

  var ViewModel = function(guests,tags){
var self = this;
self.guests = ko.observableArray(
ko.utils.arrayMap(guests,function(i){return new Guest(i);}
));
self.tags = ko.observableArray(
ko.utils.arrayMap(tags,function(i){return new Tag(i);}
));

self.selectedGuest = ko.observable(self.guests()[0]);
self.selectedTag = ko.observable(self.tags()[0]);

self.guestTags = ko.computed(function(){
return ko.utils.arrayFilter(self.tags(),function(t){
return self.selectedGuest ()。tags()。indexOf(t.id())> -1;
});
});

self.tagGuests = ko.computed(function(){
return ko.utils.arrayFilter(self.guests(),function(g){
return self.selectedTag ()。gests()。indexOf(g.id())> -1;
});
});
};



UPDATE



所以我做了一个新小提琴演示不同类型的映射,但此代码可以轻松与上述视图模型共存;它唯一的单独示范。它提供了一般查找,而不是处理选择,因此任何代码都可以使用它。下面是Tags中的HTML(来宾是对称的),以及添加到viewmodel的 guestMap 函数。



您现在会注意到名称输入,因此您可以更改名称并查看所有绑定保持最新。让我知道你的想法:

 < div>标签
< ul data-bind =foreach:标签>
< li>
< input data-bind =value:name,valueUpdate:'afterkeydown'/>
< / br>< span>标签< / span>
< ul data-bind =foreach:guests>
< li>< span data-bind =text:$ parents [1] .guestMap($ data).name()>< / span>< / li>
< / ul>
< / li>
< / ul>
< / div>






  self .guestMap = function(id){
return ko.utils.arrayFirst(self.guests(),function(g){
return id == g.id();
}) ;
};


I am creating a guest list app using Knockout.js, and so far things are going swimmingly. However I have a best-practices question. My app has several different types of objects: guests and tags among them. Guests can have multiple tags, and tags can have multiple guests. At different points in the app, I need to display both arrays individually. For example, I have a "Guests" view where one can see all the guests along with their associated tags, and I also have a "Tags" view where one can see all tags and their associated guests. At present, the code for me to add a tag to a guest looks something like this:

var tag = function(opts) {
  this.guests = ko.observableArray()

  // Other tag code here...
}

var guest = function(opts) {
  this.tags = ko.observableArray()
  // Other guest code here...

  var self = this

  this.addTag = function(tag) {
    self.tags.push(tag)
    tag.guests.push(self)
  }
}

I know there must be a better way of doing this kind of many-to-many relationship in Knockout other than updating each observableArray independently. This also leads to a kind of recursive app structure where a guest has a tags property/array which contains a tag, which has a guest property/array which contains a guest, which has a tags property... you get the picture.

Right now, the ViewModel structure is like so:

- Parent Object
  - Guests ObservableArray
    - Guest Object
      - Tag Object as property of Guest
  - Tags ObservableArray
    - Tag Object
      - Guest Object as property of Tag

So I guess my question is twofold: 1) Is there a better way to structure my ViewModel to avoid recursive arrays? and 2) how can I better use Knockout.js to update my ViewModel in a DRY manner, rather than updating both the tags array AND the guests array individually? Thanks!

解决方案

There are probably other ways to do this, but this method has pretty minimal duplication, without sacrificing proper modeling. A server should have no trouble generating the data in this format.

Here it is in a (crudely styled) fiddle. Note, clicking a tag or guest will cause the selections below it to update (the first is selected by default).

Basically, store the relationships by id, and use computed array's to represent associations. Here is a basic viewmodel:

var ViewModel = function(guests, tags) {
    var self = this;
    self.guests = ko.observableArray(
        ko.utils.arrayMap(guests, function(i){ return new Guest(i); }
    ));
    self.tags= ko.observableArray(
        ko.utils.arrayMap(tags, function(i){ return new Tag(i); }
    ));

    self.selectedGuest = ko.observable(self.guests()[0]);
    self.selectedTag = ko.observable(self.tags()[0]);

    self.guestTags = ko.computed(function() {
        return ko.utils.arrayFilter(self.tags(), function(t) {
            return self.selectedGuest().tags().indexOf(t.id()) > -1;
        });        
    });

    self.tagGuests = ko.computed(function() {
        return ko.utils.arrayFilter(self.guests (), function(g) {
            return self.selectedTag().guests().indexOf(g.id()) > -1;
        });        
    });
};

UPDATE

So I have made a new fiddle to demonstrate a different kind of mapping, but this code could easily co-exist with the above viewmodel; its only seperate for demonstration. Instead of working off selection, it offers a general lookup, so that any code can consume it. Below is the HTML from Tags (guests is symmetrical), and the guestMap function that was added to the viewmodel.

You will note that the names are inputs now, so you can change the names and watch all the bindings stay up to date. Let me know what you think:

<div>Tags
    <ul data-bind="foreach: tags">
        <li>
            <input data-bind="value: name, valueUpdate: 'afterkeydown'" />
            </br><span>Tags</span>
            <ul data-bind="foreach: guests">
                <li><span data-bind="text: $parents[1].guestMap($data).name()"></span></li>
            </ul>
        </li>
    </ul>
</div>


self.guestMap = function(id) {
        return ko.utils.arrayFirst(self.guests(), function(g) {
            return id == g.id();
        });
    };   

这篇关于Knockout JS ObservableArray具有多对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆