Dealing with many attributes mapping to a parent component list in VueJS

强颜欢笑 提交于 2021-01-29 15:22:24

问题


I've got a list of components where I'd like them all to be editable / replicate state to the parent component.

The list component exists as:

Vue.component("shortcuts", {
  props: {
    shortcuts: Array
  },
  template: '...<shortcut-entry v-for="(shortcut, index) in shortcuts" v-bind:key="index" v-bind="shortcut" @remove="remove(index)"></shortcut-entry>...'
})

It's used with a model like this:

<shortcuts v-bind:shortcuts.sync="shortcuts"></shortcuts>

Now each shortcut-entry component will contain lots of values which I would like to be propagated back to the top level list of objects:

    Vue.component("shortcut-entry", {
      props: {
        mod_ctrl: Boolean,
        mod_alt: Boolean,
        mod_shift: Boolean,
        keypress: String,
        action: String,
        ...
      },

Each of those properties exists as a separate checkbox / input on the page with (for example) <input ... v-model="action">. The way I understand it, I could wire the update events back to the parent component and do replacements there... but that sounds like a lot of boilerplate code.

Can I somehow propagate any modifications for those props back to the parent component automatically? (avoiding the "Avoid mutating a prop directly" warning)

It seems to work as I expect if I move every prop I currently have into another level (so I have props: {options: Object}, v-bind it with .sync and assign everything there), but I'm looking into some more explicit solution which actually declares the relevant options ahead of time.


回答1:


You can use sync modifier with the props object notation together. Instead of v-bind="shortcut" use v-bind.sync="shortcut"

This way shortcut component can declare all props (instead of just options object) and still be able to notify parent about mutation

But you need to change how you bind your inputs. Instead of <input ... v-model="action"> you need to <input ... v-bind:value="action" v-on:input="$emit('update:action', $event.target.value)">. Problem with this is that different <input> types use different names for value and change event

To work around it and keep using v-model you can declare computed for each prop and use v-model="actionComputed"

computed: {
  actionComputed: {
    get: function() { return this.action },
    set: function(value) { this.$emit('update:action', value) }
  }
}

So the result is again lot of boilerplate...

TL:DR

If you want all props declared ahead of time (instead of single prop of type object), some boilerplate is necessary. It can be reduced by generating computed props for v-model on the fly (same way Vuex helpers generate computed to access and update Vuex state) but I don't think it is worth the effort. Just pass an object and let the <input> components mutate it's properties...



来源:https://stackoverflow.com/questions/65503140/dealing-with-many-attributes-mapping-to-a-parent-component-list-in-vuejs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!