<br />
<b>Warning</b>:  The magic method SFML_Singleton::__wakeup() must have public visibility in <b>/home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php</b> on line <b>72</b><br />
{"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":"<p>While attempting to have <a href=\"https:\/\/vuejs.org\/\">Vue<\/a> components react to changes in my <a href=\"http:\/\/www.js-data.io\/\">js-data<\/a> model instances and their relationships, I found a great <a href=\"https:\/\/medium.com\/@calebroseland\/state-management-in-vue-525ffe12ad81\">post from Caleb Roseland<\/a> with an accompanying <a href=\"https:\/\/gist.github.com\/calebroseland\/2fa37abdb5560739b3b4b901382b0a90\">code example<\/a>. They detail how to make model properties reactive in Vue, without overriding js-data&#8217;s own reactivity. What they don&#8217;t discuss is how to make Vue react to changes in the set of models associated with another through a relationship.<\/p>\n<p>For example, if you have a Post that hasMany Comments, and a component on your page that iterates over <span class=\"lang:default decode:true crayon-inline \">post.comments<\/span>\u00a0, then the comments list still won\u2019t change in Vue when it does in js-data.<\/p>\n<h2>Summary \/ tl;dr<\/h2>\n<p>By adding a boolean option to specify that some js-data relations should be made reactive, and defining a\u00a0<span class=\"lang:default decode:true  crayon-inline\">VueReactiveRecord<\/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 <a href=\"https:\/\/gist.github.com\/mikeu\/441fbae43f2ec629f13ff2d5abde68f5\">this gist<\/a> to see an example of the final result.<\/p>\n<h2>Making relationships reactive<\/h2>\n<p>My first attempt was to hew as closely to Caleb&#8217;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 <span class=\"lang:default decode:true crayon-inline \">post<\/span>\u00a0\u00a0and some associated <span class=\"lang:default decode:true  crayon-inline \">comment<\/span>\u00a0\u00a0records were in the store, <span class=\"lang:default decode:true  crayon-inline \">post.comments<\/span>\u00a0\u00a0was empty as was each <span class=\"lang:default decode:true  crayon-inline \">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 &#8230; . 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&#8217;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<h3>Opting in<\/h3>\n<p>When defining the js-data mappers, I included a new optional property named <span class=\"lang:default decode:true  crayon-inline \">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 <span class=\"lang:default decode:true  crayon-inline \">hasMany<\/span>\u00a0from posts to comments should be reactive, but leave the <span class=\"lang:default decode:true  crayon-inline \">belongsTo<\/span>\u00a0 from comments to posts alone:<\/p>\n<pre class=\"lang:js decode:true\" title=\"Defining a mapper with a relationship that should be reactive in Vue\">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<p>With that in place, I updated Caleb&#8217;s\u00a0<span class=\"lang:default decode:true  crayon-inline\">ViewReactiveRecord<\/span>\u00a0class:<\/p>\n<pre class=\"lang:js decode:true\" title=\"Adding relationship reactivity to ViewReactiveRecords\">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<h2>Using the reactive relationships<\/h2>\n<p>Now we can have a Vue template that does something such as this:<\/p>\n<pre class=\"lang:default decode:true\" title=\"Using reactive relationships in a Vue template\">&lt;div&gt;\r\n  &lt;h1&gt;{{ user.name }}&lt;\/h1&gt;\r\n  &lt;h2&gt;Post titles&lt;\/h2&gt;\r\n  &lt;p v-for=\"post in user.posts\" :key=\"post.id\"&gt;\r\n    {{ post.title }}\r\n  &lt;\/p&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<p>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>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&#8217;s own reactivity. What they don&#8217;t discuss is how to make Vue react &#8230; <span class=\"more\"><a class=\"more-link\" href=\"https:\/\/www.munderwood.ca\/index.php\/2018\/05\/16\/adding-vue-reactivity-to-js-data-relationships\/\">[Read more&#8230;]<\/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}]}}