Skip to content

Custom Vue components

Intro

The XalokNext comes with hooks to register custom Vue components that you can use in the Vue app.

Warning

Using wf-* attributes inside your custom components is NOT supported. This is because the wf-* attributes are being parsed at build time (check this section for details), and the component is being rendered at runtime.

Registering custom components

To register a new component, add a Vue Single-File Component file in the src/App/Bundle/CmsAdminBundle/Resources/public/javascripts/wfvue/components directory.

Naming conventions

App prefix

It's recommended that your custom component be prefixed with App to prevent conflicts with either Wf components or with possible (existing or future) HTML element names.

Module editors

In wfvue/XalokNext, the module editors are prefixed with WfModuleEditor (e.g.: WfModuleEditorContentModels). You are encouraged to register project module editors with AppModuleEditor prefix.

Module renderers

In XalokNext, module renderers are a special type of component used for... well... rendering modules 😃

Their names are prefixed with WfModuleRenderer (e.g. WfModuleRendererListing). You are encouraged to register project module renderers with AppModuleRenderer prefix.

Platform specific

If the filename ends in .client (e.g. AppCustomComponent.client.vue), this component will be available only when working in the browser. Useful for module editors - their code is not needed when rendering the page for the public side - there's no content edition possible there.

If the filename ends in .server (e.g. AppCustomComponent.server.vue), this component will be available only when rendering the page for the public side.

You can add a component with the same name but different code for .client and .server platforms. This comes in handy for module renderers: the code needed to handle the rendering of a module is wildly different between the client and the server platforms. For example, the automated listing module renderer (WfModuleRendererListing), during SSR it needs to output only an <esi:include src="__SLUG_OF_THE_LISTING__" /> and nothing more, while on the client it needs to listen to changes made to the listing and refresh through AJAX the contents of the listing.

Module renderers

One of the common use-cases for using Vue custom components is to handle the rendering of a module - depending on the module's type. This means that you're likely going to inject the module renderer from the wf-app-module wf-directive:

javascript
// in src/App/Bundle/CmsBundle/Resources/wf-directives/wf-app-module.js
module.exports = {
    extends: "wfRole",
    bind: (el, {value}, moduleConfig) => {
        switch (value) {
            case "custom_module":
                moduleConfig.module = "custom_module";
                el.innerHTML = `<app-module-renderer-custom-module :module="module" />`
                break;
        }
    }
}

The ad module renderer

It's likely that the code for showing ads in the CMS differs from project to project. Add a src/App/Bundle/AppCmsBundle/Resources/public/javascripts/wfvue/components/WfModuleRendererAd.server.vue file to overwrite the code contained in vendor/wfcms/standard/Wf/Bundle/CmsEditorBundle/Resources/public/javascripts/wfvue/components/WfModuleRendererAd.server.vue.

Module editors

It's likely that adding a new type of module will require implementing a custom editor. For basic cases, using wf-popover-editor can be enough. If a more special editor is required, one can hook it in the wf-app-module wf-directive:

javascript
// in src/App/Bundle/CmsBundle/Resources/wf-directives/wf-app-module.js
module.exports = {
   extends: "wfRole",
   bind: (el, {value}, moduleConfig) => {
      switch (value) {
         case "custom_module":
            moduleConfig.module = "custom_module";
            moduleConfig.editor = 'AppModuleEditorCustom'; // <-- this module will use the `AppModuleEditorCustom` component
            break;
      }
   }
}

PropTypes

Both a custom editor and a wf-popover-editor one are being passed some props from wfvue application. You can use wfed/wfvue/components/prop_types, the moduleEditor key for these props:

javascript
// in src/App/Bundle/CmsAdminBundle/Resources/public/javascripts/wfvue/components/AppModuleEditorSample.client.vue
<template>
    <!-- The Vue template -->
</template>


import propTypes from "wfed/wfvue/components/prop_types";
import trans from "wfed/wfvue/filters/trans";

let lastId = 0;

export default defineComponent({
    functional: true,
    emits: ["change"],
    props: {
        ...propTypes.moduleEditor,
    },
});

Updating the module

For a wf-popover-editor: when the data has been edited, emit a change event with the updated data:

javascript
// in src/App/Bundle/CmsAdminBundle/Resources/public/javascripts/wfvue/components/AppModuleEditorSample.client.vue
<template>
    <!-- The Vue template -->
</template>


import propTypes from "wfed/wfvue/components/prop_types";
import trans from "wfed/wfvue/filters/trans";

let lastId = 0;

export default defineComponent({
    functional: true,
    emits: ["change"],
    props: {
        ...propTypes.moduleEditor,
    },
    setup(props, ctx) {
        // call `change()` to update this module's data
        const change = () => {
            ctx.emit("change", {
                ...props.data,
                // additional module data 
            });
        };
        
        return {
            change
        };
    }
});

For a custom editor use the props.store to dispatch either MODULE_UPDATE or MODULE_PARTIAL_UPDATE actions.