javascriptvue.jsroutesparent-child

Vue.js parent <-> child updating value, routing view


I'm having issue regarding updating parent prop in child view. In my case Contestant is parent, EditContestant should be child. Contestant.vue should store (yeah, probably answer is right here - store as in Vuex) user info and EditContestant should only render edit view, allow for edit user info action and save it via own method or parent method. I've included routing so you should get what I'm talking about.

Structure is:

Contestant.vue
|-EditContestant.Vue

Contestant.vue:

<script>
    export default {
        data() {
            return {
                contestant: {
                    id: this.$route.params.id,
                    gender: '',
                    firstname: '',
                    lastname: '',
                },
            }
        },
    methods: {
            fetchContestant(id) {
        //some api call here                            
              vm.updatePropContestant(res.data);
        // ...
            },
            updatePropContestant(newData) {
                if (!this.contestant || this.contestant.length === 0) {
                    this.contestant = {};
                }
                this.contestant.firstname = newData.firstname;
                this.contestant.lastname = newData.lastname;
                this.contestant.id = newData.id;
                this.contestant.gender = newData.gender;
                // this.$forceUpdate();
            },
        },
        }
</script>
<template>
    <div>
        <router-view :contestant="contestant"  @interface="contestant = $event"></router-view>
    </div>
</template>

EditContestant.vue

<script>
    export default {
        data() {
            console.log('data');
            return {
                editContestant: {
                    id: '',
                    'firstname': '',
                    'lastname': '',
                    'gender': 0
                },
                edit: false
            }
        },
        props: ['contestant'],
        created: function () {
// tried also to fetchContestant if parent beforeCreate method with same result, so tried moving it here :(
            this.$parent.fetchContestant(this.$route.params.id);
        }
    }
</script>

<template>
<div class="col">
<input id="firstname" v-model="this.$parent.contestant.firstname" type="text" class="form-control"                                placeholder="First name" 
<!-- this doesn't help either v-on:input="updateParentValue($event.target.value)" --> >
                </div>
</template>

app.js

require('./bootstrap');
window.Vue = require('vue');
import router from './router';
new Vue({
    el: "#app",
    router,
    // render: h => h(app)
});

router/index.js


import contestantComponent from '../components/Contestant/Contestant'
import contestantEditComponent from '../components/Contestant/EditContestant'
Vue.use(Router)
export default new Router({
    routes: [
        {
            path: '/contestant/:id',
            component: contestantComponent,
            children: [
                {

                    name: 'Contestant edit',
                    component: contestantEditComponent,
                    path: '/contestant/:id?/edit',
                },
                {
                    name: 'View contestant',
                    component: ViewContestantComponent,
                    path: '',
                }
            ],
    ]
})

When I add something to the input I get an error:


found in

---> <EditContestant> at resources/js/components/Contestant/EditContestant.vue
       <Contestant> at resources/js/components/Contestant/Contestant.vue
         <Root>
warn @ app.js:41366
logError @ app.js:42625
globalHandleError @ app.js:42620
handleError @ app.js:42580
invokeWithErrorHandling @ app.js:42603
invoker @ app.js:42916
original._wrapper @ app.js:48273

and

app.js:42629 TypeError: Cannot read property '$parent' of null
    at _c.on.input (app.js:37434)
    at invokeWithErrorHandling (app.js:42595)
    at HTMLInputElement.invoker (app.js:42916)
    at HTMLInputElement.original._wrapper (app.js:48273)

Solution

  • You don't need this. in template, just use $parent. Template is already in the this. scope.

    The communication between parent and child should be using Props down events up, instead of directly call the function thru this.$parent.function(). You should $emit('callFunc') then @callFunc="function".