Skip to content

Instantly share code, notes, and snippets.

@mikeu
Forked from calebroseland/vue-js-data-reactivity.js
Last active January 5, 2019 21:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikeu/441fbae43f2ec629f13ff2d5abde68f5 to your computer and use it in GitHub Desktop.
Save mikeu/441fbae43f2ec629f13ff2d5abde68f5 to your computer and use it in GitHub Desktop.
import Vue from 'vue'
import {DataStore, Record} from 'js-data'
// Define a base class that enables property-level vue reactivity and, optionally does so at the relationship-level.
export class VueReactiveRecord extends Record {
constructor (...args) {
// Among other things, this will apply js-data schema if configured to do so; be sure to do `track: true`.
super(...args);
// Apply vue reactivity.
for (let key in this) {
Vue.util.defineReactive(this, key, this[key]);
}
// Add Vue reactivity to relationships as well, when their definitions say to.
const relationsByType = this._mapper().relations;
// e.g. relationsByType = { hasMany: {...}, belongsTo: {...} }
for (const relType in relationsByType) {
const relations = relationsByType[relType];
// e.g. relations is all hasMany relationships, or all belongsTo ones.
for (const relName in relations) {
const relation = relations[relName];
// Now relation is the actual definition of a single relationship on the mapper.
// If it has not been explicitly marked for Vue reactivity, move to the next.
if (!relation.vueReactive) { continue; }
const key = relation.localField;
Vue.util.defineReactive(this, key, this[key]);
}
}
// Re-apply the js-data schema.
this._mapper().schema.apply(this) ;
}
};
// Create related record classes that inherit this.
export class User extends VueReactiveRecord {};
export class Post extends VueReactiveRecord {};
// Create a store to which we'll add some mappers based on these classes.
export const store = new DataStore();
export const userMapper = store.defineMapper('user', {
idAttribute: 'id',
endpoint: 'users',
recordClass: User,
schema: {
track: true,
properties: {
id: { type: 'number' /* , or maybe... type: 'string', format: 'uuid' */ },
name: { type: 'string' },
},
},
relations: {
hasMany: {
post: {
localKeys: 'postIds',
localField: 'posts',
vueReactive: true,
},
},
},
});
export const postMapper = store.defineMapper('post', {
idAttribute: 'id',
endpoint: 'posts',
recordClass: Post,
schema: {
track: true,
properties: {
id: { type: 'number' /* , or maybe... type: 'string', format: 'uuid' */ },
title: { type: 'string' },
},
},
relations: {
belongsTo: {
user: {
localKeys: 'userId',
localField: 'user',
},
},
},
});
// Now the properties of users and posts will be reactive in Vue, as will the set of posts
// associated with each user.
// For a detailed explaination about the properties, see here: https://medium.com/p/525ffe12ad81#c925
// A discussion of the addition of the relationship reactivity is here:
// https://www.munderwood.ca/index.php/2018/05/16/adding-vue-reactivity-to-js-data-relationships/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment