Josh
Josh

Reputation: 1429

Axios: Previous response data being assigned to variable

I am creating a frontend to a patient booking system with Vue.js, which is simply a dynamic web form. The user first selects a type of treatment, then the practitioner they want to see, and finally the appointment time. All data is obtained via RESTful API calls using axios.

The available options in each form field are filtered using the previous choice. For example, the user will only be presented with the available times of their selected practitioner, and the practitioner can only be selected from the group of practitioners who can perform the chosen treatment.

Filtering the practitioners based on the selected treatment works just fine.

However, filtering the appointments based on the selected practitioner does not work -- it's out of sync: the appointments are loaded for the previously selected practitioner. I have checked the backend, which is fine, and the API calls are in-sync (i.e. the person_id matches the id of the newly selected practitioner).

What is causing this problem and how do I fix it?

Here is the Vue.js code that performs this filtering:

var app = new Vue({
    el: '#app',
    data: {
        appointments: [],
        practitionerId: 0,
        practitioners: [],
        treatmentId: 0,
        treatments: [],
    },
    mounted: function () {
        axios.get('/api/treatments')
            .then(response => this.treatments = response.data);
    },
    watch: {
        // filter available practitioners by the selected treatment
        treatmentId: function () {
            // get the allowed role ids for the selected treatment
            var allowedRoleIds = '';
            const allowedRoles = this.treatments[this.treatmentId - 1]['allowed_roles'];
            for (var i = 0; i < allowedRoles.length; i++) {
                allowedRoleIds += allowedRoles[i]['id'];
                if (i + 1 < allowedRoles.length) {
                    allowedRoleIds += ',';
                }
            }
            // load the practitioners using the allowed role ids
            axios.get('/api/people?role_ids=' + allowedRoleIds)
                .then(response => this.practitioners = response.data);
        },
        // filter the available appointments by the selected practitioner
        practitionerId: function () {
            axios.get('/api/appointments?person_id=' + this.practitionerId)
                // ERROR!!! This is out of sync.
                .then(response => this.appointments = response.data);
        }
    }
});

Upvotes: 0

Views: 247

Answers (2)

Josh
Josh

Reputation: 1429

The problem can be resolved by adding a watcher to the appointments variable.

All I needed to do was add the following code within watch: { ... }:

appointments: function () {
    // now it works -- even without any function body
}

This seems really odd to me. I should not need to create a watcher for a variable in order to have that variable updated in the function body of another watcher.

I have either missed something in the Vue.js documentation about watchers or this is a bug. If someone can shed some light on this in the comments that would be great!

Upvotes: 1

glinda93
glinda93

Reputation: 8479

You need to refresh practitionerId after fetching people from RESTful API.

For example, in treatmentId watch:

axios.get('/api/people?role_ids=' + allowedRoleIds).then(response => {
    this.practitioners = response.data;

    // refresh practitionerId whenever fetch new people
    const selectedPractitionerId = this.practitionerId;
    this.practitionerId = 0;
    // if selected practitioner exists in new people
    practitioners.forEach(p => {
        if (p.id == selectedPractitionerId) {
            this.practitionerId = p.id;
        }
    }) // you can omit this search if you force the user to select new practitioner whenever they change treatment
});

Upvotes: 0

Related Questions