Web Component Component for Hippo CMS

March 2nd 2018 Hippo CMS Web Components Java

As a part of getting acquainted with Hippo CMS I took on the task of creating a custom Hippo component for including a Stencil web component in a portal page using the CMS editor. I based my work on a similar component I found on GitHub for a Polymer web component.

I started by creating an interface for configuration parameters:

package org.example.components.info;

import org.hippoecm.hst.core.parameters.Parameter;

public interface WebComponentInfo {
    @Parameter(name = "url", required = true, displayName = "URL")
    String getUrl();

    @Parameter(name = "elementName", required = true, displayName = "Element Name")
    String getElementName();
}

In the component class I retrieve the configuration parameter values and pass them on to the request so that I can access them inside the template:

package org.example.components;

import org.example.components.info.WebComponentInfo;
import org.hippoecm.hst.core.component.HstRequest;
import org.hippoecm.hst.core.component.HstResponse;
import org.hippoecm.hst.core.parameters.ParametersInfo;
import org.onehippo.cms7.essentials.components.CommonComponent;

@ParametersInfo(type = WebComponentInfo.class)
public class WebComponent extends CommonComponent {

    @Override
    public void doBeforeRender(final HstRequest request, final HstResponse response) {
        super.doBeforeRender(request, response);
        final WebComponentInfo paramInfo = getComponentParametersInfo(request);
        request.setAttribute(REQUEST_ATTR_PARAM_INFO, paramInfo);
    }
}

These two files are almost identical to their counterparts in the component I was basing my work on. The main difference is in the template as Stencil web components are distributed as a bunch of Javascript scripts, not as an HTML fragment:

<#include "../include/imports.ftl">

<#-- @ftlvariable name="cparam" type="org.example.components.info.WebComponentInfo"-->
<#-- @ftlvariable name="editMode" type="java.lang.Boolean"-->

<#if editMode>
    <#if cparam.url?? && cparam.elementName??>
        <h2>${cparam.elementName}</h2>
    <#else>
        <i>Click to Select Desired Web Component</i>
    </#if>
<#else>
    <#if cparam.url?? && cparam.elementName??>
        <div>
            <script>
                document.currentScript.parentElement.innerHTML =
                    '<${cparam.elementName}></${cparam.elementName}>';
            </script>
        </div>
    <#else>
        <div>
            <h1>Invalid Web Component Configuration</h1>
        </div>
    </#if>

    <@hst.headContribution category="htmlHead">
        <script type="text/javascript" src="<@hst.webfile path="${cparam.url}"/>">
        </script>
    </@hst.headContribution>
</#if>

To include the script tag in the page head, I take advantage of head contributions. I then dynamically add the element to the DOM in the embedded script. The @ftlvariable directives at the top are there as a hint to code completion in IntelliJ IDEA.

I registered the component in Hippo CMS manually using the Console. First I added the template by:

  • adding web-component node of type hst:template to hst:hst/hst:configurations/gogreen/hst:templates, and
  • adding and hst:renderpath property with a value of webfile:/freemarker/gogreen/web-component.ftl to the newly created node.

Template registration in the Console

Then I added the component to the catalog by:

  • adding web-component node of type hst:containeritemcomponent to hst:hst/hst:configurations/gogreen/hst:catalog/gogreen-catalog, and
  • adding the following properties to it:

    • hst:componentclassname with value org.example.components.WebComponent,
    • hst:label with value Web Component,
    • hst:template with value web-component, and
    • hst:xtype with value hst:item.

Component catalog entry in the Console

After writing the changes to the repository, the component became available in the component catalog of the CMS editor. When dragged into a placeholder on a page, a UI is automatically generated to enter the parameter values:

  • Set Element Name to the name of the element as specified in the Stencil component, e.g. my-component.
  • Set URL to the absolute path to the entry file in the component distribution folder. I put the package into repository-data/webfiles/src/main/resources/site/webcomponents folder, hence the value was /webcomponents/mycomponent/mycomponent.js. (Don't forget to add webcomponents to hst-whitelist.txt file if you do the same or the files won't be publicly available.)

Once you publish the changes, the web component should render on the portal.

Get notified when a new blog post is published (usually every Friday):

If you're looking for online one-on-one mentorship on a related topic, you can find me on Codementor.
If you need a team of experienced software engineers to help you with a project, contact us at Razum.
Copyright
Creative Commons License