2

I'm trying to reinitialize/ redraw all MDC components for form elements when their values change via javascript, but so far my attempts have fallen short. Is there an easy way to achieve this with a built in MDC method that I'm unaware of?

I created a custom way to reload the MDC components with a data-mdc-reload html attribute that fires on click but this isn't quite doing the job.

Here's a codepen showing the issue: https://codepen.io/oneezy/pen/XvMavP

  • click the UPDATE FORM VALUES button to add data
  • the VALUE output in red means the component is broke/ blue means it works
  • click the RESET button to reset data to initial state (this is broke too)


Javascript

    // MDC Reload Component
    function mdcReload(time = 1) {
        var components = mdc.autoInit();
        let reloadComponents = document.querySelectorAll('[data-mdc-reload]');

        for (const reloadItem of reloadComponents) {
            reloadItem.addEventListener("click", async () => {

                setTimeout(function() {
                    components.forEach((c) => c.layout && c.layout());
                }, time);

            });
        }  
    }

    // Initialize MDC Components
    mdcReload();
Oneezy
  • 4,881
  • 7
  • 44
  • 73

2 Answers2

2

You can use the Foundations and Adapters provided by MDC. I would suggest you make a MDC instance of every component and use the built in methods in mdc.COMPONENT.foundation_.adapter_.

Here is the modified pen

The issue was that you need to call floatLabel(true) to let the labels float after you set their values.

if (c.foundation_.adapter_ && c.foundation_.adapter_.floatLabel) {
  c.foundation_.adapter_.floatLabel(true);
}

Furthermore I changed the select component to

// $(MDCselect).val('Option 3');
// Instantiate the MDC select component.
const mdcSelect = mdc.select.MDCSelect.attachTo(document.querySelector('.mdc-select'));
mdcSelect.foundation_.adapter_.setValue('Option 3');

Hope it helps !

Valentin
  • 400
  • 1
  • 4
  • 14
1

I found that the easiest way to refresh the labels for the MDC components after setting a custom value via javascript is to send a Blur event to the input like this:

yourMDCInput.dispatchEvent(new Event('blur'))

This will leave the MDC component to decide which action it has to take, so it floats the label if there is a value set or resets the label if there is no value set.

It is quite annoying, but without digging into the code of the MDC foundation to find a better solution, I couldn't spot any better solution in the docs (which are incomplete and partly wrong anyways).

If you can, try using the MDC class instance to set your values - in that case, the MDC component is informed about the change and will behave as intended. When using autoInit, please note that the docs say the MDC class instance is attached to the root <div> while it is actually attached to the <label> where the data-mdc-auto-init attribute is set.

Assuming you wrap an MDCTextField in a <div id='my-text-field'>, you could do something like:

document.querySelector('#my-text-field label').MDCTextField.value = 'hello world'

and the field will update as expected.

Lupinity Labs
  • 2,099
  • 1
  • 15
  • 23