vue-meteor icon indicating copy to clipboard operation
vue-meteor copied to clipboard

3-way data binding / Full Stack Reactivity

Open buhrmi opened this issue 8 years ago • 9 comments

I wondered if it's possible to implement full-stack reactivity in meteor-vue-component, similar to how angular-meteor does it: https://www.angular-meteor.com/tutorials/socially/angular2/3-way-data-binding

Basically, what it does is to call the corresponding Collection.update/insert/etc functions when the data model changes. For example, a text field with a v-model would not only update the client-side data, but through reactivity, also update the collection in the database.

buhrmi avatar Oct 17 '16 04:10 buhrmi

That should be possible!

Akryum avatar Oct 17 '16 09:10 Akryum

Iv been trying to implement that but I'm n able to figure out I in th watcher which field h changed. So I'm now doing a collection.update(id, {$set: enitiredocument} call. It would be nicer to make a call that sets only the changed fields.

buhrmi avatar Oct 17 '16 10:10 buhrmi

You may look into flux integration into apollo which makes data sources management simpler, assuming that someday they'll integrate meteor into it, so that then youd need vuex/apollo for simple data management.

janat08 avatar Oct 29 '16 08:10 janat08

I heard that minimongo doesn't go deep looking into fields, so that would most likely be your own extend of reach, as well as that more so conscious of operating expense may be weary of such a direct binding in write/update to DB.

janat08 avatar Nov 03 '16 16:11 janat08

According to this: https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events

<input v-model="something">

is just syntactic sugar for:

<input v-bind:value="something" v-on:input="something = $event.target.value">

That being the case, wouldn't this be sufficient?

<style lang="stylus" src="./styles"></style>
<template>
    <div id="app" class="app">
        <template v-for="text in texts">
            {{text.text}}
            <br />
            <input type="text" :value="text.text" @input="updateText" :data-id="text._id" />
            <br />
        </template>
    </div>
</template>
<script>
    import { Meteor } from 'meteor/meteor';
    import Texts from '/imports/api/texts/texts';
    export default {
        name: 'App',
        data: ()=> ({
            texts: []
        }),
        meteor: {
            subscribe: {
                texts: []
            },
            texts() {
                return Texts.find().fetch();
            }
        },
        methods: {
            updateText(e) {
                Meteor.call('updateText', {
                    id: e.target.dataset.id,
                    text: e.target.value
                });
            }
        }
    };
</script>

In the above example, instead of updating the client text value directly, like what would happen with v-model, we call the updateText method which updates the client text value through reactivity.

In any case, in order to get a method call in, you would have to specify which method to call using a v-on, which makes using v-model moot.

Narkoleptika avatar Dec 19 '16 00:12 Narkoleptika

Or you could use computed setters with v-model.

Akryum avatar Dec 19 '16 03:12 Akryum

Well, shit. @Akryum When you're right, you're right.

How would you set that up for a field on each mongo document from a collection? Sub component, probably... Is there any way to do it without a sub component?

Narkoleptika avatar Dec 19 '16 16:12 Narkoleptika

I've been using the collection-helpers package to implement a save method on documents (example: https://github.com/buhrmi/q-editor/blob/master/lib/collections.coffee#L149). Then I added a watcher like this:

watch: {
    myDocument: {
        deep: true,
        sync: true,
        handler: function(doc) {
           if (!Tracker.active) doc.save();
        }
    }
}

The !Tracker.active part is to ensure that the triggered watcher originated from Vue's reactivity and not from Meteor.

buhrmi avatar Dec 20 '16 07:12 buhrmi

One thing I would like to see here is also latency compensation. So if a doc is changed using v-model, a method runs on client and server to update the doc, then:

  • doc should be updated from simulated value of the method
  • if server-side updates doc differently, then client side doc should be updated to that value as well

Maybe this happens automatically because data flows from server and replaces those docs with new versions, but to me the issue with v-model is that Vue renders UI based on locally changed doc, and not on doc changed by simulated method. But maybe simulated method can override locally changed doc if it conflicts. So we have two levels of correcting. Simulated method -> doc changed by Vue. And server side -> doc changed by simulated method.

mitar avatar Jul 12 '17 13:07 mitar