[JSFIELD-25] Send parameters in map Created: 21/Dec/22  Updated: 04/Feb/23  Resolved: 04/Feb/23

Status: Resolved
Project: Java Script UI (App and Dialog Fields)
Component/s: None
Affects Version/s: 1.2.1
Fix Version/s: 1.2.2

Type: Bug Priority: Neutral
Reporter: Teresa Miyar Assignee: Adrien Manzoni
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Relates
relates to INCUBATOR-13 JS Field - Add Parameters | Improvement Closed
Template:
Acceptance criteria:
Empty
Date of First Response:

 Description   

Getting error when sending complex parameters:

label: Bouncy Ball Scene
form:
  implementationClass: info.magnolia.ui.javascript.form.FormViewWithChangeListener
  properties:
    title:
      $type: textField
      i18n: true
    temp:
      label: Temp
      $type: javascriptField
      fieldScript: /magnolia-babylonjs-xrworld-lm/webresources/engineOptionsField.html

 

This isn't working due to:

Caused by: elemental.json.JsonException: Map is missing generics parameters: availableSettings: antialias: textContent: 'Antialias' type: 'boolean' adaptToDeviceRatio: textContent: 'Adapt to Device Ratio' type: 'boolean' somethingElse: textContent: 'Something Else' type: 'number'
4:41
And here's the stack trace if you need it:
4:41
15-Dec-2022 16:11:40.085 SEVERE [http-nio-8080-exec-4] com.vaadin.server.DefaultErrorHandler.doDefault 
java.lang.RuntimeException: elemental.json.JsonException: Map is missing generics
at com.vaadin.server.JsonCodec.encodeObject(JsonCodec.java:815)
at com.vaadin.server.JsonCodec.encode(JsonCodec.java:743)
at com.vaadin.server.LegacyCommunicationManager.encodeState(LegacyCommunicationManager.java:107)
at com.vaadin.server.AbstractClientConnector.encodeState(AbstractClientConnector.java:292)
at com.vaadin.server.communication.SharedStateWriter.write(SharedStateWriter.java:67)
at com.vaadin.server.communication.UidlWriter.write(UidlWriter.java:176)
at com.vaadin.server.communication.UidlRequestHandler.writeUidl(UidlRequestHandler.java:125)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:93)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1637)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:464)
at info.magnolia.admincentral.AdmincentralServlet.service(AdmincentralServlet.java:119)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:779)
at info.magnolia.cms.filters.ServletDispatchingFilter.doFilter(ServletDispatchingFilter.java:148)
at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
at info.magnolia.cms.filters.CompositeFilter.doFilter(CompositeFilter.java:75)
at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
at info.magnolia.module.cache.executor.Bypass.processCacheRequest(Bypass.java:58)
at info.magnolia.module.cache.executor.CompositeExecutor.processCacheRequest(CompositeExecutor.java:66)
at info.magnolia.module.cache.filter.CacheFilter.doFilter(CacheFilter.java:164)
at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
at info.magnolia.cms.i18n.I18nContentSupportFilter.doFilter(I18nContentSupportFilter.java:85)
at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
at info.magnolia.virtualuri.VirtualUriFilter.doFilter(VirtualUriFilter.java:102)
at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
at info.magnolia.cms.filters.RangeSupportFilter.doFilter(RangeSupportFilter.java:78)
at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
at info.magnolia.cms.security.BaseSecurityFilter.doFilter(BaseSecurityFilter.java:57)
at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
at info.magnolia.cors.AbstractCorsFilter.doFilter(AbstractCorsFilter.java:77)
at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
at info.magnolia.cms.filters.CompositeFilter.doFilter(CompositeFilter.java:79)
.... MESSAGE TOO LONG
Caused by: elemental.json.JsonException: Map is missing generics
at com.vaadin.server.JsonCodec.encodeMap(JsonCodec.java:962)
at com.vaadin.server.JsonCodec.encode(JsonCodec.java:716)
at com.vaadin.server.JsonCodec.encodeStringMap(JsonCodec.java:1029)
at com.vaadin.server.JsonCodec.encodeMap(JsonCodec.java:972)
at com.vaadin.server.JsonCodec.encode(JsonCodec.java:716)
at com.vaadin.server.JsonCodec.encodeObject(JsonCodec.java:804) 

 



 Comments   
Comment by Scot Rhodes [ 02/Feb/23 ]

Here's the original dialog that broke due to the Map<String,Object> issue (the broken bits being commented out):

label: Bouncy Ball Scene
form:
  implementationClass: info.magnolia.ui.javascript.form.FormViewWithChangeListener
  properties:
    title:
      $type: textField
      i18n: true
    temp:
      label: Temp
      $type: javascriptField
      fieldScript: /magnolia-babylonjs-xrworld-lm/webresources/engineOptionsField.html
      # TODO This isn't working due to:  Caused by: elemental.json.JsonException: Map is missing generics
