Skip to content

Am I cheating if I use computed properties with setters? #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
thelinuxlich opened this issue Jan 13, 2016 · 11 comments
Closed

Am I cheating if I use computed properties with setters? #38

thelinuxlich opened this issue Jan 13, 2016 · 11 comments

Comments

@thelinuxlich
Copy link

<input v-model="message">

// ...
computed: {
  message: {
    get: function () {
      return store.state.message
    },
    set: function (newValue) {
      store.dispatch("CHANGE_MESSAGE", newValue)
    }
  }
}
//...
@yyx990803
Copy link
Member

Ha, I'd say this is pretty clever. The point is making sure all changes are explicitly recordable, and this does ensure every change to message is recorded in a mutation.

@blake-newman
Copy link
Member

Id say this is a good way to incorporate flux, as long as there is no direct manipulation, so that an action can control calls to multiple mutations. +1

@amanpatel
Copy link

If this is encouraged, I wonder if it can be made less verbose and perhaps even part of Vuex or Vue natively. I'm thinking of a brand new vuex property declaration:

  vuex: {
    message:  {
      dispatch: "CHANGE_MESSAGE",
      // more configuration?
    }
  }

Again, probably a lot of thought needs to go in to this before it is actually incorporated. But I wanted to start the discussion. This also directly addresses a way to to work with v-model on writable computed properties.

This could also be a mixin or plugin opportunity which uses the configuration and creates the computed properties for you. Would love to hear thoughts.

@yyx990803
Copy link
Member

@amanpatel imo this could be used in certain situations, but I would not put it into core. The point being that this makes it much less explicit about what is going on. It's fine if you build your own abstraction layer on top of Vuex to make this possible (e.g. a mixin), because it fits your mental model well. But I think Vuex itself should only provide the most explicit API.

@leevigraham
Copy link

@thelinuxlich For anyone else interested I had a slightly different requirement where there was lots of child data attributes.

@LinusBorg Helped point me in the right direction over here: https://forum.vuejs.org/topic/1546/vuex-state-mutation-error-on-data-stored-inside-component-data/4

  • I'm using a single vue file complied with webpack
  • I'm using vuex config over the global store singleton
  • Adding getters and setters for each child / form input would have been painful
  • The store state is quite deeply nested
  • In this case I'm manipulating an object in the store that has children
<template>
  <div>
    <h2>Customer Needs Analysis</h2>
    <input 
        :value="customerNeedsAnalysis.vehicleUsage" 
        v-on:input="update('vehicleUsage', $event)"
    >
    <textarea 
        :value="customerNeedsAnalysis.notes" 
        v-on:input="update('notes', $event)"
    ></textarea>
  </div>
</template>

<script>
export default {
  vuex: {
    getters: {
      customerNeedsAnalysis: state => state.quote.customerNeedsAnalysis
    },
    actions: {
      update: ({ dispatch }, attribute, e) => {
        dispatch('UPDATE_CUSTOMER_NEEDS_ANALYSIS', {[attribute]: e.target.value});
      }
    }
  }
}
</script>

screenshot

@thelinuxlich
Copy link
Author

your solution is much better

@leevigraham
Copy link

leevigraham commented Jun 21, 2016

@thelinuxlich Except for one small problem:

When I do this, it works well, but I've noticed an interesting artifact. If using the same model in more than one input, the mutation is called on all inputs when changing the input value in one. I could probably just check the value and abort if no change, but it would be nice to avoid calling the mutation on every input when a change is only made in one.

http://forum.vuejs.org/topic/2303/integrating-vuex-with-input-components-js-doesn-t-have-pointers/9

@jperelli
Copy link

As a workaround for that extreme corner case, maybe you can use something like _.debounce ?

@minhtruong92
Copy link

@leevigraham : Your solution only work with "native control" HTML, if we use plugin (example : Vuetify) it won't work correctly.

Example with number input component
:value = ... => we send value from model to component
v-on:input = ... => we get user input value and set to model but if user input characters (not number) the control won't display correct match with your model

@molerat619
Copy link

molerat619 commented Sep 3, 2018

How does this work with nested data or arrays? Unlike @leevigraham's example, I would like to be still able to use v-model for all it's benefits and consistency.

@molerat619
Copy link

P.S.: The use of two-way computed properties has been documented in the meantime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants