Search code examples
apostrophe-cms

Extend widgets for common input fields in apostrophe cms


I am creating multiple widgets in apostrophe 2.x which work fine. Now I want to structure and organise them properly. Most of my modules have an option for changing from content-width to browser-width. I am trying to generalise this function without putting the code in every module.

For example in my layout-widget/index.js I have this:

module.exports = {
  extend: 'apostrophe-widgets',
  label: 'Layout',
  addFields: [{
    name: 'size',
    label: 'Modulbreite',
    type: 'select',
    choices: [{
        label: 'Content width',
        value: 'content-width'
      },
      {
        label: 'Full width',
        value: 'full-width'
      }
    ],
    required: true
  }]
};

And now I want to create other widgets that get individual configuration options as well as this selection by extending this general module configuration. File: test-widget/index.js

module.exports = {
  extend: 'layout-widgets',
  label: 'Test',
  addFields: [{
      name: 'headline',
      label: 'Headline',
      type: 'string',
      required: true
    },
    {
      name: 'content',
      label: 'Add Element',
      type: 'area',
      options: {
        widgets: {
          'fact': {},
          'text': {}
        }
      }
    }
  ]
};

But currently I do not see the option for size in my CMS for the test widget. I only see the options directly defined in the test module. Is this even possible or must I insert the size select into every module itself?

Best regards


Solution

  • It is possible, you just need to write 'layout-widgets/index.js' with this intention in mind. That module can't just set addFields because that will be overridden by the modules that extend it. Instead, it must use a beforeConstruct function to manipulate addFields. Here is an example from the apostrophe-pieces module:

    beforeConstruct: function(self, options) {
      options.addFields = [
        {
          type: 'boolean',
          name: 'published',
          label: 'Published',
          def: false
        }
      ].concat(options.addFields || []);
    }
    

    beforeConstruct should be at the same level as construct, i.e. not nested inside it.