Rendering Form Field Settings

Once the settings are added to the class backing the field’s settings, make sure the *Renderer can get the settings and update the front-end code.

Passing Settings to the Renderer Class

Send the new configuration settings to the Soy template so they can be displayed to the end user. Create a new Java class implementing the interface DDMFormFieldTemplateContextContributor and modify the existing class *DDMFormFieldRenderer.

The DDMFormFieldTemplateContextContributor interface has a single method named getParameters. It gets the new configuration settings, specific for a form field type, and sends for the resources that need them, like the Soy template. To get these settings, create a new class, TimeDDMFormFieldTemplateContextContributor. First create its OSGI component annotation and the class declaration:

@Component(
    immediate = true,
    property = "ddm.form.field.type.name=time",
    service = {
        DDMFormFieldTemplateContextContributor.class,
        TimeDDMFormFieldTemplateContextContributor.class
    }
)
public class TimeDDMFormFieldTemplateContextContributor
    implements DDMFormFieldTemplateContextContributor {

Then override getParameters to get the new configurations settings, placeholder and mask:

    @Override
    public Map<String, Object> getParameters(
        DDMFormField ddmFormField,
        DDMFormFieldRenderingContext ddmFormFieldRenderingContext) {

        Map<String, Object> parameters = new HashMap<>();

        parameters.put(
            "placeholder", (String)ddmFormField.getProperty("placeholder"));
        parameters.put("mask", (String)ddmFormField.getProperty("mask"));

        return parameters;
    }

}

Now pass the configuration settings to the template with a new method, populateOptionalContext, in TimeDDMFormFieldRenderer:

@Override
protected void populateOptionalContext(
	Template template, DDMFormField ddmFormField,
	DDMFormFieldRenderingContext ddmFormFieldRenderingContext) {

	Map<String, Object> parameters =
		timeDDMFormFieldTemplateContextContributor.getParameters(
			ddmFormField, ddmFormFieldRenderingContext);

	template.putAll(parameters);
}

@Reference
protected TimeDDMFormFieldTemplateContextContributor
	timeDDMFormFieldTemplateContextContributor;

The populateOptionalContext method takes three parameters: The template object, the DDMFormField, and the DDMFormFieldRenderingContext. The DDMFormField represents the definition of the field type instance: you can use this object to access the configurations set for the field type (the mask and placeholder settings in our case). The DDMFormFieldRenderingContext object contains extra information about the form like the user’s locale, the HTTP request and response objects, the portlet namespace, and more (all of its included properties can be found here).

The OSGI reference (@Reference) provides access to the TimeDDMFormFieldTemplateContextContributor service.

Now the JavaScript component and the Soy template can access the new settings. Next, update the JavaScript Component so it handles these properties and can use them, whether passing them to the template context (similar to the *Renderer, only this time for client-side rendering), or using them to configure the behavior of the JavaScript component itself.

Next configure the JavaScript component to include the new settings.

Adding Settings to the JavaScript Component

The JavaScript component must know about the new settings. First configure them as attributes of the component:

ATTRS: {
    mask: {
        value: '%I:%M %p'
    },
    placeholder: {
        value: ''
    },
    type: {
        value: 'time'
    }
},

The mask setting has a default value of %I:%M %p, and the placeholder is blank. Now that the new settings are declared as attributes of the component, make the JavaScript component pass the placeholder configuration to the Soy template on the client side. Just like in the Java renderer, pass the placeholder configuration to the template context. In this case, override the getTemplateContext() method to pass in the placeholder configuration. Add this to the prototype section of the JavaScript component definition:

getTemplateContext: function() {
    var instance = this;

    return A.merge(
        TimeField.superclass.getTemplateContext.apply(instance, arguments),
        {
            placeholder: instance.get('placeholder')
        }
    );
},

Then in the component’s render method, add the mask as an attribute of the AUI Timepicker using mask: instance.get('mask').

render: function() {
    var instance = this;

    TimeField.superclass.render.apply(instance, arguments);

    instance.timePicker = new A.TimePicker(
        {
            trigger: instance.getInputSelector(),
            mask: instance.get('mask'),
            popover: {
                zIndex: 1
            },
            after: {
                selectionChange: A.bind('afterSelectionChange', instance)
            }
        }
    );
},

Now the field type JavaScript component is configured to include the settings. All you have left to do is to update the Soy template so the placeholder can be rendered in the form with the time field.

Updating the Soy Template

Add the placeholder setting to your Soy template’s logic.

The whole template is included below, but the only additions are in the list of parameters (adds the placeholder to the list of parameters—the ? indicates that the placeholder is not required), and then in the <input> tag, where you use the parameter value to configure the placeholder HTML property with the proper value.

{namespace DDMTime}

/**
* Defines the delegated template for the time field.
*/
{deltemplate ddm.field variant="'time'"}
    {call .render data="all" /}
{/deltemplate}

/**
* Prints the time field.
*/
{template .render}
    {@param name: string}
    {@param pathThemeImages: string}
    {@param value: ?}
    {@param visible: bool}
    {@param? placeholder: string}
    {@param? dir: string}
    {@param? label: string}
    {@param? predefinedValue: string}
    {@param? readOnly: bool}
    {@param? required: bool}
    {@param? showLabel: bool}
    {@param? tip: string}

    {let $displayValue: $value ? $value : $predefinedValue ? $predefinedValue : '' /}

    <div class="form-group {$visible ? '' : 'hide'} liferay-ddm-form-field-time"
        data-fieldname="{$name}">
        {if $showLabel or $required}
            <label for="{$name}">
                {if $showLabel}
                    {$label}{sp}
                {/if}

                {if $required}
                    <svg aria-hidden="true" class="lexicon-icon lexicon-icon-asterisk reference-mark">
                        <use xlink:href="{$pathThemeImages}/lexicon/icons.svg#asterisk" />
                    </svg>
                {/if}
            </label>
        {/if}

        {if $showLabel}
            {if $tip}
                <span class="form-text">{$tip}</span>
            {/if}
        {/if}

        <div class="input-group">
            <div class="input-group-item">
                <input class="field form-control"
                    {if $dir}dir="{$dir}"{/if}
                    {if $readOnly}disabled{/if}
                    id="{$name}"
                    name="{$name}"
                    placeholder="{$placeholder}"
                    type="text"
                    value="{$displayValue}">
            </div>
        </div>
    </div>
{/template}

The mask is not needed in the Soy template because it’s only used in the JavaScript for configuring the behavior of the timepicker. You don’t need the dynamic rendering of the Soy template to take the mask setting and configure it in the form. The mask set by the form builder is captured in the rendering of the timepicker itself.

Now when you build the project and deploy your time field, you have a fully developed time form field type, complete with the proper JavaScript behavior and with additional settings.

« Adding Settings to Form Field TypesForms Storage Adapters »
この記事は役に立ちましたか?
0人中0人がこの記事が役に立ったと言っています