简体   繁体   中英

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.

Methods can run synchronously on server so you do not need to use callback. Result of method will be returned after execution or exception will be thrown if error occurs. Try this:

export const useProfileAddress = new ValidatedMethod({
  // ...
  run(args) {
    const person = Persons.findOne({'userId': Meteor.userId()});

    const result1 = getClosestStore.call({address: person.address});

    // use result1 if you need to

    const result2 = updateCartAddress.call({address: person.address});

    // // use result2 if you need to

    return person.address;
  }
})

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM