Search code examples
javascriptmeteormeteor-accounts

Meteor method call returns undefined on the client but not on the server


UPDATE

I just realized something fundamentally wrong in this approach and that nested callbacks can't return something to its parent callback. I came in late in the JS world and come from the Promises era and didn't know this is the problem with callbacks. But I didn't see enough examples for Meteor using promises so I used callbacks instead. However, if this code can be improved I'd appreciate it greatly.

Question

So I'm calling a method from the client using:

Meteor.call('cart.useProfileAddress', {}, (error, address) => {
  console.info('Address', address) // this returns undefined on client
})

This is the method in my api/carts/cartsMethod.js

export const useProfileAddress = new ValidatedMethod({
  name: 'cart.useProfileAddress',
  validate(args) {
    //
  },
  run(args) {
    const person = Persons.findOne({'userId': Meteor.userId()});
    // If I do the return here I get the address in the browser as defined.
    // return person.address

    // I'm calling another method under here:
    getClosestStore.call({address: person.address}, (error, result) => {
      // And another one method call here:
      updateCartAddress.call({address: person.address}, (error, result) => {
        // So once all the callbacks are done return the address here.
        // However the problem is I get `undefined` on the client.
        if (!error) {
          // console displays something on the Server but is `undefined` on the Client
          console.info('Returning Address', person.address)
          return person.address
        }
      })
    })
  }
})

What could be the problem on the code above? Could it be because I'm trying to get the value from a nested callback?

Also does anyone know how to avoid these nested callbacks? I know how to do it on Node using promises but in Meteor (I'm using 1.4) I'm still clueless.


Solution

  • This is how I solved my problem using Promise and the new async/await feature of Meteor 1.3+

    export const useProfileAddress = new ValidatedMethod({
      name: 'cart.useProfileAddress',
      validate(args) {
        //
      },
      run(args) {
        return ((async () => {
          const person = Persons.findOne({'userId': Meteor.userId()});
          const storeId = await getClosestStore.callPromise({address: person.address})
          const newAddress = await updateCartAddress.callPromise({address: person.address})
    
          return newAddress
        })())
      }
    })
    

    Inside each method I used the didericis:callpromise-mixin so that it will return a promise.