1

Say we have two routes: edit/1 and edit/new

The root container (on mount) checks if there is a this.$route.params.id and if so, fetches the data from the API and fills the obj. Otherwise, the obj in question remains empty.

This object is sent to a child component which has something like:

<template>
  <input v-model="obj.name">
  <input v-model=obj.email">
</template>

<script>
export default {
  props: {
    obj {
      type: Object,
      default: () => {}
    }
  },
}
</script>

The issue I'm having right now is that when I send an empty object nothing renders. Would this issue have anything to do with the empty object? As far as I can tell, properties can be added dynamically like this in Vue.

Should you need more information, please ask!

4
  • are you sure that when you send a filled object that works fine? Commented Jul 16, 2021 at 15:55
  • Yes when I send a full object it works! Commented Jul 16, 2021 at 16:01
  • 1
    btw, if you use vuex you won't need to pass about an arbitrary object, imo props should be specific to setting options for the component, everything else like any kind of data like your code should be in the store Commented Jul 16, 2021 at 19:17
  • @LawrenceCherone Agreed! Unfortuantely not how this app was designed without the store in mind Commented Jul 16, 2021 at 22:35

2 Answers 2

2

Just for the record

default: () => {}

Will not return an empty object as a default. The arrow function will return void. If you're trying to set an empty object as a default use

default: () => ({})

Anyway as prop mutations are not only discouraged, they're considered an anti-pattern in Vue2 (see Vue 2 - Mutating props vue-warn) you should add a data field that either already declares default values or get's its default from the corresponding prop field

props: {
  obj: {
    type: Object,
    default: () => ({ name: '', email: '' })
  }
}
data() {
  return {
    name: this.obj.name,
    email: this.obj.email,
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Could we use spread operator here to shallow copy obj?
data() { return { obj: { ...this.someProp } }; }, should work sure but I can't vouch for it
1

The problem is you need to either declare the prop members in the object, or use Vue.set to add new reactive properties from the parent.

default: () => ({name:null, email:null})
// or
default: () => { return {name:null, email:null} }

or in the parent

Vue.set(defaultObjWithoutMembers, 'name', 'foo')

Vue2 is not able to detect or track properties that are not part of the original object declaration.

See https://v2.vuejs.org/v2/guide/reactivity.html

6 Comments

but v-model mutates the prop which is not allowed in vue
its allowed, but discouraged. and even so, using :value and @input('$emit'...) to change won't detect new properties.
I'm using :obj.sync="obj" and it works fine if the obj is full
@StevenSpungin Ok your Vue.set method worked! But, I wanted to add that not all properties required it. Only arrays (in my case). Could you explain why?
The javascript runtime that Vue2 runs in uses a proxy that can only track what it sees when it initially scans the object. So using Vue.set is the work around, or declaring null or undefined props. Also note i put your default function in ( ) now to return an object, as stated in Braks post. Vue3 does not have this issue BTW.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.