How to trigger DataBinding Validation for all Controls? - validation

I have an OpenUI5 form consisting of a number of Inputcontrols. These Inputcontrols are bound to a model using the OpenUI5 DataBinding as described in the documentation.
For example:
new sap.m.Input({
value: {
path: "/Position/Bezeichnung",
type: new sap.ui.model.type.String(null, {
minLength: 1,
maxLength: 128
})
}
})
As in the example above I'm using constraints on the stringlength.
When a User changes the Value of the Input, the Validation is triggered and according to the Validationresult one of the functions descripted here is called.
In these functions I'm setting the ValueState of the control like this:
setupValidation: function() {
var oCore = sap.ui.getCore();
oCore.attachValidationError(function (oEvent) {
oEvent.getParameter("element").setValueState(sap.ui.core.ValueState.Error);
});
oCore.attachValidationSuccess(function (oEvent) {
oEvent.getParameter("element").setValueState(sap.ui.core.ValueState.None);
});
oCore.attachFormatError(function (oEvent) {
oEvent.getParameter("element").setValueState(sap.ui.core.ValueState.Error);
});
oCore.attachParseError(function (oEvent) {
oEvent.getParameter("element").setValueState(sap.ui.core.ValueState.Error);
});
},
Let's assume the bound model variable is initial.
I'm loading the view, the property value is parsed and displayed as empty.
The Validationerror/Parseerror method is not called although the constraints are not met.
This seems to be standard behaviour of OpenUI5. Only changes in the Control will be a validated.
Now let's assume I've a submit button and the Value of the Inputcontrol is still empty. When the user hits the submit button I'd like to trigger the DataBinding Validation for all childcontrols of my view. This would validate the above mentioned input and would result in an errorstate.
My question is: How can I trigger the databinding validation for all childcontrols of my view?
There is another question on SO where the poster asks for a way to define required fields. The proposed solution is to call getValue() on the control and validate the value manually. I think this is kind of cumbersome as formating and constraint information and logic is already present.

I suggest looking into field groups.
An example here in the UI5 docs
Field Groups allow you to assign group IDs to the input fields. Then you can call all of the input fields at once. You can set the name property and required property on each <Input> separately in your view, allowing you to handle some logic when you perform validation.
You can call this.getView().getControlsByFieldGroupId("fieldGroupId"), which will return an array of the input controls. Then you can loop through the controls, pass them through your logic, and use setValueState() to show the results.
Or, you can assign the validateFieldGroup event on the parent container, which is usually a form, but can be anything like a <VBox> that contains the controls. When the users focus moves out of the field group, the event is fired. You can then use the event handler in your controller to perform the validation.
In your case, I would assign a press event to your submit button, and in the handler, call the field group by ID and loop through the controls. At the end of your function, check to see if all fields are validated before continuing.
View
<Input name="email" required="true" value="{/user/email}" fieldGroupIds="fgUser"/>
<Input name="firstName" required="false" value="{/user/firstName"} fieldGroupIds="fgUser"/>
<Button text="Submit" press="onSubmit"/>
Controller
onSubmit: function() {
var aControls = this.getView().getControlsByFieldGroupId("fgUser");
aControls.forEach(function(oControl) {
if (oControl.getRequired()) {
//do validation
oControl.setValueState("Error");
oControl.setValueStateText("Required Field");
}
if (oControl.getName() === "firstName") {
//do validation
oControl.setValueState("Success");
}
});
var bValidated = aControls.every(function(oControl) {
return oControl.getValueState() === "Success";
});
if (bValidated) {
//do submit
}
}

