Today I released the initial version of a Vue2Leaflet plugin to provide a simple wrapper of the polyline measurement tool as a Vue2Leaflet plugin, via the vue2-leaflet-polyline-measure component. Usage is simple:
<l-map> <l-polyline-measure :options="{ showUnitControl: true }" position="bottomright"/> <!-- other map components --> </l-map>
The options object is passed directly to the underlying library, so can be any of the polyline measurement options. The position parameter places the control in a corner of the map based on the available Leaflet control options.
]]>For example, if you have a Post that hasMany Comments, and a component on your page that iterates over post.comments , then the comments list still won’t change in Vue when it does in js-data.
By adding a boolean option to specify that some js-data relations should be made reactive, and defining a VueReactiveRecord class 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 to see an example of the final result.
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 and some associated comment records were in the store, post.comments was empty as was each comment.post . 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.
When defining the js-data mappers, I included a new optional property named vueReactive to the relationships that I explicitly wanted to make reactive within Vue components. For example, it’s 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 from posts to comments should be reactive, but leave the belongsTo from comments to posts alone:
defineMapper('post', ... ... relations: { hasMany: { comment: { foreignKey: 'post_id', localField: 'comments', vueReactive: true, }, }, }, );
With that in place, I updated Caleb’s ViewReactiveRecord class:
class ViewReactiveRecord extends Record { ... // 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 (!relation.vueReactive) { continue; } const key = relation.localField; Vue.util.defineReactive(this, key, this[key]); } } ... }
Now we can have a Vue template that does something such as this:
<div> <h1>{{ user.name }}</h1> <h2>Post titles</h2> <p v-for="post in user.posts" :key="post.id"> {{ post.title }} </p> </div>
and know that if the set of associated posts in the js-data store changes, the list of titles displayed will reactively update accordingly.
]]>