On CRM 2013 on-premise, I'm working to write a javascript that checks for email validation. The field can contain a list of email address, however if the email is not valid, it will not let the users save the form.
I got the splitting and validating to work fine now.
However I continue to have problems to prevent users from saving the form.
On the OnChange, I check the box on the "Pass execution context as first parameter"
I user the preventDefault() function as suggested by an MSDN article however I keep getting error message "Unable to get property 'preventDefault' of undefined or null reference".
Any idea is appreciated. Here's my code:
function EmailTest(EmailField)
{
var Email = /^([a-zA-Z0-9_.-])+#([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/;
if(Email.test(EmailField))
{
return true;
}
else
{
return false;
}
}
function CheckEmailString(context)
{
try
{
var EmailString = context.getEventSource().getValue();
if (EmailString != null)
{
var separator = [" ", ",", ";", "|"];
var EmailArray = EmailString.split(separator);
var Flag = true;
for(var i = 0;i < EmailArray.length;i++)
{
if(!EmailTest(EmailArray[i]))
{
Flag = false;
break;
}
}
if(Flag != true)
{
alert("The list of emails entered contain invalid email format. Please re-enter");
context.getEventArgs().preventDefault();
}
}
}
catch(err)
{
alert(err.message);
}
}
you get the error
Unable to get property 'preventDefault' of undefined or null reference
because the getEventArgs is available only when you are inside the save event, it's not available inside onchange event.
You should add the validation check also inside the save event if you want to stop the save.
Could I suggest you might try updating it to the full version of the method ie
Xrm.Page.context.getEventArgs.preventDefault().
I understand when working in CRM you have to reference use the full names in order for your function to see the prevent default method.
Hopefully that helps but if not good luck in seeking a solution
Related
This is just a best practice question that I have run into and can't find the answer for. Any input is welcome! (Backed up responses with data/research would be amazing)
Example Save Button
When my save button is pressed, I want to do some validation, name (must be first and last), age (must be from 0 - 125), email (valid email address) and if these are all true, I want to "save" the user (to a db or wherever doesn't matter)
Right now my functions are set up
// Global error handler for example
var errors = {};
// Save Button Function
saveButton = function(dataModel) {
var valid = true;
valid = validateName(valid, dataModel.name);
valid = validateAge(valid, dataModel.age, 'extraParam');
valid = validateEmail(valid, dataModel.email, 'secondParam', 'thirdParam');
valid = (dataModel.red) ? validateRedUser(valid, dataModel) : valid;
if (valid) {
// Save user to database
}
else {
// alert to user an error has occured
// user errors object to respond with the errors
}
}
I feel like passing around the valid state to each sub validation function is not the best approach to a problem like this. It works, but can it be improved?
Edit: A sub-validation function would look something like:
validateName = function(valid, dataModel.name) {
if (!dataModel.name) {
valid = false;
// access global error handler to save error
errors.name = 'error in the name';
}
return valid;
}
Taking your sample function added the valid state condition check.
validateName = function(valid, dataModel.name) {
if (!dataModel.name && valid) {
valid = false;
// access global error handler to save error
errors.name = 'error in the name';
}
return valid;
}
I have a Client Script that performs a GlideRecord query to check if a record already exists with the same name.
If a matching record is found, we need to STOP the form from being submitted.
We have this working fine on the CMS portal.
However, the new Service Portal does not support synchronous GlideRecord query.
So I can't use gr.query() I need to use a callback such as gr.query(callback).
The issue is that since the callback is asynchronous, it does not actually stop the form from being submitted!
g_form.submitted = false; DOES NOT work. That's because the script proceeds along to submit the form before the callback has a chance to retrieve the value.
How can we stop the submission of a form based on the value returned by an asynchronous callback? We can't use GlideAjax for the same reason, getXMLWait() is no longer supported.
Here is the client script that I am trying to get working in the new Service Portal.
function onSubmit() {
var group_name = g_form.getValue('u_group_name');
g_form.hideAllFieldMsgs('error');
/*Check if group already exists*/
var rec = new GlideRecord('u_auth_group');
rec.addQuery('u_group_name', u_group_name);
rec.query(getAccountResponse);
}
function getAccountResponse(rec) {
while (rec.next()) {
g_form.showFieldMsg('u_group_name', " Group Name exists already, please select another group name",'error');
g_form.submitted = false; //DOES NOT STOP THE FORM FROM BEING SUBMITTED
return false;
}
}
Here is the existing script that works in the CMS portal.
function onSubmit() {
var group_name = g_form.getValue('u_group_name');
g_form.hideAllFieldMsgs('error');
/*Check if group already exists*/
var rec = new GlideRecord('u_auth_group');
rec.addQuery('u_group_name', u_group_name);
rec.query(getAccountResponse);
while (rec.next()) {
g_form.showFieldMsg('u_group_name', " Group Name exists already, please select another group name",'error');
g_form.submitted = false; //Stops the form from being submitted if a result is returned
return false;
}
}
We're on Helsinki Patch 5 so we're going through similar growing pains. We've had luck using the following structure. There are still Glide System resources available Server Side, including Glide Record.
You might try wrapping your Submit action inside of a custom event handler.
Try:
Client side:
c.createGroup = function(groupName){
return c.server.get({
grpname : groupName
}.then(function(response){
if (response.data.result == true){
//don't submit
}
else{
//submit
}
}
Server Side
data.result = false
data.grpname = input.grpname
function checkGroupExists(data.grpname){
/*Check if group already exists*/
var rec = new GlideRecord('u_auth_group');
rec.addQuery('u_group_name', data.grpname);
rec.limit(1); //you only need to find one match
rec.query()
while (rec.next()){
data.result = true
}
}
Then you can bind this event handler to some action in the UI.
I was able to solve this by using an asyc callback with the glide record query.
function onSubmit() {
//If ServicePortal
if (!window) {
if (g_scratchpad.isFormValid) {
return true;
}
g_form.hideAllFieldMsgs("error");
var actionName = g_form.getActionName();
//Group Name contain letters numbers and dashes only
var group_name = g_form.getValue("u_group_name");
//Group name regular expression
var regGrpName = /^([A-Za-z0-9\-]+)$/;
//Check name against regular expression
validGroupName = regGrpName.test(group_name);
//Check if google group already exists
var gg = new GlideRecord("u_system_group");
gg.addQuery("u_group_name", group_name);
//Callback function to control stop submit asynchronously
gg.query(function() {
while (gg.next()) {
g_form.showFieldMsg("u_group_name","Group Name " + gg.u_group_name + " already exists! Please enter a different group name.", "error", true);
return false;
}
g_scratchpad.isFormValid = true;
g_form.submit(actionName);
});
return false;
}
}
I'm performing form validation using JQuery/AJAX. When an entry is missing or malformed, I want to send a message via alert() and return the user to the form with all fields as they were so the user can edit them and try submitting the form again. I also don't want the user to get a series of alert() boxes for each field that is malformed, but rather the first field that is discovered to be malformed should issue an alert() box; upon clicking the alert() box, the user may then return to editing the form. If there are 6 malformed fields, I don't want a series of 6 consecutive alert() boxes, but rather just the first one discovered by the routine to be errant and a return to the form (eventually the user will get them all right).
I have utilized a method that works, although it's not elegant and rather tedious to edit and error-prone...it's like a series of Russian dolls, where the first error prevents the successive routines from being run. When there are 5 fields or fields that require multiple kinds of integrity checking, the number of nested IF-ELSE statements increases exponentially, and for forms where I'm passing data via GET to a PHP file, like this:
$.get('admin_email_length_check.php', { new_email: $('#new_email').val(), max_email_length: max_email_length }, function(data) {
if (data != 0) {
alert(data);
} else {
...it has to be closed out with:
}
});
...not just a simple:
}
But here's a short routine for a 2 field validation. I set allow_submit to FALSE and prevent submission until all integrity checks are passed, at which point allow_submit becomes TRUE and I dynamically re-submit the form; this means that the integrity check (and its e.preventDefault();) will be bypassed entirely and the form will then be processed. Again, it works, but the kind of IF-ELSE structures I need to construct for forms with many fields that require many types of form validation requires extremely LONG structures with carefully edited closing braces (or braces + parentheses + ;, etc.) Is there a shorter or more elegant way to do this?:
var allow_submit = false;
$('#change_password_form').on('submit', function(e) {
if (!allow_submit) {
e.preventDefault();
// First ensure that at least one of the fields has a value:
if (($('#new_password').val() == '') && ($('#retype_password').val() == '')) {
alert("Nothing specified in either of the 'Change Password' fields.\n\nAdd data and re-submit.\n");
} else {
// Ensure both fields are filled:
if (($('#new_password').val() == '') || ($('#retype_password').val() == '')) {
alert("When changing your password, both the 'New Password' and the 'Retype Password' fields must be filled.\n\nPlease supply new, matching passwords in both fields and re-submit.\n");
} else {
// Do the two fields match?
if ($('#new_password').val() != $('#retype_password').val()) {
alert("New Password fields do not match.\n\nPlease edit password fields and re-submit.\n");
} else {
allow_submit = true;
$('#change_password_form').submit();
}
}
}
}
});
I have two suggestions:
Use early return statements to de-nest your code a bit.
Whenever you have too much conditional logic, try to use a data structure instead. See this quote by Linus Torvalds.
Here is my attempt:
$('#change_password_form').on('submit', function(e) {
var data = collect_data();
if (!data_is_valid(data)) {
e.preventDefault();
} else {
// Submit.
}
});
function collect_data() {
return {
passwords {
new_: $('#new_password').val(),
retyped: $('#retype_password').val()
},
...
};
}
function data_is_valid(data) {
if (!password_is_valid(data.passwords)) {
return false;
}
...
return true;
}
function password_is_valid(passwords) {
for (var i = 0; i < password_validators.length; i++) {
var validator = password_validators[i];
if (!validator.fails(passwords)) {
alert(validator.message);
return false;
}
}
return true;
}
var password_validators = [
{
fails: function(passwords) {
return passwords.new_ === '' && passwords.retyped === '';
},
message: 'No password provided'
},
{
fails: function(passwords) {
return passwords.new_ !== .passwordsretyped;
},
message: 'Passwords do not match'
},
...
];
I tried to make Ajax form and tried to make email verification there. I found this solution
http://jsfiddle.net/EFfCa/
but can't turn it on in my script:
<script>
$('#joinForm').ajaxForm(function() {
var testEmail = /^[A-Z0-9._%+-]+#([A-Z0-9-]+\.)+[A-Z]{2,4}$/i;
var name = $("input[name=name]")
var email = $("input[name=email]")
if(name.val()==''||email.val()=='') {
$(".notify").show();
$(".notify p").text('empty');
} else if(testEmail.test(email.value)) {
$(".notify").show();
$(".notify p").text('email is wrong');
} else {
$(".notify").show();
$(".notify p").text('good');
}
});
</script>
The form always passed verification even email is wrong. Verification for empty fields works good...
The following line else if(testEmail.test(email.value)) will return true if the email is correct.
In your logic that's where the email is wrong could that be the problem?
This is because your passing email.value. jquery objects don't have a parameter called value, so this will resolve as undefined.
.test() returns true if it is passed undefined, so your test will always pass.
use .val() instead.
$('input').blur(function() {
var testEmail =/^([\w-]+(?:\.[\w-]+)*)#((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
if (testEmail.test(this.value)) alert('passed');
else alert('failed');
});
Okay, so I am attempting to validate on the server side. I am using Windows Azure Mobile Services for my Android application. The validation is done in Javascript / Node.js.
I have been doing my best to find solutions to my issue and stumbled upon [this link] (http://blogs.msdn.com/b/carlosfigueira/archive/2012/09/21/playing-with-the-query-object-in-read-operations-on-azure-mobile-services.aspx)!
I intend to use regexp to validate the object before persisting it to the DB.
I would understand how to do this 'pre-query' but as I need access to use regex, I must perform 'post-query' filtering.
Below is the code in which I have (so far) but I want to know how can I validate many fields and deliver appropriate error messages for each invalid fields. If all are valid, then persist to the DB.
Thanks in advance!
function insert(item, user, request) {
var userTable = tables.getTable('User');
userTable.where({email: item.email}).read({
success: emailExists
});
function emailExists(existingItems)
{
if (existingItems.length > 0)
{
request.respond(statusCodes.CONFLICT,
"An account is already registered with this email!.");
}
else
{
// Insert the item as normal.
request.execute({
success: function (results)
{
var regexEmail = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
var filtered = results.filter(function(item)
{
return regexEmail.test(item.email);
});
request.respond(statusCodes.OK, filtered);
}
});
}
}
}
If I understand what you want to do correctly, you first need to validate the input's e-mail against the items in the database (to maintain unicity), then validate other fields in the input before inserting that. If that's the case, then after the query validation (to prevent duplicate e-mails) you can validate the item fields individually, as shown in this document. The code below shows an example of such validation.
function insert(item, user, request) {
var userTable = tables.getTable('User');
userTable.where({email: item.email}).read({
success: emailExists
});
function emailExists(existingItems)
{
if (existingItems.length > 0)
{
request.respond(statusCodes.CONFLICT,
"An account is already registered with this email!.");
}
else
{
// Validate fields *before* inserting
var regexEmail = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (!regexEmail.test(item.email)) {
request.respond(statusCodes.BAD_REQUEST, { error: 'E-mail is invalid' });
return;
}
if (!item.name || item.name.length < 10) {
request.respond(statusCodes.BAD_REQUEST, { error: 'Item must have a name of at least 10 characters' });
return;
}
// If all validation succeeded, then insert the item
request.execute();
}
}
}