The concept goes like this.
Use custom types while binding, to define validations. Validation
rules go inside these custom types (in the method 'validateValue').
When Submit is pressed, loop through the control hierarchy and
validate each control in your view. (By calling 'validateValue'
method of the Custom Type).
Validator (https://github.com/qualiture/ui5-validator ) uses this concept and it is a small library to make your life easy. Its main advantage is that it recursively traverses through the control library.
Using Message Manager (using sap.ui.get.core().getMessageManager() ) is the way to show the validation messages on the UI control.

Triggering data binding validations is not possible. Rather for empty fields that are having required property true you can do a work around using jQuery.
Please refer my answer to this same problem at Checking required fields

Related

Disable button in Nativescript Raddataform

I'm using commitMode="Immediate" and I'm trying to disable my save button when any input is invalid.
What is the recommended approach to achieve this?
I understand that I can just set a variable when using "manual" mode from my component, but I can't find any event that represents a change in validity of preferably the complete Raddataform (otherwise of a single property) when using Immediate validation.
You can do this by listening for validation events and then updating your model.
From this example, add the propertyValidated listener:
<RadDataForm #propertyValidated="onPropertyValidated" ...></RadDataForm>
Then change your state:
methods: {
onPropertyValidated({ object, propertyName, entityProperty }) {
this.$refs.button.enabled = !entityProperty.isValid;
}
}
You will probably want to keep track of all validations in this case, or you could use the complete dataform.hasValidationErrors().
This is the NS-Vue solution, but totally applicable in Angular.
Add a #propertyValidated="onValidateForm" event listener that triggers on each validation. Then you can use hasValidationErrors() on the form to see if the form is valid. The only trick is that is has to be wrapped in a setTimeout(), like so:
onValidateForm(event) {
setTimeout(() => {
this.validated = !event.object.hasValidationErrors();
console.log("form valid: " + this.validated);
}, 100);
}
For a complete solution, see this playground.

Delaying Kendo Validation until Submitting the form

I have marked my controls with the Required attribute.
This has caused them to not only error on the lost focus event ( which is good ) but the problem is it won't even let me continue entering values in OTHER columns and controls of the grid on the form until I first type something for the required control.
Is there a way to delay this required validation to when I submit the form?
You can bind the .getKendoValidator(); method to your form which allow you to delay your validation.
You need to set button type ="Submit"
Refer the following line of code :-
var form_validator = $("#form_reg").kendoValidator({
rules: {
/*..*/
},
messages: {
/*..*/
}
}).getKendoValidator();
Also note that as the Validator is attached to a form element,
the validation will be executed automatically when the form is submitted, which in this case is when the button is clicked. Therefore, there is no need to manually call the validate method.
Note:-execute some custom logic, like alert to the user, when form is validated you may use
validate event.

Kendo UI grid - batch update not executed

I'm implementing a simple (at least ,that was the goal) Kendo UI grid that displays two columns: one holding a checkbox, bound to a boolean, and one holding a display name for the item. The checkbox column has a simple template, and the change() event of the checkbox is handled so that the model in the datasource gets updated. I have verified this, and it works.
The data source has been configured for batch, and defines a transport for read and update. Both call a function that perform the ajax call. As I said before, the read function is handled as expected. However, the update function defined on the transport is not. The sync() on the datasource is triggered with a simple button whose click event is hooked to a function that calls datasource.sync() (or grid.saveChanges()).
transport: {
read: function(options) {
return loadStuff(options);
},
update: function (options) {
return updateStuff(options);
}
}
When debugging in the Kendo UI code, it looks like the models attribute on the ModelSet is always empty, and therefore the sync() decides that there's nothing to sync. Anyone got a clue what is happening here?
UPDATE:
Looks like something may be wrong when handling the checkbox check / uncheck. Apparently I should use something like
$('#divGrid').on('click', '.chkbx', function() {
var checked = $(this).is(':checked');
var grid = $('#divGrid').data().kendoGrid;
var dataItem = grid.dataItem($(this).closest('tr'));
dataItem.set("Selected", checked);
});
Unfortunately, it looks like the set() method is not defined on the data item. When debugging, it only contains the data, and no Model object having the set() method.
UPDATE 2:
Tried wrapping the data returned from the ajax call in a model defined with Model.define(). That seems to solve the issue of the model not being dirty, as the _modified property on the model returns true. However, the models array in the ModelSet remains empty. Is this a bug in Kendo UI, or am I going the wrong way?
You don't actually need to bind to click event on the checkboxes.
I´ve posted an example on using it in JSFiddle where you can see it running. This example displays in a grid two columns: first text (tick) and second boolean rendered as a checkbox (selected); the update is batch (so, it's pretty close to what you have).
Questions to keep in mind are:
For displaying the checkbox while not in edit mode, you should define a template, something like this. You might realize that the checkbox is in disabled state by default since you want to edit it as other fields (selecting the cell first). This also guarantees that the model is correctly updated:
{
field : "selected",
title : "Selected",
template: "<input type='checkbox' name='selected' #= selected ? 'checked' : '' # disabled/>"
}
Define in the model that this field is boolean:
schema : {
id : "id",
model: {
fields: {
symbol : { type: "string" },
selected: { type: "boolean" }
}
}
},
Define the transport.update function, something like:
transport: {
read : function (operation) {
// Your function for reading
},
update: function (operation) {
// Display modified data in an alert
alert("update" + JSON.stringify(operation.data.models, null, 4));
// Invoke updating function
// that should ends with an operation.success(the_new_data)
// In this example just say ok
operation.success(operation.data.models)
}
}
EDIT: If you want to be able to modify the checkbox state without having to enter in edit mode first, you should:
Remove the disabled from the template:
{
field : "selected",
title : "Selected",
template : "<input type='checkbox' name='selected' #= selected ? 'checked' : '' #/>"
},
Then bind the click event on checkboxes to the following handler function:
$("#stocks_tbl").on("click", "input:checkbox", function(ev) {
var dataItem = grid.dataItem($(this).closest('tr'));
dataItem.set("selected", this.checked);
});
Where #stocks_tbl is the id of the div that contains the grid. You might see it running here.
NOTE: It's important the on with the three parameters for making it live

knockout js - How to do Conditional Binding on a dropdownlist

I've got a Knockout viewmodel populated from a variety of Mvc actions.
A Category is chosen from the first dropdown (say Fruit, Meat, Drinks etc).
A second dropdown is automatically populated from the first choice. However, there may be 2 matches for fruit (say Apples, Oranges), 2 for meat (say Beef, Lamb) and many choices for drink (several hundred).
My page currently displays a search box depending on the Category chosen.
I was wondering how to automatically bind the second dropdown for Fruit & Meat, or wait and do the bind from the results of the search query.
Sorry this is vague - twitchy client! Very new to KnockoutJs.
Thanks in advance.
If I understood you right, you could create a method in your viewmodel which you bind to the change event of the dropdown.
Example method:
var myViewModel = {
firstDropDownArray: ko.observableArray([]),
secondDropDownArray: ko.observableArray([]),
// Validates Selection
validateSelection: function (item) {
var anotherList;
switch (item.toUpperCase()) {
case "FRUIT":
// Do something...
break;
case "DRINKS":
// Do something else...
break;
default:
}
}
};
Your Dropdown can bind then to the method like this:
<select id="FirstDropDown" data-bind="options: myViewModel.firstDropDownArray, <any other binding options>, event: {change: myViewModel.validateSelection(currentItem)}">
</select>
As stated here: event-binding,
When calling your handler, Knockout will supply the current model
value as the first parameter.
I'm assuming this means the currentItem will be the selected item when you are calling the method.
I know in my sample code I wrote item.toUpperCase() but that is just assuming the item is passed as a string. This syntax obviously has to change depending on how you have declared and populated your dropdown but in essence you still should be able to write a method in your viewmodel you can bind then to the change event,..or any other event you like.

JQuery - which form was submitted?

I have a page of products and for each of them, I want to have a form that uses AJAX to update the session. I've done this bit - just providing background.
I use the product's ID to create a different form class and name for each form, so each form is called something like this_form_name_567 and the next would be this_form_name_568 and so on.
There is a submit button per form. I'm having trouble figuring out
Which event is best to use so that the correct form will be identified when a submit button is clicked?
Once clicked, how to then make sure the correct value is taken from a hidden field (unique ID) within the submitted form so that I can populate a line of code such as:
$.post("compare_response.php", {compare_this: $("#compare_this").val()}, function(data){
}
You can use the .closest tree traversal method to get the form in which the button of interest is nested:
$("input[type=submit]").click(function() {
alert($(this).closest("form").attr("id"));
});
or even simpler, just get the element's form property :)
$("input[type=submit]").click(function() {
alert(this.form.id);
});
You can try it out here.
You can get the form you are submitting like this:
$('form').submit(function() {
var yourForm = $(this);
var hiddenValue = $(this).find('input[type=hidden]').val();
});
Of course you can get the hidden value differently, or if you have more than one hidden you'll have to give a little more information about it.

Resources