1

I need help. I'm kind of an amateur in Vue3, and can´t understand why this happens:

If I set this in the parent component:

props: [ 'code' ],    
data() {
    return {
        asset: {
            id: '',
            brand: '',
            group: {
                name: '',
                area: ''
            }
        }
    }
},
created() {
    axios.get('/api/myUrl/' + this.code, {})
        .then(response => {
            if (response.status === 200) {
                this.asset = response.data;
            }
        })
        .catch(error => {
                console.log(error);
        })
}

then, in my component <asset-insurance :asset_id="asset.id"></asset-insurance>, asset_id prop is empty.

But, if I set:

props: [ 'code' ],
data() {
    return {
        asset: []
    }
},
created() {
    axios.get('/api/myUrl/' + this.code, {})
        .then(response => {
            if (response.status === 200) {
                this.asset = response.data;
            }
        })
        .catch(error => {
            console.log(error);
        })
}

then, the asset_id prop gets the correct asset.id value inside <asset-insurance> component, but I get a few warnings and an error in the main component about asset property group.name not being set (but it renders correctly in template).

Probably I'm doing something terribly wrong, but I can't find where is the problem. Any help?

Edit:

I'm checking the prop in child component AssetInsurance just by console.logging it

<script>
export default {
    name: "AssetInsurance",
    props: [
        'asset_id'
    ],
    created() {
        console.log(this.asset_id)
    }
}
</script>

asset_id is just an integer, and is being assigned correctly in parent's data asset.id, because I'm rendering it in the parent template too.

jhit
  • 349
  • 4
  • 8
  • The code you posted doesn't explain the problem. It should work if data is what you expect. It's unknown how you deternined that a prop is incorrect. The most simple way would be to just output asset.id value, no child component is needed. Please, provide https://stackoverflow.com/help/mcve to reproduce it. A working demo on Stackblitz, etc may help to get an answer faster. But it's a mistake to define asset as an array and then assign an object. – Estus Flask Dec 11 '21 at 11:40
  • @EstusFlask, thank you, but I'm sorry to say I don't know how to use Stackblitz. I have edited my question to clarify that asset.id is being assigned correctly in the api call, and that a direct console.log in the child component shows that prop is not being passed when I define asset with properties, but it's passed right when declaring asset as an array. :( – jhit Dec 11 '21 at 11:55
  • I posted the explanation. You won't get prop value in created hook because it doesn't exist. I guess you just broke the component when using `asset` array (this was the reason for errors), so child component was re-mounted the second time when asset.id has been available, while it shouldn't under normal circumstances. Also be aware of this when loggin objects (not the case here) https://stackoverflow.com/questions/23392111/console-log-async-or-sync – Estus Flask Dec 11 '21 at 12:28

2 Answers2

1

It's incorrect to define asset as an array and reassign it with plain object. This may affect reactivity and also prevents nested keys in group from being read.

The problem was misdiagnosed. asset_id value is updated but not at the time when this is expected. Prop value is not available at the time when component instance is created, it's incorrect to check prop value in created, especially because it's set asynchronously.

In order to output up-to-date asset_id value in console, a watcher should be used, this is what they are for. Otherwise asset_id can be used in a template as is.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Ok, now I understand where is the point of the problem, but sadly I don't know how to fix it. What would be the right way of making the api call right in created or mounted hooks? As you indicated, I have created a watcher in computed '''asset_id_watcher() { return this.asset_id }''', but '''console.log(this.assed_id_watcher)''' doesn't work in created or mounted either. – jhit Dec 11 '21 at 14:32
  • By "watcher" I mean specifically a watcher, not a computed, https://vuejs.org/v2/guide/computed.html#Watchers . You physically cannot get a value in `created` or `mounted` if it doesn't exist yet. You likely have XY problem. If you need asset_id on component init, you shouldn't render it until data is available. This is commonly solved with v-if – Estus Flask Dec 11 '21 at 15:51
  • Btw, I didn't even know the watch properties. I have been reading, and now I understand how can I fix this whenever it's not possible to use v-if in the component. :) – jhit Dec 11 '21 at 17:09
0

Ok, I think I found the proper way, at least in my case.

Prop is not available in the component because it is generated after the creation of the component, as @EstusFlask pointed.

The easy fix for this is to mount the component only when prop is available:

<asset-insurance v-if="asset.id" :asset_id="asset.id"></asset-insurance>

This way, components are running without problem, and I can declare objects as I should. :)

Thank you, Estus.

jhit
  • 349
  • 4
  • 8
  • Usually you can just define initial `asset: null` and do `v-if="asset"` without reproducing the whole structure for asset object, this depends on how it's used in the rest of the component – Estus Flask Dec 11 '21 at 17:09