vue.jslaravel-spark

Updating custom component's form after getting a response


I'm trying to load in a Tutor's profile in a custom component with Laravel Spark. It updates with whatever I enter no problem, but the is always empty when loaded.

The component itself is as follows:

Vue.component('tutor-settings', {

data() {
    return {
        tutor: [],

        updateTutorProfileForm: new SparkForm({
            profile: ''
        })
    };
},

created() {
    this.getTutor();

    Bus.$on('updateTutor', function () {
        this.updateTutorProfileForm.profile = this.tutor.profile;
    });
},

mounted() {
    this.updateTutorProfileForm.profile = this.tutor.profile;
},

methods: {
    getTutor() {
        this.$http.get('/tutor/current')
            .then(response => {
                Bus.$emit('updateTutor');
                this.tutor = response.data;
            });
    },

    updateTutorProfile() {
        Spark.put('/tutor/update/profile', this.updateTutorProfileForm)
            .then(() => {
                // show sweet alert
                swal({
                    type: 'success',
                    title: 'Success!',
                    text: 'Your tutor profile has been updated!',
                    timer: 2500,
                    showConfirmButton: false
                });
            });
    },
}

});

Here's the inline-template I have:

<tutor-settings inline-template>
<div class="panel panel-default">
    <div class="panel-heading">Tutor Profile</div>

    <form class="form-horizontal" role="form">
        <div class="panel-body">
            <div class="form-group" :class="{'has-error': updateTutorProfileForm.errors.has('profile')}">
                <div class="col-md-12">
                    <textarea class="form-control" rows="7" v-model="updateTutorProfileForm.profile" style="font-family: monospace;"></textarea>

                    <span class="help-block" v-show="updateTutorProfileForm.errors.has('profile')">
                        @{{ updateTutorProfileForm.errors.get('profile') }}
                    </span>
                </div>
            </div>
        </div>
        <div class="panel-footer">
            <!-- Update Button -->
            <button type="submit" class="btn btn-primary"
                    @click.prevent="updateTutorProfile"
                    :disabled="updateTutorProfileForm.busy">
                Update
            </button>
        </div>
    </form>
</div>

Very new to Vue and trying to learn on the go! Any help is much appreciated!


Solution

  • OK, firstly a bus should be used for communication between components, not within the components themselves, so updateTutor should be a method:

    methods: {
        getTutor() {
            this.$http.get('/tutor/current')
                .then(response => {
                    this.tutor = response.data;
                    this.updateTutor();
                });
        },
        updateTutor() {
           this.updateTutorProfileForm.profile = this.tutor.profile;
        }
    }
    

    Now for a few other things to look out for:

    Make sure you call your code in the order you want it to execute, because you appear to be emitting to the bus and then setting this.tutor but your function uses the value of this.tutor for the update of this.updateTutorProfileForm.profile so this.tutor = response.data; should come before trying to use the result.

    You have a scope issue in your $on, so the this does not refer to Vue instance data but the function itself:

    Bus.$on('updateTutor', function () {
        // Here 'this' refers to the function itself not the Vue instance;
        this.updateTutorProfileForm.profile = this.tutor.profile;
    });
    

    Use an arrow function instead:

    Bus.$on('updateTutor', () => {
        // Here 'this' refers to Vue instance;
        this.updateTutorProfileForm.profile = this.tutor.profile;
    });
    

    Make sure you are not developing with the minified version of Vue from the CDN otherwise you will not get warnings in the console.

    I can't see how you are defining your bus, but it should just be an empty Vue instance in the global scope:

    var Bus = new Vue();
    

    And finally, your mounted() hook is repeating the created() hook code, so it isn't needed. My guess is that you were just trying a few things out to get the update to fire, but you can usually do any initialising of data in the created() hook and you use the mounted hook when you need access to the this.$el. See https://v2.vuejs.org/v2/api/#Options-Lifecycle-Hooks