ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false' - angular2-forms

I have kendo date picker and a div, which showing "Required" message in angular4 reactive form.
<kendo-datepicker #datePicker=appDateFormat
[(value)]="questionControlInfoData.currentValue"
[format]="dateFormat"
[formatPlaceholder]="{ year: 'yyyy', month: 'mm', day: 'dd' }"
[formControlName]="questionControlInfoData.formControlName" [disabled]="questionControlInfoData.disabledControl"
[appDateFormatOnly]="dateValidationFormat"> </kendo-datepicker>
<div> <span *ngIf="!isValid()" [class.star]="!isValid()">This field is required</span> </div>
The reactive form is loading the controls dynamically.
The "appDateFormatOnly" is a directive used for date format validation.
I have a method "isValid()", which is returning one boolean value based on some condition.
isValid() {
var dateValue = this.qnaFormGroup.controls[this.questionControlInfoData.formControlName].value;
var hasDateValue = (dateValue !== undefined && dateValue !== "");
if (hasDateValue && !this.datePickerDirective.isValid) {
this.qnaFormGroup.controls[this.questionControlInfoData.formControlName].setErrors({ 'invalidDate': true });
}
var isValid = this.qnaFormGroup.controls[this.questionControlInfoData.formControlName].touched ? this.qnaFormGroup.controls[this.questionControlInfoData.formControlName].valid
: this.qnaFormGroup.controls[this.questionControlInfoData.formControlName].dirty ? this.qnaFormGroup.controls[this.questionControlInfoData.formControlName].valid : true;
return hasDateValue || isValid;
}
Inside this "isValid()" method I am adding error to the control based on some condition using the "setErrors" angular4 method.
The"isValid()" is called if anything changed in this reactive form.
The issue is:
Sometimes I am getting the error "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'." while typing the date value in the date picker..
I have analyzed and found that the issue is with adding error in the form control using "setErrors" method.
Could you please someone give any solution for this problem.

Related

KendoUI Inline Edit Numeric Text Box with other culture

I am using Kendo Grid (version 2014.1.318) with inline editing on "de-DE" culture. So the numbers should use a comma(,) as the decimal separator, eg: 79,5.
The Numeric Text Box in the grid is displaying the expected format when in "Edit" mode. No problem here. But when I click on "Update" button, it is sending "79.5" instead of "79,5" back to my server. My server is configured with the "de-DE" culture and the ModelBinder couldn't process numbers in that format and as a result, assigned ZERO to my variable.
Is this a known bug or am I missing something? Everything is fine when i use "en-US" culture or any culture that uses period(.) as its decimal separator.
Did you include the kendo.culture.de-DE.min.js file:
Did you change the kendo culture:
kendo.culture("de-DE");
At last you can also try to change the culture in the numeric text box:
#Html.Kendo().NumericTextBox().Culture("de-DE")
We are having the same problem for a year now. It seems it's on low priority for Telerik to solve this or we missed the solution.
This is how we solved it:
Pass this function to the data function of grid create and update like here:
.Update(update => update.Action("Update", "Gradings").Type(HttpVerbs.Put).Data("convertDecimals")))
function convertDecimals(data) {
for (var property in data) {
var value = data[property];
if (typeof value === "number") {
// if the number is integer
if (value % 1 == 0) {
data[property] = value.toString();
}
else {
data[property] = kendo.toString(value, "n");
}
}
}
}
and this on edit:
.Events(events => events.Edit("replaceDecimalSign"))
function replaceDecimalSign(data) {
var value = $(data).val();
var converted = value.toString().replace('.', ',');
$(data).val(converted);
}
Also you need the correct culture settings like alreay answered by MohQut.
kendo.culture("de-DE");

Kendo Timepickerfor formatting not working

