Material-design-lite: Dynamically changing input (.mdl-textfield) text with Javascript does not mark it as dirty

Created on 8 Jul 2015  路  20Comments  路  Source: google/material-design-lite

Demo: http://codepen.io/anon/pen/qdYEWw

Expected behavior: Clicking the button (and thus modifying the text) should add the is-dirty class to the input's parent, which would then move the label to the top of the input.

Actual behavior: Upon clicking the button, the input's value changes, but the input's parent is not marked as dirty, so the label appears on top of the input's text.

Side note: I've had a lot of fun playing with this so far. Keep up the good work!

Documentation Textfield

Most helpful comment

The is-dirty class is applied on the div that contains the textfield. So you need to apply this class on this div.
Try it:
http://codepen.io/anon/pen/EjRLVL

All 20 comments

is-dirty is not the class, it is is-focused. And that is because the input is not focused via the JS, the value is simply modified.

I think we could do better with input with a value though, the label shouldn't return since the value text is difficult to read.

@Garbee
After manually entering text into the input, when it is blurred, its parent gets the class is-dirty if the input's value is not empty, which tells the label to go to the top of the input, rather than inside of it.

However, when using Javascript to set the input value, its parent does not receive the 'is-dirty' class, which is what is producing this issue.

This demo more accurately demonstrates the issue: http://codepen.io/anon/pen/WvJNWp - Manually edit the text-field (which marks it as dirty), then click the button to remove the is-dirty class.

Ah, yea detecting input from user to assign is-dirty, thanks for spelling that out (long day.)

Hmm... I'm not sure how we could handle this without observers (not widely supported.) Looks like something that _may_ be up to developers to understand and implement in their code (which means our action is to document the occurrence.)

Any ideas on solving this internally anyone?

At the moment I'd favor documentation of the occurrence on our end. Any introduction of a more complex dirty-checking system either requires that we build this in and support it (adds weight), support shims for Object.observe() (rather avoid) or find another way of achieving this that is opinionated. I think docs with suggestions is lightweight whilst staying useful.

The is-dirty class is applied on the div that contains the textfield. So you need to apply this class on this div.
Try it:
http://codepen.io/anon/pen/EjRLVL

I'm aware that is-dirty needs to be added to the div that contains the textfield. The reason I made this issue is to discuss the fact that dynamically editing the text of a mdl-textfield does not do this, whereas user input does. I was not sure if this was intended behavior, or an unnoticed issue.

On a side note: Your example adds the is-focused class to the textfield's parent instead of is-dirty. If you click the button, then manually focus and blur the textfield, that class is removed, resulting in the same issue that I reported.

The class is-invalid is also not changed properly. There is any form to invoke an internal function to scan the textfield and update the parent?

In PR #1116 I added new public methods that will let you directly check for the different states. This will mean after you call a value edit, you then call checkDirty on the component. If this lands then it will make checking states and having the correct UX changes much simpler.

Garbee, where can I found the public methods with some documentation?
Thank you!

@nettopaulo Right now, you can check the changes in the PR. They are self-explanitory.

The JS doc story is still in the works, so nothing for that is on the existing site.

Remember, this is _NOT_ currently accepted. It still needs to be accepted by two other core team members before it is pushed in. We could scratch it and do something else. This is purely informational that some updates are in the works to help with this, nothing is set in stone yet.

Is there any guidance on a workaround in the meantime? I've got the same issue with my code and not sure how to overcome it.

In my case I'm using react if that matters.

We don't support react, but the PR was merged and the methods should be available in the current stable. To check dirty state after changing the value, call the MaterialTextfield.checkDirty() method against the node where the js class is assigned. For example: document.querySelector('mdl-js-textfield).MaterialTextfield.checkDirty().

This still needs proper documenting before closing this issue out.

I'm also having this problem when using react and setting the value of an mdl-textfield through props. The value is updated but not the validation.

Solved it, for now, by triggering a dummy input event (that MaterialTextfield listens to) in componentDidUpdate:

render: function () {
    return <input value={this.props.myValue} ref="myInput" />;
},

componentDidUpdate: function () {
    let myInput = this.refs['myInput'];
    myInput.dispatchEvent(new Event('input'));
}

Thanks @Garbee . Updated my code to use v1.0.5 plus the following code and worked like a charm. This means I didn't need to do use your work around @snallfot (thanks for the suggestion though!)

componentDidUpdate: function() {
  this.refs.inputContainer.getDOMNode().MaterialTextfield.checkDirty();
},

You have to manually add the 'is-dirty' class to the parent, like this:

$('#sample3').parent().addClass('is-dirty');

Example:
http://codepen.io/anon/pen/mVyzBr

Probably quite off topic, But I'm having the issue that is-dirty is not being set in my application.
I'm running an Angular2 Project, whenever I use ngControl the is-dirty is not applied. It's fine when using ngModel (Without ngControl).

Any thoughts perhaps?

Now that the methods are implemented, the remaining work is just a duplicate of #1008. Closing.

Add a unique class to all inputs that you need to check for dirty, select them all with querySelectorAll, then apply the MaterialTextfield.checkDirty() method to each via a loop.

var dialogInputs = doc.querySelectorAll('.dialog-inputs');
for (var i = 0, l = dialogInputs.length; i < l; i++) {
  dialogInputs[i].MaterialTextfield.checkDirty();
}

I came across this again. Something like below should work for everyone:

  //MDL Text Input Cleanup
  function mdlCleanUp(){
    var mdlInputs = doc.querySelectorAll('.mdl-js-textfield');
    for (var i = 0, l = mdlInputs.length; i < l; i++) {
      mdlInputs[i].MaterialTextfield.checkDirty();
    }  
  }
Was this page helpful?
0 / 5 - 0 ratings

Related issues

rafaelcorreiapoli picture rafaelcorreiapoli  路  3Comments

ktodyruik picture ktodyruik  路  5Comments

baldram picture baldram  路  4Comments

J2TEAM picture J2TEAM  路  3Comments

tleunen picture tleunen  路  5Comments