javascriptgrailsgrails-3.3

Grails: add custom javaScript to field rendered in f:all


I have some fields that are being rendered using the <f:all> tag.

Three of those fields need an "onClick" attribute so I can turn on/off some manadatory settings on other fields upon clicking.

I have added the correct javascript function and tried initializing it with an init() function in the body's onload section:

<body onLoad="init()">
...
</body>

The init function looks like this:

function init() {
                const exportElement = document.getElementById('export');
                const importElement = document.getElementById('import_');
                const transitElement = document.getElementById('transit');
                exportElement.onclick(this.validate());
                importElement.onclick(this.validate());
                transitElement.onclick(this.validate());
            }

The section in the gsp page looks as followed:

    <g:form resource="${this.agreement}" method="POST">
        <fieldset class="form">
            <f:all bean="agreement" associationValues="${associationValues}"/>
        </fieldset>
        <fieldset class="buttons">
            <g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
        </fieldset>
    </g:form>

My understanding is that the elements are not yet rendered when the onload() function is called since it's called immediately on load. Therefore this idea cannot work, so here's what I'm thinking:

I know it's possible to remove some elements from the f:all scope using the "except" attribute. Can I somehow add the requirements element containing the onclick() attributes manually in a specific order or will I need to completely switch to a manual fields implementation?

Thanks for any pointers.


Solution

  • The f:all tag is the Grails Fields plugin. You can override the HTML the plugin generates. I can show you mine first. So, you can have some idea. It is easier than doing this in the client side field by field. I will try to do the code for your specific case if I am able to.

    I have a bunch of Date fields. The Fields plugin will generate the HTML to display the date like 2021-11-07 00:00:00:0000 (for example). So, instead of formatting all my Date fields one by one in the gsp files, I follow the instruction in the Fields plugin document here:

    https://grails-fields-plugin.github.io/grails-fields/latest/guide/index.html#customizingFieldRendering

    I create a set of folder in the "views" folder. The folder path is "views/_fields/date". This path tells the Fields plugin to generate the HTML for all the Date fields in my project.

    I then create a gsp file called "_displayWidget.gsp". This gsp file tells the plugin to generate all the Date fields for display only.

    This is in the gsp file:

    <g:formatDate date="${value}" format="MM/dd/yyyy"/>
    

    The Fields plugin will now display all the dates in the MM/dd/yyyy format automatically.

    In your case, it looks like you have a field called "export" in your domain. To follow the instruction, you will create a folder path using this format:

    grails-app/views/controllerName/propertyName/
    

    So, you will create the display widget gsp file in this folder like:

    "views/yourControllerName/export/_displayWidget.gsp"
    

    replace "yourControllerName" with the name of your actual controller that the domain has the "export" field.

    So, the HTML in the _displayWidget.gsp file may look like this.

    <button onclick="validate()">${value}</button>
    

    Now the Fields plugin will generate this HTML every time it sees your "export" field.

    For your import_ and your transit fields, you create the folder like this and put your HTML code in the gsp file.

    "views/yourControllerName/import_/_displayWidget.gsp"
    "views/yourControllerName/transit/_displayWidget.gsp"
    

    The Fields plugin will match the name of the folder to the name of your field to generate the HTML.