#      parameters:
#        availableSettings:
#          antialias:
#            textContent: 'Antialias'
#            type: 'boolean'
#          adaptToDeviceRatio:
#            textContent: 'Adapt to Device Ratio'
#            type: 'boolean'
#          somethingElse:
#            textContent: 'Something Else'
#            type: 'number' 

And the old version of the JS dialog field that I was trying to use:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
</head>
<body>

<select id="input">
    <!-- <option value="">--Please choose an option--</option> -->
</select>

<div id="inputs">

</div>

<script>
    let input = document.getElementById('input');
    let inputs = document.getElementById('inputs');
    let correlationId;
    let availableSettings = [
        {
            name: 'antialias',
            textContent: 'Antialias',
            type: 'checkbox',
        },
        {
            name: 'adaptToDeviceRatio',
            textContent: 'Adapt to Device Ratio',
            type: 'checkbox',
        },
        {
            name: 'somethingElse',
            textContent: 'Something Else',
            type:'number',
        },
        {
            name: 'somethingElsex',
            textContent: 'Something Elsex',
            type:'text',
        }
    ]

    let optionsSet = {};

    function getBooleanValue(val) {
        if (val.checked) {
            return 'true';
        }
        return 'false';
    }

    function setOptionValue(setting, inputField, value) {
        switch (setting.type) {
            case 'checkbox':
            case 'radio':
                if (value === 'true') {
                    inputField.checked = true
                } else {
                    inputField.unchecked = true
                }
                break;
            default:
                inputField.value = value
        }
    }

    function changeValue() {
        let val = {}
        Object.keys(optionsSet).forEach(key => {
            switch (optionsSet[key].type) {
                case 'checkbox':
                case 'radio':
                    val[key] = getBooleanValue(document.getElementById(key))
                    break;
                default:
                    val[key] = document.getElementById(key).value
            }
        })

        parent.window.postMessage({action: 'changeValue', correlationId, value: JSON.stringify(val)}, '*');

        // TODO Had to add this because "change" is failing in the below code.
        if (!optionsSet.hasOwnProperty(input.value)) {
            const newOption = availableSettings.find(item => item.name === input.value)
            addSetting(newOption)
            optionsSet[input.value] = newOption
        }
    }

    function createOption(value, textContent) {
        const option = document.createElement('option');

        option.value = value;
        option.textContent = textContent;

        return option;
    }

    function setOptions() {
        while (input.lastElementChild) {
            input.removeChild(input.lastElementChild);
        }

        input.appendChild(createOption('', '--Please choose an option--'));

        availableSettings.forEach(setting => {
            if (!optionsSet.hasOwnProperty(setting.name)) {
                input.appendChild(createOption(setting.name, setting.textContent))
            } else {
                addSetting(setting, optionsSet[setting.name].value)
            }
        });
    }

    function addSetting(setting, value) {
        let settingInputDiv = document.createElement('div')
        settingInputDiv.id =setting.name + '-div'
        let settingInputLabel = document.createElement('label')
        settingInputLabel.setAttribute('for', setting.name)
        settingInputLabel.innerHTML = setting.textContent
        let settingInputField = document.createElement('input')

        settingInputField.setAttribute('type', setting.type)
        settingInputField.setAttribute('id', setting.name)
        // TODO Is this right? Still doesn't help if last value wasn't changed.
        settingInputField.addEventListener('change', changeValue);
        setOptionValue(setting, settingInputField, value)
        settingInputDiv.append(settingInputLabel)
        settingInputDiv.append(settingInputField)
        inputs.append(settingInputDiv)
    }

    // SAVE BUTTON
    // TODO Add changeSelect event listener to update 'inputs'
    // Add Event Listener to each component in 'addSetting'
    input.addEventListener('change', changeValue);

    window.addEventListener(
        'message',
        function (event) {
            switch (event.data.action) {
                case 'init':
                    const value = event.data.state.value ? JSON.parse(event.data.state.value) : {}
                    correlationId = event.data.correlationId;
                    Object.keys(value).forEach(key => {
                        optionsSet[key] = availableSettings.find(item => item.name === key)
                        optionsSet[key].value = value[key]
                    })
                    setOptions();
                    break;
                // case 'change':
                //     console.log('changing here')
                //     const newConditionalField1 = event.data.state.formFields.temp;
                //     console.log('newConditionalField1: ' + newConditionalField1)
                //     console.log(event.data.state.value);
                //     if (newConditionalField1) {
                //         if (conditionalField1 !== newConditionalField1) {
                //             let result = availableSettings.find(item => item.name === newConditionalField1);
                //             optionsSet[result.name] = result
                //             setOptions(result.name)
                //             addSetting(result)
                //         }
                //     }
                //     break;
                default:
            }
        },
        false
    );
</script>
</body>
</html>

<!--antialias={true} adaptToDeviceRatio={true} canvasId="sample-canvas"--> 
Comment by Scot Rhodes [ 02/Feb/23 ]

In case it's not clear, the JS Code that broke starts towards the end, starting with:

// case 'change': 
Generated at Mon Feb 12 02:16:22 CET 2024 using Jira 9.4.2#940002-sha1:46d1a51de284217efdcb32434eab47a99af2938b.