JQuery validation resetForm is not working - javascript

I have a very simple issue: There is a form with a clear form button. When I click on it, all fields reset. But I also have an extra validation rule: at least one additional field should be filled. After clearing, they all are empty, of course, but I don't want to see these validation messages. I want it to clear the entire form, hide all validation messages and so on. Here is my code:
$("a[data-clear]").click(function (event) {
var now = new Date();
$("#report_search section:gt(0) input").val("");
$("#includeDerived").prop("checked", true);
$("#includeApp").prop("checked", true);
$("#includeOrg").prop("checked", false);
$("input[name='FromDate']").datepicker().datepicker("setDate", now.dateAdd("year", -1));
$("input[name='ToDate']").datepicker().datepicker("setDate", now);
$("form").validate().resetForm();
event.preventDefault();
});
I have only one form on the page so multiple forms is not an issue.
Desired result: form is cleared, validation messages are not shown.
Actual result: form is cleared, validation messages persist.
Sample rule which is checking if fields are filled:
jQuery.validator.addMethod("isSufficientInfo",
function (value, element, params) {
var hasPersonInfo = $("input[name='LastName']").val() && $("input[name='FirstName']").val();
if (hasPersonInfo) {
return true;
}
var hasDocInfo = $("select[name='D']").val() && $("input[name='C']").val() && $("input[name='E']").val();
if (hasDocInfo) {
return true;
}
return $("input[name='A']").val() || $("input[name='B']").val();
}, "File some fields");
$("#IsEnoughInfo").rules("add", { isSufficientInfo: "" });

If you're still looking for the answer,
I suspect that $("form").validate() creates a new validator instance.
What you need is the previously created instance:
$("form").data("validator").resetForm()
Or store the validator in a variable:
var v = $("form").validate()
v.resetForm()

Reason for error
Your event for click event is getting propagated from button to window (inside-out). This is causing your form to trigger validation and thus you are getting the same error message, even after you call the resetForm. If you debug the validation library step by step and get to this.hideErrors then you will see that when this.hideErrors gets executed, the error messages are gone. Since the validation script hasn't finished yet, it continues with other statements, and at the end the event that got propagated is handled by the window from inside-out. The error messages are again shown as this event triggers the request on the form.
Solution
The solution is to move your call to event.preventDefault() to the top, like as shown below:
$("a[data-clear]").click(function (event) {
event.preventDefault(); // Move to top
var now = new Date();
$("#report_search section:gt(0) input").val("");
$("#includeDerived").prop("checked", true);
$("#includeApp").prop("checked", true);
$("#includeOrg").prop("checked", false);
$("input[name='FromDate']").datepicker().datepicker("setDate", now.dateAdd("year", -1));
$("input[name='ToDate']").datepicker().datepicker("setDate", now);
$("form").validate().resetForm(); // this should work now
});
Also see the updated jsfiddle sample
Give it a try and let me know if this works for you or not. I did the step-by-step debug and got to this conclusion.

Related

Tracking form submission

I'm developing tracking script which tracks some events (page view, link click, custom, ...) and sends them to API. Problem is I'm little bit stuck with form submission. So far I have following...
At first I add event listeners to every form on page:
const forms = document.getElementsByTagName("form");
for (let i = 0; i < forms.length; i++) {
forms[i].addEventListener("submit", trackFormSubmit);
}
}
And then trackFormSubmit function:
const trackFormSubmit = function(evt) {
if (evt.preventDefault) {
evt.preventDefault();
}
const form = evt.target || evt.srcElement;
const formElements = form.elements;
// parse form data payload here, not important to show
const event = {
...
};
Helper.sendEvent(event)
.then(() => {
form.submit();
})
.catch(error => {
console.log(error);
form.submit();
});
};
Helper.sendEvent function sends the event to the API. This solution works well for non-SPA websites, however it's not working great for SPA. I've tested it in React where I had a form using Redux Form library - the form submission was successfully tracked but I've received console error:
Form submission canceled because the form is not connected
The evt.preventDefault() doesn't work as expected in this case. Have someone an idea how this can be implemented?
Well I have to clarify the above statement: evt.preventDefault is called by Redux Form library so you have to handle onSubmit by your function (send data somewhere + redirect). I guess it's same in other Single-Page-Apps, there's no action where the user is sent ... default form behaviour is prevented initially.
First, make sure your ES6 arrow function trackFormSubmit is defined before your for loop that sets the event listener to every form. This could cause the code to work but without listening to the form submit.
Here is an example of setting up the event listener for every form in the document and handling their submit.
const trackFormSubmit = function(event) {
event.preventDefault();
const form = event.target || event.srcElement;
const formElements = form.elements;
alert(`Form ${event.target.name} was submited.`);
};
const forms = document.querySelectorAll("form");
forms.forEach(f=>{
f.addEventListener("submit",trackFormSubmit);
});
Here is a fiddle so you can view how this code works:
https://jsfiddle.net/k3llydev/fgL5owdj/
Also, I changed the way of setting the event listeners to a forEach way. Which is a lot more readable.
Hope this gives you at least an idea of how it would work.
Checking value of event.isDefaultPrevented solved the issue :-)

