telerik / kendo-ui-core

An HTML5, jQuery-based widget library for building modern web apps.
http://www.telerik.com/kendo-ui
Other
2.54k stars 1.91k forks source link

Editable: can't set new field value programmatically if input is already invalid #5099

Open Casimodo72 opened 5 years ago

Casimodo72 commented 5 years ago

Kendo Editable: can't set new field values programmatically on an ObservableObject if the input's value is currently invalid.

The Kendo Editable listens for the "set" event of an ObservableObject, then it tries to validate the input element without the new value being set yet.

E.g. if one has a "required" input and the input's value is initially empty (and thus invalid) then one can't set a new value programmatically using myobservable.set("myProp", value). The Editable will call e.preventDefault() in its Editable._validate() function, resulting in the new value being ignored in the ObservableObject.set() function.

This results in a behavior that sometimes (if the input is currently valid) allows manipulation of the ObservableObject fields and sometimes does not allow manipulation (if it is currently invalid).

matanasov commented 5 years ago

Could you please provide a runnable example (DoJo) that demonstrates the problem you need fixed?

Casimodo72 commented 5 years ago

No, I'm not motivated to provide an example ;-) But I can report what I did to fix this for my stuff. I translated the Kendo Editable thingy into a CustomEditable TypeScript class (not pretty though) here.

I set the model field values now via my edit form component. This way I can set a flag on my CustomEditable in order to skip validation entirely.

If you inspect Kendo's Editable code: it binds to the "set" event of the ObservableObject but does not use the field value of that event in the _validate function. It only uses the value of the input element. This should give people enough information to see an issue.

Maybe one could fix this by at least trying to compare the given field value against the value of the input element. If they don't match then something is fishy, right?

Alex-Bubblemaster commented 5 years ago

@Casimodo72 , can you confirm that you would like to set a value to an invalid field while in edit mode programmatically with the set() method like pictured in the screenshot?

image

Casimodo72 commented 5 years ago

@Alex-Bubblemaster: Yes. If there's a required attribute on the input element, then the Editable will incorrectly prevent that. Note: I'm using only the kendo.data.Model and the kendo.data.DataSource in my component. No grid or any other higher level Kendo component is used.

Dojo: https://dojo.telerik.com/ENeSIzop Here setting the field "date2" does not work.

Since I don't know if those anonymous Dojos are permanently persisted:

<div id="view" style="display:flex">
      <div>
            <input data-role='datepicker' id='date' name='date' data-val='true'  />
            <span class='k-invalid-msg' data-for='date'></span>
        </div>

        <div>
            <input data-role='datepicker' id='date2' name='date2' data-val='true' required=''/>
            <span class='k-invalid-msg' data-for='date2'></span>
        </div>

        <div>
            <input data-role='datepicker' id='date3' name='date3' data-val='true' />
            <span class='k-invalid-msg' data-for='date3'></span>
        </div>
  <div>
const $view = $("#view");
const Thingy = kendo.data.Model.define({
    id: "id",
    fields: {
        "date": {
            type: "date", validation: { required: true }
        },
        "date2": {
            type: "date", validation: { required: true }
        },
        "date3": {
            type: "date", validation: { required: true }
        }
    }
});

const thingy = new Thingy({
    id: kendo.guid()
});

const opts = {
    model: thingy,
    clearContainer: false
};

const editable = $view.kendoEditable(opts).data("kendoEditable"); 

// Not touching first date field: thingy.set("date", new Date());
thingy.set("date2", new Date());
thingy.set("date3", new Date());

editable.validatable.validate();        
linaori commented 3 years ago

I ran into this issue as well, I've created a forum post: https://www.telerik.com/forums/adding-required-true-to-form-validation-doesn-t-let-me-set-values-programatically

I'm not sure what the proper way is to re-use a form (in my case inside a wizard), so I hit this obstacle. It's really annoying to not be able to do the most basic thing this way.

I found a work-around with this in the form:

validatable: {
    validateOnBlur: false,
},

It's not ideal, but at least it works.