Home > Software design >  Vue: executing two methods in specific order
Vue: executing two methods in specific order

Time:12-14

I have a Vue application. I would like to retrieve entries (from a database) based on a userid. I have the following methods in Vue:

export default {
    name: 'Entries',
    data() {
      return {
        userid: null
      };
    },
    methods: {
      getEntries() {
        this.getUserID();
        console.log("userid getEntries: "   this.userid);
        axios.get('/entries', this.userid)
          .then((res) => {
            this.entries = res.data;
            console.log(this.entries);
          })
          .catch((error) => {
            console.error(error);
          });
      },
      getUserID() {
        axios.get('/userid')
          .then((res) => {
            this.userid = res.data;
            console.log("userid getUserId: "    this.userid );
          })
          .catch((error) => {
            console.error(error);
          });
        },
    },
    created() {
      this.getEntries();
    }
  };

Within the getEntries method, I'm immediately calling the getUserID function. I would assume this sets the variable userid to the value retrieved from the getUserID method.

Instead I get the following output in the browser console, in exactly this order:

userid getEntries: null
userid getUserId: user_a

Why does it print first the console output from the getEntries function? And why is this null if it first executes the getUserID method?

How could I change is so that the axios call /entries can pass the userid.

CodePudding user response:

axios calls are async, if you need the userid populated before anything else is called, then you should populate before anything else is called, in mounted/created.

Then you can react to its change with a watcher. You could call getEntries when the getUserID call resolves but it's dirty and couples the two methods.

And don't forget to assign entries in data.

This will work:

export default {
  name: 'Entries',
  data() {
    return {
      userid: null,
      entries: []
    };
  },
  watch: {
    userid (v) {
      if (v) this.getEntries()
    }
  },
  mounted() {
    this.$nextTick(this.getUserID)
  },
  methods: {
    getEntries() {
      console.log("userid getEntries: "   this.userid);
      axios.get('/entries', this.userid)
        .then((res) => {
          this.entries = res.data;
          console.log(this.entries);
        })
        .catch((error) => {
          console.error(error);
        });
    },
    getUserID() {
      axios.get('/userid')
        .then((res) => {
          this.userid = res.data;
          console.log("userid getUserId: "   this.userid);
        })
        .catch((error) => {
          console.error(error);
        });
    }
  }
};

Using async/await

export default {
  name: 'Entries',
  data() {
    return {
      userid: null,
      entries: []
    };
  },
  watch: {
    userid (v) {
      if (v) this.getEntries()
    }
  },
  mounted() {
    this.$nextTick(this.getUserID)
  },
  methods: {
    async getEntries() {
      try {
        const { data } = await axios.get('/entries', this.userid)
        this.entries = data;
      } catch (error) {
        console.error(error);
      }
    },
    async getUserID() {
      try {
        const { data } = await axios.get('/userid')
        this.userid = data;
      } catch (error) {
        console.error(error);
      }
    }
  }
};

CodePudding user response:

Since getUserId is asynchronous, it doesn't return immediately. You therefore need to wait for it to return before continuing. This can be done using then but, nested Promises are a bit unpleasant to work with. A simpler option is to use async/await instead:

async getEntries() {
  await this.getUserID();
  console.log("userid getEntries: "   this.userid);
  axios.get('/entries', this.userid)
    .then((res) => {
       this.entries = res.data;
       console.log(this.entries);
    })
    .catch((error) => {
     console.error(error);
    });
},
  • Related