Search code examples
meteorasync-awaitcallback

How do I receive promise values in meteor for helper functions?


I wanted to work with Shopify's address library. Since these work with promises I thought about implementing callbacks in order to receive the results

import { Template } from 'meteor/templating';
import { ReactiveDict } from 'meteor/reactive-dict'
import AddressFormatter from '@shopify/address';

import './main.html';

const address = {
    company: 'Shopify',
    firstName: '恵子',
    lastName: '田中',
    address1: '八重洲1-5-3',
    address2: '',
    city: '目黒区',
    province: 'JP-13',
    zip: '100-8994',
    country: 'JP',
    phone: '',
};

Template.hello.onCreated(function () {
    const addressFormatter = new AddressFormatter('ja');
    const instance = this
    instance.state = new ReactiveDict()
    instance.state.setDefault('result', {
        "formattedAddress": "",
        "orderedFields": ""
    });

    getData(addressFormatter, function(r) {
        // the next line triggers the helper, since it "observes" the changes
        // to this "result" property on the reactive-dictionary
        instance.state.set('result', {
            formattedAddress: r.formattedAddress,
            orderedFields: r.orderedFields
        });
    });
})

Template.hello.helpers({
    address: function() {
        console.log(Template.instance().state.get("result"));
        return Template.instance().state.get('result')
    }
});

function getData(addressFormatter, callback) {
    const fa = async () => {
        const result = await addressFormatter.format(address);
        console.log(result)
        return result;
    }
    const of = async () => {
        const promise = addressFormatter.getOrderedFields('CA');
        promise.then(result => {
            console.log(result);
            return result;
        });
    }
    let results = {
        "formattedAddress": fa(),
        "orderedFields": of()
    }
    callback(results);
}

The only thing that I receive in the template are [object Promise]. The console.logs in the getData() method actually show the accurate data but they are not displayed in teamplte. What can I do to receive the values and make my helper wait for them?

Edit: I have edited it according to @Jankapunkt answer but the objects are still empty, while the results in getData() are not.


Solution

  • You don't. Helpers are there to immediately return values but are triggered by reactive data sources.

    If you want a helper to "run" once the data "arrived" then your should move this code into onCreated and store the value in a reactive data source:

    import { Template } from 'meteor/templating';
    import { ReactiveDict } from 'meteor/reactive-dict'
    import AddressFormatter from '@shopify/address';
    
    import './main.html';
    
    const address = {
        company: 'Shopify',
        firstName: '恵子',
        lastName: '田中',
        address1: '八重洲1-5-3',
        address2: '',
        city: '目黒区',
        province: 'JP-13',
        zip: '100-8994',
        country: 'JP',
        phone: '',
    };
    
    Template.hello.onCreated(function () {
      const instance = this
      instance.state = new ReactiveDict()
      instance.state.setDefault('result', {
        "formattedAddress": "",
        "orderedFields": ""  
      })
    
    
      const addressFormatter = new AddressFormatter('ja')
      getData(addressFormatter)
        .then(({ formattedAddress, orderedFields }) => {
          // the next line triggers the helper, since it "observes" the changes
          // to this "result" property on the reactive-dictionary
          instance.state.set('result', { formattedAddress, orderedFields })
        })
        .catch(e => console.error(e))
    
      return results;
    })
    
    Template.hello.helpers({
        address: function() {
          return Template.instance().state.get('result')
        }
    });
    
    const getData = async function (addressFormatter) {
      const formattedAddress = await addressFormatter.format(address)
      const orderedFields = await addressFormatter.getOrderedFields('CA')
      return {
        formattedAddress,
        orderedFields
      }
    }
    

    Readings: http://blazejs.org/

    Edit: added a simplified getData that should work