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:
// 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:
// 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:
// 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:
// 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.