Search code examples
apostrophe-cms

Create widget select type field based on 3rd party API response


We started to develop a site in Apostrophe CMS based on a 3rd party API and stuck on the following issue:

  • we need a widget which has a select (on admin side).
  • the options from it are generated based on an API response.
  • the Admin user will select an option when he/she sets up the widget parameters (server side).
  • based on this selection we will call another API, and based on that response will generate some HTML (client side; images, texts, etc.)

The scenario is the following: the admin chooses a product from a list and on the front-end we will show information based on that selection.

const request = require( 'request-promise' );

module.exports = {
    extend: 'apostrophe-widgets',
    label: 'Preloaded list widget',
    addFields: [
        {
            label: 'Product',
            name: 'product',
            type: 'select',
            required: true,
            choices: "getChoices"
        }
    ],

    getChoices: async function( req )
    {
        const products = await request( {
            uri: "http://API_for_product_list",
            json: true
        } );

        var choiceList = [];
        for( idx = 0; idx < products.totalRecords; idx++ )
        {
            var option =
            {
                label: products.items[ idx ].label,
                value: products.items[ idx ].value
            };

            choiceList.push( option );
        }

        return choiceList;
    }
};


When I start the application i got the following warning: "widget type preloadedlist, field name product: When using showFields, field.choices must be an array" And the list shows empty. The getChoices function is never called.

I'm missing something but I don't know what. We did everything according to the documentation.


Solution

  • You have to attach your getChoices function to the module itself so that it can be referenced later.

    const request = require('request-promise');
    
    module.exports = {
      extend: 'apostrophe-widgets',
      label: 'Preloaded list widget',
      addFields: [{
        label: 'Product',
        name: 'product',
        type: 'select',
        required: true,
        choices: 'getChoices'
      }],
      construct: function(self, options) {
        self.getChoices = async function (req) {
          const products = await request({
            uri: "http://API_for_product_list",
            json: true
          });
    
          var choiceList = [];
          for (idx = 0; idx < products.totalRecords; idx++) {
            var option = {
              label: products.items[idx].label,
              value: products.items[idx].value
            };
    
            choiceList.push(option);
          }
          return choiceList;
        }
      }
    };