Warning: The magic method SFML_Singleton::__wakeup() must have public visibility in /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php on line 72

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/rest-api/class-wp-rest-server.php on line 1642

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/rest-api/class-wp-rest-server.php on line 1642

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/rest-api/class-wp-rest-server.php on line 1642

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/rest-api/class-wp-rest-server.php on line 1642

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/rest-api/class-wp-rest-server.php on line 1642

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/rest-api/class-wp-rest-server.php on line 1642

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/rest-api/class-wp-rest-server.php on line 1642

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/rest-api/class-wp-rest-server.php on line 1642
{"id":256,"date":"2018-05-16T12:30:25","date_gmt":"2018-05-16T18:30:25","guid":{"rendered":"http:\/\/www.munderwood.ca\/?p=256"},"modified":"2018-05-16T12:30:25","modified_gmt":"2018-05-16T18:30:25","slug":"adding-vue-reactivity-to-js-data-relationships","status":"publish","type":"post","link":"https:\/\/www.munderwood.ca\/index.php\/2018\/05\/16\/adding-vue-reactivity-to-js-data-relationships\/","title":{"rendered":"Adding Vue reactivity to js-data relationships"},"content":{"rendered":"

While attempting to have Vue<\/a> components react to changes in my js-data<\/a> model instances and their relationships, I found a great post from Caleb Roseland<\/a> with an accompanying code example<\/a>. They detail how to make model properties reactive in Vue, without overriding js-data’s own reactivity. What they don’t discuss is how to make Vue react to changes in the set of models associated with another through a relationship.<\/p>\n

For example, if you have a Post that hasMany Comments, and a component on your page that iterates over post.comments<\/span>\u00a0, then the comments list still won\u2019t change in Vue when it does in js-data.<\/p>\n

Summary \/ tl;dr<\/h2>\n

By adding a boolean option to specify that some js-data relations should be made reactive, and defining a\u00a0VueReactiveRecord<\/span>\u00a0class that enables Vue reactivity on those relations, we can use related models in a Vue template and have them update when the data store changes. Check out this gist<\/a> to see an example of the final result.<\/p>\n

Making relationships reactive<\/h2>\n

My first attempt was to hew as closely to Caleb’s example as possible, automatically discovering every relationship and making them all reactive. Unfortunately the resulted in neither side of the relationship working correctly. Even though a post<\/span>\u00a0\u00a0and some associated comment<\/span>\u00a0\u00a0records were in the store, post.comments<\/span>\u00a0\u00a0was empty as was each comment.post<\/span>\u00a0. At first I wondered if there would be an infinite loop problem, of A reacting to B reacting to A reacting to B reacting … . Instead it appeared as if neither side was able to react even once, and the models were never connected to each other. Either way, I didn’t debug that issue and instead set up a method by which relationships would only become reactive if explicitly told to do so.<\/p>\n

Opting in<\/h3>\n

When defining the js-data mappers, I included a new optional property named vueReactive<\/span>\u00a0\u00a0to the relationships that I explicitly wanted to make reactive within Vue components. For example, it\u2019s much more likely that a new comment will be added to an existing post than that the post a comment was for will become a different one, so we can specify that the hasMany<\/span>\u00a0from posts to comments should be reactive, but leave the belongsTo<\/span>\u00a0 from comments to posts alone:<\/p>\n

defineMapper('post', ...\r\n  ...\r\n  relations: {\r\n    hasMany: {\r\n      comment: {\r\n        foreignKey: 'post_id',\r\n        localField: 'comments',\r\n        vueReactive: true,\r\n      },\r\n    },\r\n  },\r\n);<\/pre>\n

With that in place, I updated Caleb’s\u00a0ViewReactiveRecord<\/span>\u00a0class:<\/p>\n

class ViewReactiveRecord extends Record {\r\n  ...\r\n  \/\/ Add Vue reactivity to relationships as well, when their definitions say to.\r\n  const relationsByType = this._mapper().relations;\r\n  \/\/ e.g. relationsByType = { hasMany: {...}, belongsTo: {...} }\r\n  for (const relType in relationsByType) {\r\n    const relations = relationsByType[relType];\r\n    \/\/ e.g. relations is all hasMany relationships, or all belongsTo ones.\r\n    for (const relName in relations) {\r\n      const relation = relations[relName];\r\n      \/\/ Now relation is the actual definition of a single relationship on the mapper\r\n      if (!relation.vueReactive) { continue; }\r\n      const key = relation.localField;\r\n      Vue.util.defineReactive(this, key, this[key]);\r\n    }\r\n  }\r\n  ...\r\n}<\/pre>\n

Using the reactive relationships<\/h2>\n

Now we can have a Vue template that does something such as this:<\/p>\n

<div>\r\n  <h1>{{ user.name }}<\/h1>\r\n  <h2>Post titles<\/h2>\r\n  <p v-for=\"post in user.posts\" :key=\"post.id\">\r\n    {{ post.title }}\r\n  <\/p>\r\n<\/div>\r\n<\/pre>\n

and know that if the set of associated posts in the js-data store changes, the list of titles displayed will reactively update accordingly.<\/p>\n

 <\/p>\n","protected":false},"excerpt":{"rendered":"

While attempting to have Vue components react to changes in my js-data model instances and their relationships, I found a great post from Caleb Roseland with an accompanying code example. They detail how to make model properties reactive in Vue, without overriding js-data’s own reactivity. What they don’t discuss is how to make Vue react … [Read more…]<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[13],"tags":[17,19],"_links":{"self":[{"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/posts\/256"}],"collection":[{"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/comments?post=256"}],"version-history":[{"count":4,"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/posts\/256\/revisions"}],"predecessor-version":[{"id":260,"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/posts\/256\/revisions\/260"}],"wp:attachment":[{"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/media?parent=256"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/categories?post=256"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.munderwood.ca\/index.php\/wp-json\/wp\/v2\/tags?post=256"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}