Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 多对多关系的淘汰赛_Javascript_Mvvm_Knockout.js_Knockout Mapping Plugin - Fatal编程技术网

Javascript 多对多关系的淘汰赛

Javascript 多对多关系的淘汰赛,javascript,mvvm,knockout.js,knockout-mapping-plugin,Javascript,Mvvm,Knockout.js,Knockout Mapping Plugin,我正在使用Knockout.js创建一个来宾列表应用程序,目前一切进展顺利。然而,我有一个最佳实践问题。我的应用程序有几种不同类型的对象:访客和标签。来宾可以有多个标记,标记可以有多个来宾。在应用程序中的不同点,我需要分别显示两个阵列。例如,我有一个“来宾”视图,可以看到所有来宾及其关联的标签,我还有一个“标签”视图,可以看到所有标签及其关联的来宾。目前,我向来宾添加标记的代码如下所示: var tag = function(opts) { this.guests = ko.observab

我正在使用Knockout.js创建一个来宾列表应用程序,目前一切进展顺利。然而,我有一个最佳实践问题。我的应用程序有几种不同类型的对象:访客和标签。来宾可以有多个标记,标记可以有多个来宾。在应用程序中的不同点,我需要分别显示两个阵列。例如,我有一个“来宾”视图,可以看到所有来宾及其关联的标签,我还有一个“标签”视图,可以看到所有标签及其关联的来宾。目前,我向来宾添加标记的代码如下所示:

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)
  }
}
我知道一定有更好的方法在淘汰赛中实现这种多对多的关系,而不是独立更新每个可观察的array。这还导致了一种递归应用程序结构,其中来宾具有包含标记的标记属性/数组,该属性/数组包含来宾,该属性/数组具有标记属性。。。你明白了

现在,ViewModel结构如下所示:

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

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

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

在这里它是在一个(粗糙的风格)。注意,单击标记或来宾将导致其下面的选择更新(默认情况下选择第一个)

基本上,按id存储关系,并使用
computed
array来表示关联。以下是一个基本的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;
        });        
    });
};
更新 所以我做了一个例子来演示一种不同的映射,但是这段代码可以很容易地与上面的viewmodel共存;这是唯一一个单独的演示。它提供了一个通用的查找,而不是关闭选择,这样任何代码都可以使用它。下面是来自标记的HTML(来宾是对称的),以及添加到viewmodel的
guestMap
函数

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

<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>

我也有同样的问题。显示多对多相关内容。我必须做“网格”样式的显示,并且有一个更新机制

我最终复制了后端数据库中的结构。两个项目表,中间有联接表。从三个数组中取出数据,并不断更新“join”数组。下面是测试数据和我的测试结果

var items = [{name: "T1",id: 1}, {name: "T2",id: 2}, {name: "T3",id: 3}, {name: "T4",id: 4}];
var cats = [{catname: 'C1', catid: 1}, {catname: 'C2',catid: 2}, {catname: 'C3',catid: 3}, {catname: 'C4',catid: 4}];
var catsItems = [{catid:1,itemid:2},{catid:2,itemid:1},{catid:4,itemid:2},{catid:3,itemid:4},{catid:3,itemid:1},{catid:1,itemid:3},{catid:2,itemid:4}];


我不确定这个方法在处理大量数据时有多有效,但我做了我需要的事情。

我的答案有问题吗?如果你让我知道哪里不对,我可以试着改进它。嘿,泰尔修斯,我喜欢这个答案,这就是为什么我投了更高的票,但我觉得它没有完全解决结构问题。我同意保存ID和使用计算函数进行查找比保存完整对象更好,但是如果我使用了许多不同的来宾实例和标记实例,每个实例都需要能够循环它们各自的关联,那么在您的模型中如何做到这一点呢?目前看来,只有当我想一次循环一个对象时,你的答案才有效。对不起,如果我太挑剔了,这有点新。所以,我不完全确定你的意思。您想同时看到多个“SelectedTag”吗?顺便说一句,挑剔是好的。你有一个特别的问题,你需要帮助。是的,你可以这样说。我需要同时为每位客人提供“selectedTags”视图。不同之处在于,在您的模型中,我一次选择一个来宾或标记,因此您可以在父视图模型上进行“selectedGuests”和“selectedTags”。但是,如果我想一次显示多个客人,每个人都有自己的标签列表,并且一次显示多个标签,每个人都有自己的客人列表,那么我应该如何组织事情,以便能够轻松地更新这两个标签?谢谢是,这确实需要不同的viewmodel。我会给你做点东西的谢谢Tyrsius!最后一个问题:有没有办法存储数据以避免冗余?我的意思是,现在你在每个客人的标签上列出他们的每个标签,在每个标签上列出他们的每个客人。但这些数据是相同的;如果我想向其中一个来宾添加标记,我需要同时更新来宾数组和标记数组。有没有办法避免这种情况,这样我就可以只更新其中一个数组?再次感谢!嗯,这是我应该早点考虑的。我认为关系是分开的,这样客人就可以有一个标签,而不需要客人的标签。关系数据库解决方案在这里可能很好,实际上有一个tagGuest对象,它只存储了一个Id对数组。我会看看是否能想出一些方法来确保这个解决方案有效,但似乎效率很低,因为每次更改都会触发对重新计算相关元素的搜索。更好的(但更复杂的解决方案)应该将找到的关系缓存到索引结构中,因此每次更改只需要一个更有效的索引update@FrancescoAbbruzzese这是非常正确的,这都是非常即兴的,我相信有很多优化(或者直接更好的方法)存在。我很想看看你的解决方案。有各种各样的可能性,每个都有优点和缺点,例如:1)每个对象都有一个数组,其中包含它所关联的所有节点(在关系的两侧)。有两种方法addRelation(node1,node2)和deleteRelation(node1,node2)。添加、新节点和关系的处理非常精确,删除关系只需扫描两个数组……但是删除节点有一个
var items = [{name: "T1",id: 1}, {name: "T2",id: 2}, {name: "T3",id: 3}, {name: "T4",id: 4}];
var cats = [{catname: 'C1', catid: 1}, {catname: 'C2',catid: 2}, {catname: 'C3',catid: 3}, {catname: 'C4',catid: 4}];
var catsItems = [{catid:1,itemid:2},{catid:2,itemid:1},{catid:4,itemid:2},{catid:3,itemid:4},{catid:3,itemid:1},{catid:1,itemid:3},{catid:2,itemid:4}];