Javascript 在donejs中正确建模MVVM应用程序 我所做的
我在donejs中创建了一个组件,然后使用以下命令创建了两个超级模型Javascript 在donejs中正确建模MVVM应用程序 我所做的,javascript,node.js,mvvm,canjs,donejs,Javascript,Node.js,Mvvm,Canjs,Donejs,我在donejs中创建了一个组件,然后使用以下命令创建了两个超级模型contact和email: donejs添加组件联系人组件联系人组件 donejs添加超级模特联系人 donejs添加超级模特电子邮件 有一个API(feathers+mongodb)提供联系人和电子邮件。每封电子邮件都有一个联系人ID 该组件包括Contact模型,并处理诸如保存、创建新元素、删除元素之类的事情。当它与.stache文件结合使用时,它将成功地从API中检索元素并相应地列出它们 因此,每个联系人都有电子邮件
contact
和email
:
donejs添加组件联系人组件联系人组件
donejs添加超级模特联系人
donejs添加超级模特电子邮件
联系人ID
该组件包括Contact
模型,并处理诸如保存、创建新元素、删除元素之类的事情。当它与.stache
文件结合使用时,它将成功地从API中检索元素并相应地列出它们
因此,每个联系人都有电子邮件。由于每个联系人都有自己的电子邮件,contactComponent无法直接获取电子邮件,只能通过contact
元素
这就是我的设计问题开始的地方。
到目前为止,ContactComponent创建了一个viewmodel,用于处理联系人的处理方式。联系人模型处理API连接。这工作很好,可扩展且干净
但是每个联系人都需要一个新的模型来加载数据(电子邮件),然后我直接使用该模型来管理与电子邮件相关的所有逻辑。这确实可行,但让模型处理连接和viewmodel处理复杂交互似乎更适合MVVM设计模式
我想我不是第一个做这种类型数据建模的人,我认为一定有更好的解决方案,尤其是在处理大量关系和更复杂的关系时
我想我现在拥有的是这样的东西:
contactComponent.js
├── (includes) models/contact.js
│ ├── (includes) models/email.js
这就是我要找的(我可能错了)
旧文件
文件结构
contactComponent
├── contactComponent.js
├── contactComponent.stache
models
├── contact.js
├── email.js
contactComponent/contactComponent.js
/* contactComponent/contactComponent.js */
import Component from 'can/component/';
import Map from 'can/map/';
import 'can/map/define/';
import template from './contactComponet.stache!';
import Contact from '../models/contact.js';
export const ViewModel = Map.extend({
define: {
contactPromise: {
get: function() {
return Contact.getList({});
}
}
},
saveContact: function() {
// do some stuff
},
deleteContact: function() {
// do some stuff
}
});
export default Component.extend({
tag: 'contact-component',
viewModel: ViewModel,
template
});
contactComponent/contactComponent.stache
/* contactComponent/contactComponent.stache */
{{#if contactPromise.isResolved}}
{{#each contactPromise.value}}
Name: {{name}}
{{#if emailPromise.isResolved}}
Emails:
{{#each emailPromise.value}}
{{email}}
{{/each}}
{{/if}}
{{/each}}
{{/if}}
models/email.js
/* models/email.js */
import can from 'can';
import superMap from 'can-connect/can/super-map/';
import tag from 'can-connect/can/tag/';
import 'can/map/define/define';
export const Email = can.Map.extend({
define: {},
type: null,
email: null,
});
Email.List = can.List.extend({
Map: Email
}, {});
export const emailConnection = superMap({
url: '/api/modelEmail',
idProp: '_id',
Map: Email,
List: Email.List,
name: 'email'
});
tag('email-model', emailConnection);
export default Email;
这就是事情变得太复杂的原因:
models/contact.js
/* models/contact.js */
import can from 'can';
import superMap from 'can-connect/can/super-map/';
import tag from 'can-connect/can/tag/';
import 'can/map/define/define';
import Email from '../models/email.js';
export const Contact = can.Map.extend({
define: {
emailPromise: {
get: function() {
return Email.getList({ contactId: this.attr('id') });
}
}
},
name: null,
});
Contact.List = can.List.extend({
Map: Contact
}, {});
export const contactConnection = superMap({
url: '/api/modelContact',
idProp: '_id',
Map: Contact,
List: Contact.List,
name: 'contact'
});
tag('contact-model', contactConnection);
export default Contact;
没有一个正确的方法来回答你的问题,但让我描述一下我的工作 通常,模型关系是在模型级别定义的。据我所知,大多数ORM都是这样工作的(例如Mongoose和Sequelize)。我是一个喜欢双方都知道关系的人——例如,你的联系人模型知道它有很多电子邮件,而电子邮件模型知道它属于某个联系人。每种型号都可以独立使用,这意味着你不必在与联系人打交道时收到电子邮件,反之亦然 然后,模型可以公开用于检索相关数据的助手方法。因此,您的联系人模型可以实现诸如
getEmails()
,setEmails()
,addNewEmail()
,doSomethingUniqueWithEmails()等方法。您的电子邮件模型可以对getContact()
和setContact()
执行相同的操作。这些方法将处理实际的数据事务(进行AJAX调用)——因此,根据您的需要实现这一部分取决于您。例如,当您调用contact.setEmails([…])
时,联系人模型将在所有电子邮件上设置联系人ID,并为此调用EmailModel.save()
或其他方法
最后,您的viewModel将根据需要使用helper方法来处理业务。您的模型只关心关系以及如何将数据持久化到服务器。然后,viewModels将使用业务逻辑来确定如何以及何时创建、销毁数据等
希望有帮助
/* models/contact.js */
import can from 'can';
import superMap from 'can-connect/can/super-map/';
import tag from 'can-connect/can/tag/';
import 'can/map/define/define';
import Email from '../models/email.js';
export const Contact = can.Map.extend({
define: {
emailPromise: {
get: function() {
return Email.getList({ contactId: this.attr('id') });
}
}
},
name: null,
});
Contact.List = can.List.extend({
Map: Contact
}, {});
export const contactConnection = superMap({
url: '/api/modelContact',
idProp: '_id',
Map: Contact,
List: Contact.List,
name: 'contact'
});
tag('contact-model', contactConnection);
export default Contact;