davestewart / vuex-pathify

Vue / Vuex plugin providing a unified path syntax to Vuex stores
https://davestewart.github.io/vuex-pathify
MIT License
1.37k stars 57 forks source link

Need to be able to use this.PROPERTY inside get, set, sync functions #28

Closed mcmimik closed 5 years ago

mcmimik commented 6 years ago

Hi,

I make form components in my project. Form has one prop storage, that should be a string to use it as link to model in storage.

Example of use:

<BaseForm :storage="modelName">
    <BaseFormItem name="domain">
        <BaseInput/>
    </BaseFormItem>
</BaseForm>

I have many BaseForm's on different pages, so I want to sync such controls like BaseInput automatically with the store. I'd like to do it with the storage property provided from the BaseForm, and controlName passed from the BaseFormItem:

// BaseInput.vue
inject: {
    storage: { default: '' },
},
computed: {
    controlName() {
        return this.name || this.baseFormItem.name;
    },
    controlValue: sync(`${this.storage}/form/${this.controlName}`)
}

But the problem is that I can not use this this way (it is undefined). Could you please make it possible to use function inside get/set/sync? For example:

controlValue: sync(function() {
    return `${this.storage}/form/${this.controlName}`;
})

Or maybe some custom syntax:

controlValue: sync(`{this.storage}/form/{this.controlName}`)
davestewart commented 6 years ago

Hey,

Unfortunately you can't use this when defining the computed properties, as this doesn't yet exist!

One workaround is to modify the $options.computed property in the created lifecycle hook:

I'm not sure if something like the custom syntax you suggested would work as I can't remember what the context of the created property would be at the time, but it's an interesting idea.

If you can work with the workarounds in the meantime, I'll look into it!

mcmimik commented 6 years ago

I decided to use getter and setter for now, it seemed to me a lesser evil:

controlValue: {
    get() {
        return this.$store.state[this.storage].model[this.controlName];
    },
    set(value) {
        this.$store.dispatch(`${this.storage}/setValue`, {
            name: this.controlName,
            value
        });
    }
}

Nevertheless, It would be very handy to use function as the parameter for get or sync, that returns string. By the way, Vuex supports function in its helpers: https://stackoverflow.com/a/52157115/3386279

davestewart commented 6 years ago

Yeah, I was going to suggest the same. Good choice!

BenRichter commented 5 years ago

If you want to keep the simplicity of e.g. pathify sync, I followed the Example in #27 and came up with the following solution. You can still use other computed props.

props: {
  store: {
    type: String,
    required: true
  }
},

computed: {}, // required for assignment! Can still contain properties :)

beforeCreate() {
  const { store } = this.$options.propsData
  Object.assign(this.$options.computed, {
    ...sync(`${store}/*`)
  })
},

I guess it would be possible to implement this into Pathify directly, for a more intuitive Syntax, by trying this as a Fallback if a variable in the path declaration is undefined. Would be awesome under the hood magic. (but could possibly disguise some bugs though...)