molerat
molerat

Reputation: 994

VueJS 2: Child does not update on parent change (props)

When I update the parent's singleIssue variable, it does not get updated inside my <issue> component. I am passing it there using props. I have achieved this in other projects already, but I can't seem to get what I am doing wrong.

I have reduced my code to the relevant parts, so it is easier to understand.

IssueIndex.vue:

<template>
    <div class="issue-overview">
        <issue v-if="singleIssue" :issue="singleIssue"></issue>

        <v-server-table url="api/v1/issues" :columns="columns" :options="options" ref="issuesTable">
            <span slot="name" slot-scope="props">{{props.row.name}}</span>

            <div slot="options" slot-scope="props" class="btn-group" role="group" aria-label="Order Controls">
                <b-btn class="btn-success" v-b-modal.issueModal v- 
on:click="showIssue(props.row)">Show</b-btn>
            </div>
        </v-server-table>
    </div>
</template>

<script>
    export default {
        mounted() {
            let app = this;

            axios.get('api/v1/issues/')
                .then(response => {
                    app.issues = response.data;
                })
                .catch(e => {
                    app.errors.push(e);
                }); 
        },
        data: () => {
            return {
                issues: [],
                singleIssue: undefined,
                columns: ['name', 'creation_date', 'options'],
                options: {
                    filterByColumn: true,
                    filterable: ['name', 'creation_date'],
                    sortable: ['name', 'creation_date'],
                    dateColumns: ['creation_date'],
                    toMomentFormat: 'YYYY-MM-DD HH:mm:ss',
                    orderBy: {
                        column: 'name',
                        ascending: true
                    },
                    initFilters: {
                        active: true,
                    }
                }
            }
        },
        methods: {
            showIssue(issue) {
                let app = this;

                app.singleIssue = issue;

                // This gets the action history of the card
                axios.get('api/v1/issues/getCardAction/' + issue.id)
                    .then(response => {
                        app.singleIssue.actions = response.data;
                    })
                    .catch(error => {
                        // alert
                    });
            }
        }
    }
</script>

Issue.vue:

<template>
    <div>
        {{ issue }}
    </div>
</template>

<script>
    export default {
        props: ['issue']
    }
</script>

So after showIssue() is triggered, it will get actions for the issue. But after then, I can't see the actions in the issue component.

If I update the issue-model in the issue component using form inputs, it will also start showing the actions. So I assume it's just in a weird state where it needs a refresh.

Thanks in advance!

Upvotes: 2

Views: 1474

Answers (1)

Decade Moon
Decade Moon

Reputation: 34286

If the singleIssue.actions property does not exist at the time when you're setting it, Vue will not be able to detect it. You need to use $set, or just define the property before you assign singleIssue to app.

Change this:

app.singleIssue = issue;

to this:

issue.actions = undefined;
app.singleIssue = issue;

The app.singleIssue property is reactive (because it was declared in the data section), so Vue will detect when this property is assigned to and make the new value reactive if it isn't already. At the time when issue is being assigned, it will be made reactive without the actions property, and Vue cannot detect when new properties are being added to reactive objects later on (hence why $set is required for those situations).

Upvotes: 2

Related Questions