Javascript 在donejs中正确建模MVVM应用程序 我所做的

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中检索元素并相应地列出它们 因此,每个联系人都有电子邮件

我在donejs中创建了一个组件,然后使用以下命令创建了两个超级模型
contact
email

  • donejs添加组件联系人组件联系人组件
  • donejs添加超级模特联系人
  • donejs添加超级模特电子邮件
有一个API(feathers+mongodb)提供联系人和电子邮件。每封电子邮件都有一个
联系人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;