Refresh form after save and close

I have some custom script that adds the latest note value to a hidden text field, and the hidden text field is subsequently displayed in one of my views for the entity. When I click save and close after adding a new note, the view does not update with the newest note since the form was not refreshed. What can I do so that the form will be refreshed if the user clicks on save and close?
EDIT: #Arthur For some reason, I cannot add a comment to your post.
Anyhow, I tried as you have suggested. When I tried to click on "save" alone, the form refreshed and the value returned was true, so the flag was tripped. However, when I tried the same with "save and close" the form did not refresh, and consequently the flag was not tripped. This is leading me to assume that I must refresh the form in order for the view to update.
EDIT 2: Here is the code that retrieves the information.
function GetLatestNote() {
var req = new XMLHttpRequest();
req.open("GET", encodeURI(Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/AnnotationSet?" + "$select=NoteText&$filter=ObjectId/Id eq guid'" + Xrm.Page.data.entity.getId() + "'&$orderby=CreatedOn desc&$top=1"), true);
req.setRequestHeader('Accept', 'application/json');
req.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var note = JSON.parse(req.responseText).d;
var results = note.results;
var NoteText = results[0].NoteText;
var newnote = Xrm.Page.getAttribute("new_lastcomment").setValue(NoteText);
}
}
};
req.send();
}
new_lastcomment is the hidden field. What I am trying to do now is that if the user clicks on save and close, to stop the save event, reload the page, and use the script to close the form. Here is the code for that function:
function save(executionObj) {
var savestate = executionObj.getEventArgs.getsavemode();
if (savestate == 2) {
executionObj.getEventArgs().preventDefault();
window.location.reload(true);
Xrm.Page.data.entity.save("saveandclose");
}
}
What happens when I test this code however is that I get the following message when I attempt to save and close :
There was an error with this field's customized event.Field: crmForm, Event: onsave, Error: Object does not support property or method 'getsavemode'
However, once I click ok, the script closes and the view is updated as I want it! But now there is a problem because I do not want this error message popping up every time I hit save and close. To add more depth here, I run both of these function as an onsave event, and for the save function, I have "Pass execution context as first parameter" checked. I tried to run it without checking this box, and got an error that the value was undefined, but once again, after I clicked ok, the form would close and the view updated. Why is this error coming up now?
EDIT: #Arthur The form is now refreshing, but I am still getting the same error message that I was getting before.
Typically a "isdirty" flag gets triggered whenever there is a change to the form.
This flag lets CRM know that there have been modifications to the form in question, and to make sure to display the "There are unsaved changes" dialog box.
My guess is that this flag is not being tripped when you update the textbox.
if you put
console.log(Xrm.Page.data.entity.getIsDirty())
in your javascript and check out the resulting code, does it say true or false?
If it's false you'll need to set the dirty flag using
Xrm.Page.data.setFormDirty()
EDIT: I don't think this is the issue any more. refer to below.
After you set the value of the text box try executing this:
Xrm.Page.data.refresh(save);
That should save it, that way the save and close button doesn't have to.
After doing some research, I have found out what the issue was.
In my function GetLatestNote(), I was retrieving the data from the note field asynchronously. This may have resulted in the control returning to the user before the code was executed and the field was populated on the form. Therefore, this resulted in the information not being brought over when I clicked save and close.
Here is the code with the JSON code being executed synchronously, for those who may need it in the future. Works like a charm :)
function GetLatestNote() {
var req = new XMLHttpRequest();
req.open("GET", encodeURI( Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/AnnotationSet?" + "$select=NoteText&$filter=ObjectId/Id eq guid'"+Xrm.Page.data.entity.getId()+"'&$orderby=CreatedOn desc&$top=1"), false);
req.setRequestHeader('Accept', 'application/json');
req.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
req.send(null);
var note = JSON.parse(req.responseText).d;
var results = note.results;
var NoteText = results[0].NoteText;
var newnote = Xrm.Page.getAttribute("new_lastcomment").setValue(NoteText);
}
#Arthur thank you very much for trying to help me out. I truly appreciated it!

websockets do not work when assigned to global var

I use websockets along with javascript and html5
I have the following code.
<input type="text" onFocus=" so = new websocket('ws://localhost:1234');" onBlur="so.close();" onKeyUp="keyup();" >
<script type='text/javascript'>
var so; //this is global...
//wait a little (user stops typing)
function keyup(){
if (timeout) {clearTimeout(timeout);}
timeout = setTimeout(lookup, 250);
}
function lookup(){
//it's global, so use it right away
so.onopen = function(){
//send data to server to get responce...
So, websockets open/close if user clicks/or not a textfield. User types something on textfield. The value of textfield is sended to the server, a query is executed and if there are matching results, they render on the screen of the user.
If I click on the text field I see in the console "connected" and if I click anyware else I see "closed normally", as I should. That's ok.
But when I type letteres to the textfield, to send data to server, nothing is sended. I see nothing in the console. I see no errors.
What am I missing? It's like so.onopen never get executed.
Any advice?
Thanks in advance
The problem is that you recreate the socket but don't bind the onopen event handler.
On focus, you should call a function doing both : create the websocket and bind the onopen event handler :
<input id=someid type="text" onBlur="so.close();" >
<script type='text/javascript'>
var so, field = document.getElementById('someid');
field.onfocus = function(){
so = new websocket('ws://localhost:1234');
so.onopen = function(){
// do things
}
}

JQuery preventDefault not working with delegated event

I have a feed that uses AJAX to load in posts once the document is ready. Because the elements aren't ready at code execution, I have to use delegate to bind a lot of functions.
$(posts).delegate('.edit_comment_text','keyup',function(e){
return false;
if (e.keyCode == 13 && e.shiftKey == false) {
//Post the new comment and replace the textbox with a paragraph.
var message_area = $(this).parent('.comment_message');
var new_message = $(this).val();
var comment_id = $(this).closest('.group_comment').attr('data-comment');
var url = 'functions/edit_comment.php';
var array = {
'comment':comment_id,
'message':new_message
}
$.post(url, array, function(data){
console.log(data);
$(message_area).html("");
$(message_area).text(new_message);
});
}
})
This is the code I execute on the event. I've been trying to get the browser to stop dropping down a line when the user hits enter, but this action is performed before my code is even triggered. To prove it, I put the 'return false' at the very top of the block. With that example, none of my code is run when the user hits enter, but the textarea still drops a line.
Is it something to do with JQuery's delegate that causes my function to be called after the default events? They give examples of preventing default events in their documentation, so maybe it's a version bug or something?
Anyone have any ideas?
Thanks!

Detecting/handling changed data in ASP.NET MVC / jQuery / JS

We need to universally handle changed data on forms in ASP.NET MVC. Our application has ~100 forms, and the user should be prompted if they start editing a form and click on anything other than Save (i.e. something like "Your data has been changed. Click OK to return to the form, or Cancel to lose all changes.").
It looks like SO implements this (while asking a question) using JavaScript. In general, is this the best way? Also, any tips on how best to implement this?
The way I've done this is to use javascript to store the initial values of inputs when the page loads. Then I have a beforeunload handler that checks to see if any of the inputs have a different value than when the page was loaded. If any inputs are changed, it prompts the user to confirm that they want to leave the page, canceling the action if they cancel. In my submit logic, I set a flag that keeps the beforeunload check from happening so a submit doesn't get the prompt.
I suspect there is a jQuery plugin to do this, but I haven't implemented this since I started using jQuery. My earlier code used Prototype.
Edit: Couldn't find a jQuery plugin, but I could have just missed it. Here's a sample of how I might do it. Obviously, there's more that could be done. Note I wasn't able to get it to work with pure jQuery -- not sure exactly why, the popup would appear twice.
This should work with all input elements. You might want to change it to ignore/handle buttons, though. I only adjusted it to ignore a submit button (so it can post back without the popup). If other button types can cause a page unload, you may need to address that.
var CheckOnClose = function() {
this.initialize();
}
CheckOnClose.prototype = {
submitting: false,
initialize: function() {
var that = this;
window.onbeforeunload = function() { return that.checkLeavePage(); }
},
isChanged: function() {
var changed = false;
$('input:not(:submit)').each( function() {
var iv = $(this).data('initialValue');
if ($(this).val() != iv) {
changed = true;
return false;
}
});
return changed;
},
setSubmitting: function() {
this.submitting = true;
},
checkLeavePage: function() {
if (!this.submitting && this.isChanged()) {
return 'You have some unsaved changes.';
}
}
}
var checker = new CheckOnClose();
$(document).ready(function() {
$(':input:not(:submit)').each( function() {
$(this).data('initialValue',$(this).val() );
});
$(':submit').click( function() {
checker.setSubmitting();
});
});
JavaScript is your only shot for doing this. It doesn't even have to be a complicated bunch of code. All you have to do is have a global variable to flag if the form is in editing stages (var formEdited = false; would do), and then add this snippet to your page:
window.onbeforeunload = confirmExit;
function confirmExit()
{
if (formEdited)
{
return "You have attempted to leave this page. If you have made any changes to the fields without Submitting the form, your changes will be lost. Are you sure you want to exit this page?";
}
// no changes - return nothing
}

Categories

Resources