0

I have a custom component which receives a list of filters in order to display just the doctors that the user has selected:

<DoctorsSidebarFilter @update-view='showFilteredDoctors'></DoctorsSidebarFilter>

Next, in my main component, I'm using this to display the doctors:

<v-flex
   v-for="doctor in allDoctors"
   :key="doctor.first_name"
   xs12
   sm6
   md4
>

And here's my data:

export default {
data: () => ({
        allDoctors:[],
    }),
    methods: {
        fetchDoctors(){
            //Retrieve doctors
            this.$store.dispatch(RETRIEVE_DOCTORS)
            .then(
                response => {
                    this.allDoctors = response;
                }
            )//TODO-me: Handle the error properly!
            .catch(error => {
                console.log(error);
            });
        },
        showFilteredDoctors(filters){
            let result = [];
            this.fetchDoctors();

            console.log('1:' + " " + JSON.stringify(this.allDoctors));
            if (filters.length > 0) { // If Array is not empty then apply the filters
                console.log('2');
                this.allDoctors.forEach(function(e) {
                    if(filters.some(s => s.specialty === e.specialty || s.city === e.city)) {
                        result.push(e);
                    }
                });
                console.log('3:' + " " + JSON.stringify(result));
                this.allDoctors = [...result];
                console.log('4:' + " " + JSON.stringify(this.allDoctors));
            }
        }
    },
    mounted() {
        this.fetchDoctors();
    }
}

The problem is that eventhough my filtering works correctly and I can see from console.log('4:' + " " + JSON.stringify(this.allDoctors)); that this.allDoctors contains the new, filtered list; this is never displayed on screen.

Instead I see the default list of doctors that I've fetched from my API. Using vue devtools I can see that the this.allDoctors is momentarily updated with the correct values but then it goes back to the default ones.

2 Answers 2

3

As @user1521685 has already explained, the call to fetchDoctors is asynchronous so it'll complete after you've performed the filtering.

Typically you'd do something like this using a computed property instead and only make the server call once.

export default {
    data: () => ({
        allDoctors: [],
        filters: []
    }),
    computed: {
        filteredDoctors() {
            const allDoctors = this.allDoctors;
            const filters = this.filters;

            if (filters.length === 0) {
                return allDoctors;
            }

            return allDoctors.filter(doctor => {
               return filters.some(filter => filter.specialty === doctor.specialty || filter.city === doctor.city);
            });
        }
    },
    methods: {
        fetchDoctors(){
            //Retrieve doctors
            this.$store.dispatch(RETRIEVE_DOCTORS)
            .then(
                response => {
                    this.allDoctors = response;
                }
            )//TODO-me: Handle the error properly!
            .catch(error => {
                console.log(error);
            });
        },
        showFilteredDoctors(filters){
            this.filters = filters;
        }
    },
    mounted() {
        this.fetchDoctors();
    }
}

In your template you'd then use:

v-for="doctor in filteredDoctors"
Sign up to request clarification or add additional context in comments.

1 Comment

I figured this would be somekind of problem due to async. It works now, thanks!
2

fetchDoctors is async, so in showFilteredDoctors you fetch the doctors, then set the filtered array and then the thenable in fetchDoctors kicks in and overrides the doctors again: this.allDoctors = response. You'd have to return the Promise in fetchDoctors and use it in showFilteredDoctors like so: this.fetchDoctors().then(() => /* do the filtering */)

EDIT: Return the Promise like this: return this.$store.dispatch(RETRIEVE_DOCTORS).then().catch()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.