Yii2 validate an ActiveForm with javascript - javascript

I have a working Active Form, which can be submitted, and validated via Yii PHP. However, I would like to determine if the form is valid, when clicking a Next button.
I can pass error messages to the user via this:
$("#form").yiiActiveForm("validate", true);
But this function doesn't return anything; I don't know if there are indeed any errors or not. I tried this:
$error_count = document.getElementsByClassName("help-block").length
but this does not work; the errors are counted before the UI has updated. If I press the button again, a second time, then error_count is what I'd expect.
This doesn't seem to do anything:
$("#form").yiiActiveForm("validate");
I also tried this:
$('#form').on('afterValidate', function (event, messages, errorAttributes) {}
But this is only triggered after the fact so I'm not sure what to do.
Any advice would be appreciated.

If you need to react to button you simply need to combine both events:
let isNextClicked = false;
$('.next-btn').on('click', function(e) {
e.preventDefault();
isNextClicked = true;
$("#form").yiiActiveForm("validate", true);
});
$('#form').on('afterValidate', function(event, messages, errorAttributes) {
if (!isNextClicked) {
//validation wasn't triggered by clicking next
return;
}
// reset the state
isNextClicked = false;
if (errorAttributes.length > 0) {
//there are errors so we won't let user to continue
//we can also show some alert() here
return;
}
// ... code to show the next tab of form ...
});

Related

jquery dirrty form set it clean manually

I am using jquery dirrty plugin to check the state of a form and prevent it from reloading if there are some unsaved changes.
Link to jquery.dirrty github
Flow:
1) I have initialized jquery.dirty as follows
$(function(){
initializeDirtyForm();
})
/** dirty form initialization*/
function initializeDirtyForm(){
$("#uAForm").dirrty().on("dirty", function(){
$("#uAFormSubmit").removeAttr("disabled");
}).on("clean", function(){
$("#uAFormSubmit").attr("disabled", "disabled");
});
}
2) There is a table on the page and when it click on the td cells it make an ajax call.
function ajaxCallEdit()
{
var result = checkDirtyStatus();
if(result === false) {
return;
}
$.ajax({
....
....
....
....
success:function(){
initializeDirtyForm();
}
)}
}
/** check if the form is dirty */
function checkDirtyStatus(){
dirtyStatus = $("#uAForm").dirrty("isDirty");
if(dirtyStatus == true){
if (confirm("Changes you made may not be saved. Do you still want to reload?")) {
return true;
}else{
return false;
}
}
}
If the form is dirty, it works totally fine and show warning message.
ISSUE
Here is the main issue, if I force it to reload, (this means it won't actually reload page, instead it would make an ajax call) it is still setting the status of the form as dirty. I have tried by re-initializing the jquery form but still the form is flagged as dirty.
To make it extra sure and actually what is the the status of the form, I checked the status and tried to console log on ajaxSuccess.
....
success: function(){
initializeDirtyForm();
var result = checkDirtyStatus();
console.log(result);
}
...
However, consoling this result showing the value as undefined.
I could not find any documentation related to the setting it manually and reinitalizing is not working as intented.
So, if you are javascript wizard could you please check the jquery.dirrty.js file attached above and check if I could trigger following part from the js file or any other hacks that helps me to solve the problem.
setClean: function(){
this.isDirty = false;
this.history[0] = this.history[1];
this.history[1] = "clean";
}
If you need any further details please let me know.
try $("#uAForm").dirrty("setClean");
I just got into needing to do the same thing and that worked for me.
Cheers

Query OnSubmit Issue

I am encountering an error using the query below is the snippet of the code:
$('form[action="/home/service/"]').on("click", (function(event) {
if ($("#id1").val() == "" && $("#id2").val() == "") {
alert("Invalid entry");
event.preventDefault();
} else {
$('form[action="home/service/"]').submit();
}
});
the event.preventDefault(); works as it should however its the submit. I have tried using the .off("click" , function); but this didn't work and was the same issue.
Once the preventDefault() method is fired I am unable to resubmit the form once the issues have been resolved? I have seen a few people encounter this but their fixes didn't resolve my issues.
UPDATE
this is what I have now, however I am still receiving the issue, The issue is that it works on the initial on submit however as soon as I try to resubmit with the values it appears that the submit button is locked, has anyone encountered this before? Below is my updated code:
//function on
function checkForm(event)
{
debugger;
if ($("ID1, ID2" ).val() != "" ){
return;
}
else{
event.preventDefault();
$("#alerts-row").html("<div class='alert_box red'><p>Please Ensure that you have filled in at least one item number below!</p></div>");
$('form[action="Form"]').unbind("submit", checkForm);
}
}
$('form[action="form"]').on("submit", checkForm);
Thanks,
Gavey
try putting it before the if statement
$('form[action="/home/service/"]').on("click", (function(event) {
event.preventDefault();
if ($("#id1").val() == "" && $("#id2").val() == "") {
alert("Invalid entry");
} else {
$('form[action="home/service/"]').submit();
}
});
I think that the proper way would be to use the Submit event. If you do that, then on failure to validate you would preventDefault (as you have done), and on success you wouldn't prevent the default.
There's nothing stopping you having a click event on some element that simply calls form.submit(), but you should probably consider using a <Button> instead that can submit automatically.
To resolve the issue which I was having we used unobtrusive Validation, with the help of some samples we were able to create the or statement and allowed us to post the correct validation on the form.
$(document).ready(function(){
// Register new validation adapter
$.validator.unobtrusive.adapters.addBool('minimumselect');
// Add validator to controls
$input = $("#Input1");
$input.attr('data-val', 'true');
$input.attr('data-val-minimumselect', 'Please provide either this or Number 2');
$input2 = $("Input2");
$input2.attr('data-val', 'true');
$input2.attr('data-val-minimumselect', 'please provide this or Ref Number 1');
// Refresh form - needed to pick up new validator
refreshFormValidators();
});
Thanks,
Richard

CRM 2013: Force refresh a form after save

We have a requirement to refresh the form after saving (to ensure that some hide/show logic works as expected based on a field value).
Currently the form does not automatically refresh after saving the record.
I have gone through some articles and found this reference:
http://msdn.microsoft.com/en-us/library/dn481607%28v=crm.6%29.aspx
When I try to do either of the below, it results in an infinite loop and throws a 'Callstack exceeded Max limit' error.
OnSave(context)
{
//my logic
...
...
Xrm.Page.data.save.then(SuccessOnSave, ErrorOnSave);
}
function SuccessOnSave()
{
//force refresh
Xrm.Page.data.refresh();
}
function ErrorOnSave()
{
//do nothing
}
OnSave(context)
{
...
...
//force refresh
Xrm.Page.data.refresh(true).then(SuccessOnSave, ErrorOnSave);
}
function SuccessOnSave()
{
//do nothing
}
function ErrorOnSave()
{
//do nothing
}
Can someone please explain me how to use the refresh or save method to do a force refresh of the form ??
Rajesh
I use to achieve it with following code
Xrm.Page.data.save().then(
function () {
Xrm.Page.data.entity.attributes.forEach(function (attribute, index) {
attribute.setSubmitMode("never");
});
Xrm.Utility.openEntityForm(Xrm.Page.data.entity.getEntityName(), Xrm.Page.data.entity.getId());
},
function (errorCode, message) {
}
);
For me this is what solved the purpose (CRM 2015)
// Save the current record to prevent messages about unsaved changes
Xrm.Page.data.entity.save();
setTimeout(function () {
// Call the Open Entity Form method and pass through the current entity name and ID to force CRM to reload the record
Xrm.Utility.openEntityForm(Xrm.Page.data.entity.getEntityName(), Xrm.Page.data.entity.getId());
}, 3000);
If you want to do a hard refresh on the form data, you will likely want to do a location reload. What I've done in the past is put the refresh logic in a function that is called when the Form is loaded (after being saved). The tricky part about this is that the function can get called if the form is auto-saved in CRM 2013. You also want to take into account that you don't want to refresh the form on the first load, since this would result in an infinite reloading loop. Here's an example:
var formLoaded = false;
function formLoad() {
if (formLoaded) {
window.location = location.href;
}
formLoaded = true;
}
You have attached the OnSave() method to OnSave event. So, logically if you call save again within the same event, the calls goes recursively.
From MSDN
Xrm.Page.data.refresh(save).then(successCallback, errorCallback);
Parameter: save - A Boolean value to indicate if data should be saved
after it is refreshed.
So, you will have to pass 'false' to this method (You just need to refresh, no save is required)
As I couldn't find the complete code for this written in a 'generically' reusable way, here goes:
var triggeredSave = false;
//Attach the OnSave Form event to this OnSave function
//and select passing of context as the first parameter.
//Could instead be attached programmatically using the code:
//Xrm.Page.data.entity.addOnSave(OnSave);
function OnSave(context) {
var eventArgs = context.getEventArgs();
var preventedAutoSave = false;
//Preventing auto-save is optional; remove or comment this line if not required.
preventedAutoSave = PreventAutoSave(eventArgs);
//In order to setup an after save event function, explicitly
//invoke the save method with callback options.
//As this is already executing within the OnSave event, use Boolean,
//triggeredSave, to prevent an infinite save loop.
if (!preventedAutoSave && !triggeredSave) {
triggeredSave = true;
Xrm.Page.data.save().then(
function () {
//As the form does not automatically reload after a save,
//set the save controlling Boolean, triggeredSave, back to
//false to allow 'callback hookup' in any subsequent save.
triggeredSave = false;
OnSuccessfulSave();
},
function (errorCode, message) {
triggeredSave = false;
//OPTIONAL TODO: Response to failed save.
});
}
}
function PreventAutoSave(eventArgs) {
if (eventArgs.getSaveMode() == 70 || eventArgs.getSaveMode() == 2) {
eventArgs.preventDefault();
return true;
}
return false;
}
//Function OnSuccessfulSave is invoked AFTER a save has been committed.
function OnSuccessfulSave() {
//It seems CRM doesn't always clear the IsFormDirty state
//by the point callback is executed, so do it explicitly.
Xrm.Page.data.setFormDirty(false);
//TODO: WHATEVER POST SAVE PROCESSING YOU REQUIRE
//e.g. reload the form as per pre CRM 2013 behaviour.
ReloadForm(false);
//One scenario this post save event is useful for is retriggering
//Business Rules utilising a field which is not submitted during save.
//For example, if you implement a Current User field populated on Form
//Load, this can be used for user comparison Business Rules but you
//may not wish to persist this field and hence you may set its submit
//mode to 'never'.
//CRM's internal retriggering of Business Rules post save doesn't
//consider changes in fields not submitted so rules utilising them may
//not be automatically re-evaluated or may be re-evaluated incorrectly.
}
function ReloadForm(preventSavePrompt) {
if (preventSavePrompt) {
Xrm.Page.data.entity.attributes.forEach(function (attribute, index) {
attribute.setSubmitMode("never");
});
Xrm.Page.data.setFormDirty(false);
}
Xrm.Utility.openEntityForm(Xrm.Page.data.entity.getEntityName(),
Xrm.Page.data.entity.getId());
//Another way of trying Form reload is:
//window.location.reload(true);
}
Use Mscrm.Utilities.reloadPage();
I found this post helpful in demonstrating the difference between Xrm.Page.data.refresh() and Xrm.Utility.openEntityForm(entityName, id).
TL;DR - if you want the screen to repaint, consider using Xrm.Utility.openEntityForm(entityName, id).
You can achieve by placing Modified On field on the form. And set visible by default property to false.
Use below JS to refresh the form
function refreshCRMFORM()
{
setTimeout(function () {
// Call the Open Entity Form method and pass through the current entity name and ID to force CRM to reload the record
Xrm.Utility.openEntityForm(Xrm.Page.data.entity.getEntityName(), Xrm.Page.data.entity.getId());
}, 1000);
}
Create On Change event on Modified on field and provide above function name.

Preventing form from being submitted with manual validation

I implemented some custom validation logic with JQuery and Unobtrusive validation with help of the following post:
Manually set unobtrusive validation error on a textbox
To save you time reading through that post here is the simple javascript that forces a validation message to be displayed if something fails:
On my textbox .blur():
var errorArray = {};
errorArray["Slug"] = 'Some error message for the Slug text box';
$('#SomeFormId').validate().showErrors(errorArray);
Works great.
My problem is while the failed validation message is displayed, when submit is clicked the form submits just fine.
How can I implement custom validation with code above and prevent the form from being submitted when the message is displayed ? I tired doing something like $('#SomeFormId').valid = false; but it didn't work.
Thank you.
Using $('#SomeFormId') will not work because when you do:
$('#SomeFormId').valid = false;
and then when you access it in your form submit handler again using (what I assume):
var form = $('#SomeFormId'); // or $(this)
if (form.valid) {
//
}
You're essentially creating two different objects, even though they're referring to the same DOM element. So setting valid = true in one will not update it in the second.
The code you gave is very barebones though, so I'm assuming that your validation is separate from your submit handler (since it's in blur anyway), so what you can do is utilize something like .data() or a flag (just make sure that it's in context).
// on blur
$('#SomeFormId').data('isvalid', false); // invalid
// on submit
var isvalid = $('#SomeFormId').data('isvalid');
if (!isvalid) {
// invalid form
ev.preventDefault();
}
EDIT
The jQuery Event object
When you bind a function as an event handler in jQuery, one of the things that jQuery does silently for you is it "creates" a normalized Event object for you. This will contain information about the event you can use in the handler, and also allows you to control the behavior of the event in some ways.
// setting a submit event on my form
// | whatever you put here
// V is the event object.
$('#SomeFormId').on('submit', function (ev) {
// preventing the default action
// : in a form, this prevents the submit
ev.preventDefault();
});
To check if the form is valid, you can use something like this:
var form = $("#SomeFormId");
form.submit(function(event) {
if(form.valid() == false) event.preventDefault();
}
Edited to add a bit more to it, this will take care of your submission/prevention, now you just add in your validation calls.

Problem handling onchange on a textbox

I have a GridView with textboxes in its cells. I need to call a javascript function when the user changes the contents of a TextBox, and then hits Enter or leaves the TextBox. The latter is achieved by doing onchange="MyJavascriptFunc", but the javascript function is not called when Enter is pressed. If I call the javascript function from EnterKeyPressHandler function, MyJavascriptFunc is called twice, which I would prefer to avoid.
Could you please help me with this?
Thanks.
Check if the func is called when the user presses enter.
var called = false;
if(called != true)
{
called = true;
// and do sth
}
called = false;

Categories

Resources