I have an MVC Kendo Timepicker for that I am using. It works fine except that I can't format the time to Military time. After I add the formatting for Military time, once I select the time the validation doesn't pass and it tells me it must be a date. Is there a way to format the TimePickerFor to allow military time?
#using Kendo.Mvc.UI
#model DateTime?
#(Html.Kendo().TimePickerFor(m=>m)
.Value(#Model)
.Min("05:00")
.Max("00:00")
.Format("{0:HHmm}")
)
Update: This doesn't work with format being changed to .Format("HHmm")
Ok, so thanks to the Kendo people, I found the answer. The script may need some work depending on the situation. My TimePickerFor is in an Editor Template which sits in a grid with other timepickers and numeric text boxes. Only thing with this way of working is that once the script is fired, the numeric boxes used this script also to validate (hence the return $.isNumeric(input.val()) line. Hope this helps someone else out.
TimePickerFor Control:
#using Kendo.Mvc.UI
#model DateTime?
#(Html.Kendo().TimePickerFor(m=>m)
.Value(#Model)
.Format("HHmm")
.HtmlAttributes(new{data_format="HHmm"})
.ParseFormats(new[]{"HHmm"})
)
<script>
var originDate = kendo.ui.validator.rules.mvcdate;
kendo.ui.validator.rules.mvcdate = function(input) {
var format = input.attr("data-format");
if (input.val() == "") {
return kendo.parseDate("0000", format);
}
if (format) {
return kendo.parseDate(input.val(), format);
} else {
return $.isNumeric(input.val());
}
};
</script>
I think you have to remove the curly braces and make sure that is a valid format type. I also don't think the 0 is necessary.
Here's some formating documentation
http://docs.telerik.com/kendo-ui/getting-started/framework/globalization/dateformatting
#(Html.Kendo().TimePickerFor(m=>m)
.Value(#Model)
.Min("05:00")
.Max("00:00")
.Format("yyyy/MM/dd hh:mm tt")
)
Edit:
Is your max and min values correct? I don't see how that is logically correct.

How to display previous value on Min Miles text field

I want to display a previous value on Min Miles and that should not be editable. I want like
Default value of Min Miles is 0.
When I click on Add More Range then In the new form - Min Value should be Max Value of Previous Form.
I am using semantic form for. Please Help Me. How can I do this...
Regarding your second question, and assuming that the new form appears through javascript, without page reloading, you can grab the
field value with javascript and use it as the default value for the
new field. The "add new range"
Something Like
function getvalue(){
var inputTypes_max = [],inputTypes_min = [],inputTypes_amount = [];
$('input[id$="max_miles"]').each(function(){
inputTypes_max.push($(this).prop('value'));
});
$('input[id$="amount"]').each(function(){
inputTypes_amount.push($(this).prop('value'));
});
var max_value_of_last_partition = inputTypes_max[inputTypes_max.length - 2]
var amount_of_last_partition = inputTypes_amount[inputTypes_amount.length - 2]
if (max_value_of_last_partition == "" || amount_of_last_partition == "" ){
alert("Please Fill Above Details First");
}else{
$("#add_more_range_link").click();
$('input[id$="min_miles"]').each(function(){
inputTypes_min.push($(this).prop('id'));
});
var min_id_of_last_partition=inputTypes_min[inputTypes_min.length - 2]
$("#"+min_id_of_last_partition).attr("disabled", true);
$("#"+min_id_of_last_partition).val(parseInt(max_value_of_last_partition) + 1)
}
}
I have Used Jquery's End Selector In a loop to get all value of max and amount field as per your form and get the ids of your min_miles field and then setting that value of your min_miles as per max_miles
It worked For me hope It works For You.
Default value of a field can just be passed in the form builder as a second parameter:
...
f.input :min_miles, "My default value"
Of course I do not know your model structure but you get the idea.
Regarding your second question, and assuming that the new form appears through javascript, without page reloading, you can grab the field value with javascript and use it as the default value for the new field. The "add new range" click will be the triggerer for the value capture.
Something like (with jQuery):
var temp_value = '';
$('#add_more_range').click(function(){
temp_value = $('#my_form1 #min_miles').value();
$('#my_form2 #max_miles').value(temp_value);
});
Again I am just guessing the name of the selectors, but the overall approach should work.
If you are also adding dinamically to the page the "Add new range" buttons/links, then you should delegate the function in order to be inherited also for the so new added buttons:
$('body').on('click', '#add_more_range', function(){...});

Jquery Datepicker with MVC - Get date picked

I have the following in my MVC View:
#Html.TextBoxFor(model => model.FromDateCollected, new { style = "width:90px;" })
In query I have the following:
$("#FromDateCollected").datepicker();
To get the selected date, I tried the following:
var dt = $("#FromDateCollected").datepicker("getDate")
alert(dt);
but getting:
[object Object]
just get the value of text box
var dt = $("#FromDateCollected").val();
alert(dt);
If you want to get the selected date, when user select a date in the calendar, you can do that on the onSelect event
$(function() {
$('#FromDateCollected').datepicker({
onSelect: function(dateText, inst) {
alert(dateText);
}
});
});
Working sample http://jsfiddle.net/pDmjm/5/
EDIT : as per the comment,
$("#FromDateCollected").datepicker("getDate") will give you a Date object and $("#FromDateCollected").val(); will give you a string with current value in the textbox. write the result to a console and you will see the result.
Sample : http://jsfiddle.net/pDmjm/14/ (check firebug console after alerts)
You can get the date from the textbox value.
var dt = new Date(Date.Parse($('#FromDateCollected').val()));
alert(dt);

Very odd event behaviour for onChange on Telerik MVC DatePicker

To the question started, my code (I'll try to only include relevant portions to start), starting with my script:
function RaceDate_onChange() {
var pickedDate = $(this).data('tDatePicker').value();
var month = pickedDate.getMonth() + 1;
$.get("/RaceCard/Details?year=" + pickedDate.getFullYear() + "&month=" + month + "&day=" + pickedDate.getDate());
}
Then my markup:
#Html.Telerik().DatePickerFor(model => model.RaceDate).ClientEvents(events => events.OnChange("RaceDate_onChange"))
And finally a bit of the receiving action:
[HttpGet]
public ActionResult Details(int year, int month, int day)
{
var viewModel = new RaceCardModel {Metadata = DetailModelMetadata.Display, RaceDate = new DateTime(year, month, day)};
I'm trying to get the selection of a new date to trigger a GET, to refresh the page without submitting a form. This works fine, except for this problem:
In GET requests to the Details action, the day value is always one day behind the DatePicker. E.g. The first value is set from a view model property, when the view is rendered, say 3. I then click on 14 and hit my breakpoint in the action method. The day value is 3. When I click on 29 and hit the breakpoint, the day value is 14.
Besides asking what is wrong, I'll take a liberty and ask if there is a better way that is no more complicated. I am fairly novice and would rather deliver working code that needs revision than get bogged down in tangents and details.
Try using e.value instead as shown in the client-side events example. You are probably using an older version where the value() method returned the previous value during the OnChange event.
UPDATE:
"e.value" means the value field of the OnChange arguments:
function onChange(e) {
var date = e.value; // instead of datePicker.value()
}
As far as the 1 month difference you are getting, that's normal, and it is how the getMonth() method works in javascript on a Date instance:
The value returned by getMonth is an
integer between 0 and 11. 0
corresponds to January, 1 to February,
and so on.
So adding +1 is the correct way to cope with the situation, exactly as you did.
Just a little remark about your AJAX call: never hardcode urls. Always use url helpers when dealing with urls:
var year = pickedDate.getFullYear();
var month = pickedDate.getMonth() + 1;
var day = pickedDate.getDate();
var url = '#Url.Action("Details", "RaceCard")';
$.get(url, { year: year, month: month, day: day }, function(result) {
// process the results of the AJAX call
});

Resources