Validation.Javascript
I am creating some custom JavaScript validation functions. I have 130 input elements on screen so want to make this scalable.
I have this function where I call it within the JavaScript's function attribute: ValidateCheckNumber(this.id)
where I want to pass the ID of the element into the Javascript function but this is not working, any ideas how to successfully dynamially pass the ID of the element without having to manually add document.getElementById('inpText') etc as the parameter each time
-
Hi Jon
I'm not quite understanding what you have but would I be right in thinking you want to pass the element ID into the JS e.g. ValidateCheckNumber(element1, element2, element3, etc...) and have the script loop through each element passed in?
Regards
Neil
0 -
Hi Neil,
I only have certain inputs I want to do this for so I want to pass the element ID into the function without actually specifying what the ID as I this is in a DataTable, which is iterating through populating questions and answers so I wont exactly know the row number the input is on - this is why I want to do this dynamically (hope I am making sense)
If I add JS to on change event on the same Input element ValidateCheckNumber(this.id) works and passes the ID of the element but not with the JavaScript validation. I just get null for the ID that is passed,
0 -
If you're passing a value from a table for example from a button on a row you can build the elementId in the JavaScript.
For example, if you had a table with columns called Question and Answer and a column containing a button that calls your JS code you can use the row number of the table as a parameter in the JS by using @Function.Rownumber~ and appending this to the elementId in the script like this:
var myAnswer = document.getElementById('ANSWER_Row@Function.RowNumber~').value;Alternatively you could pass the row number into your procedure as an input parameter:
ValidateCheckNumber(this.id, rowNo) passing @Funtion.RowNumber~ as the second parameter.
I hope I've interpreted your requirement correctly, if not perhaps you could post part of your script so I can better understand.Regards
Neil
0 -
I can't even seem to get to pass the RowNumber either, please see attached my report.
<?xml version="1.0" encoding="utf-8"?><ReportID="Default"><Body><IncludeScriptID="jsValidateInput"IncludedScript="function ValidateCheckNumber(id,rowNum){alert('RowNumber:' + rowNum);var elementID = document.getElementById(id);alert('ElementID:' + elementID.value);throw("ERROR");}"/><ResponsiveRow><ResponsiveColumn><DataTableAjaxPaging="True"ID="dt-P4"KeepScrollPosition="True"SortArrows="True"Width="100"WidthScale="%"><DataLayerID="dlsQuestions"Type="Static"><StaticDataRowAnswer=""DataType="String"QuestionNumber="1"QuestionText="Name"/><StaticDataRowAnswer=""DataType="Number"QuestionNumber="2"QuestionText="Age"/><StaticDataRowAnswer=""DataType="String"QuestionNumber="3"QuestionText="Email"/></DataLayer><DataTableColumnClass="ThemeAlignCenter ThemeAlignTop"ColumnHeaderClass="ThemeAlignCenter, rdThemeDataTableHeader"ID="colQuestionNumber"Width="5"WidthScale="%"><LabelCaption="@Data.QuestionNumber~ @Function.RowNumber~"Class="ThemeBold"ID="lblQuestionNumber"/></DataTableColumn><DataTableColumnHeader="Question"ID="colQuestionText"><LabelCaption="@Data.QuestionText~"Format="HTML"ID="lblQuestionText"/></DataTableColumn><DataTableColumnClass="ThemeAlignCenter ThemeAlignTop"Header="Answer"ID="colAnswer"Width="15"WidthScale="%"><InputTextDefaultValue="@Data.Answer~"ID="txtAnswer"><ValidationClass="TextBoxValidate"ErrorMsg="There are errors on the Page. {error}"JavascriptFunction="ValidateCheckNumber(this.id, @Function.RowNumber~);"Type="Javascript"/></InputText></DataTableColumn></DataTable></ResponsiveColumn></ResponsiveRow><ResponsiveRow><ResponsiveColumn><LabelCaption="Save Section"Class="btn btn-success btn-lg"><ActionElementID="DivEmpty"ID="actRefresh"Type="RefreshElement"Validate="True"/></Label></ResponsiveColumn></ResponsiveRow><DivisionID="DivEmpty"/></Body><ideTestParams/></Report>0 -
Hi Jon
I'm running out of time today to look at this today - let me have a look this evening / tomorrow but I get what you're trying to do. When you hit Save you want each input field validated as not being empty, correct?
Cheers
Neil
0 -
I have scaled this down just to attach the code, I have div tags within the answer column depending on the DataType. I don't want to ensure a value is empty, I just want the ones that require a Numeric input to have this validation. Validation.Numeric is not working within the DataTable.
0 -
Hi Jon
I have a bit of time this afternoon to take a further look at this, can you attach then latest code you allude to in your last comment please.
Cheers
Neil0 -
<?xml version="1.0" encoding="utf-8"?><ReportID="Default"><Body><IncludeScriptID="jsValidateInput"IncludedScript="function ValidateCheckNumber(id,rowNum){alert('RowNumber:' + rowNum);var elementID = document.getElementById(id);alert('ElementID:' + elementID.value);throw("ERROR");}"/><ResponsiveRow><ResponsiveColumn><DataTableAjaxPaging="True"ID="dt-P4"KeepScrollPosition="True"SortArrows="True"Width="100"WidthScale="%"><DataLayerID="dlsQuestions"Type="Static"><StaticDataRowAnswer=""DataType="String"QuestionNumber="1"QuestionText="Name"/><StaticDataRowAnswer=""DataType="Number"QuestionNumber="2"QuestionText="Age"/><StaticDataRowAnswer=""DataType="String"QuestionNumber="3"QuestionText="Email"/></DataLayer><DataTableColumnClass="ThemeAlignCenter ThemeAlignTop"ColumnHeaderClass="ThemeAlignCenter, rdThemeDataTableHeader"ID="colQuestionNumber"Width="5"WidthScale="%"><LabelCaption="@Data.QuestionNumber~ @Function.RowNumber~"Class="ThemeBold"ID="lblQuestionNumber"/></DataTableColumn><DataTableColumnHeader="Question"ID="colQuestionText"><LabelCaption="@Data.QuestionText~"Format="HTML"ID="lblQuestionText"/></DataTableColumn><DataTableColumnClass="ThemeAlignCenter ThemeAlignTop"Header="Answer"ID="colAnswer"Width="15"WidthScale="%"><InputTextDefaultValue="@Data.Answer~"ID="txtAnswer"><ValidationClass="TextBoxValidate"ErrorMsg="There are errors on the Page. {error}"JavascriptFunction="ValidateCheckNumber(this.id, @Data.QuestionNumber~);"Type="Javascript"/></InputText></DataTableColumn></DataTable></ResponsiveColumn></ResponsiveRow><ResponsiveRow><ResponsiveColumn><LabelCaption="Save Section"Class="btn btn-success btn-lg"><ActionElementID="DivEmpty"ID="actRefresh"Type="RefreshElement"Validate="True"/></Label></ResponsiveColumn></ResponsiveRow><DivisionID="DivEmpty"/></Body><ideTestParams/></Report>0
-
If I can get the either the elementID or the RowNumber into the JavaScript function I will be able to manipulate this to fire the validation.
0 -
sorry this is the amended code with the toggle of data types:
<ResponsiveRow>
<ResponsiveColumn>
<DataTable
AjaxPaging="True"
ID="dt-P4"
KeepScrollPosition="True"
SortArrows="True"
Width="100"
WidthScale="%"
>
<DataLayer
ID="dlsQuestions"
Type="Static"
>
<StaticDataRow
Answer=""
DataType="String"
QuestionNumber="1"
QuestionText="Name"
/>
<StaticDataRow
Answer=""
DataType="Number"
QuestionNumber="2"
QuestionText="Age"
/>
<StaticDataRow
Answer=""
DataType="String"
QuestionNumber="3"
QuestionText="Email"
/>
</DataLayer>
<DataTableColumn
Class="ThemeAlignCenter ThemeAlignTop"
ColumnHeaderClass="ThemeAlignCenter, rdThemeDataTableHeader"
ID="colQuestionNumber"
Width="5"
WidthScale="%"
>
<Label
Caption="@Data.QuestionNumber~ @Function.RowNumber~"
Class="ThemeBold"
ID="lblQuestionNumber"
/>
</DataTableColumn>
<DataTableColumn
Header="Question"
ID="colQuestionText"
>
<Label
Caption="@Data.QuestionText~"
Format="HTML"
ID="lblQuestionText"
/>
</DataTableColumn>
<DataTableColumn
Class="ThemeAlignCenter ThemeAlignTop"
Header="Answer"
ID="colAnswer"
Width="15"
WidthScale="%"
>
<Division
Condition=""@Data.DataType~" = "String""
ID="String"
>
<InputText
DefaultValue="@Data.Answer~"
ID="txtAnswer"
/>
<Label
Caption="STRING"
/>
</Division>
<Division
Condition=""@Data.DataType~" = "Number""
ID="Number"
>
<InputText
DefaultValue="@Data.Answer~"
ID="txtAnswer"
>
<Validation
Class="TextBoxValidate"
ErrorMsg="There are errors on the Page. {error}"
JavascriptFunction="ValidateCheckNumber(this.id, @Data.QuestionNumber~);"
Type="Javascript"
/>
</InputText>
<Label
Caption="NUMBER"
/>
</Division>
</DataTableColumn>
</DataTable>
</ResponsiveColumn>
</ResponsiveRow>0 -
Hi Jon
I had some time to think about this and came up with this as a solution. It doesn't require you to pass the Row number from the table as it finds that itself by counting the rows in the displayed table.
See if this works for you (I hope it will) and let me know is you have any questions.
Regards
Neil
// This answer presumes you have three columns displayed in your table:Col1 - the question numberCol2 - the questionCol3 - the input field for the answerand a data value of isNumeric returned in the DataLayer which can be used to identify if the answer to the question should be numeric or not.
function validateAnswers() {// Get all of the table rows by using the tr selector within the tablevar rows = document.querySelectorAll("table tr");
// Loop through each row starting at the second displayed row// (this has an index of 1 as JavaScript starts counting at 0)// presuming the table has a header row.// If it doesn't then change var i = 1; to var i = 0; to start from the first row.for (var i = 1; i < rows.length; i++) {// Get the cells for the current row// This will get all of teh TD values for each rowvar cells = rows[i].querySelectorAll("td");
// Get the answer from the input field in the third columnvar answer = cells[2].querySelector("input").value;
// Check if the answer should be numeric// This might need some playing with as I don't know how you're holding the flag// to say this question requires a numeric answer.var isNumeric = '@DataTransfer.isNumeric_Row' + i + '~';
// If isNumeric is true and the answer goven is not then display an alertif (isNumeric && isNaN(answer)) {// Display an alert if the answer isn't numericalert("Question " + cells[0].innerText + " must have a numeric answer only. Please correct and try again.")// Exit the loopreturn false;}}// If all the answers are valid return truereturn true;}0 -
The easiest way to pass the id of an input into a function is to use jQuery.
validateCheckNumber($(this).attr('id'));
This will pass the id of the input calling the function
function validateCheckNumber(e) {
console.log(e);
console.log($('#'+e).val());
}This function will return the 'id' to the console as well as the current value.
The report would look like this where each input specifically calls the function.
<Report ID="LogiForum.jquer-validation">
<IncludeScriptFile IncludedScriptFile="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" />
<Body>
<DataTable ID="dt1">
<DataTableColumn>
<InputText ID="inptext01">
<EventHandler DhtmlEvent="onkeyup">
<Action Type="Javascript" Javascript="validateCheckNumber($(this).attr('id'));" />
</EventHandler>
</InputText>
</DataTableColumn>
<DataLayer Type="Static">
<StaticDataRow row="1" />
<StaticDataRow row="2" />
<StaticDataRow row="3" />
<StaticDataRow row="4" />
</DataLayer>
</DataTable>
<IncludeScript IncludedScript="function validateCheckNumber(e) {
 console.log(e);
 console.log($('#'+e).val());
}
" />
</Body>
</Report>You could also use a selector to bind the function to each input (ie. apply a non-existent css class to your input element or select all inputs within the table), then iterate through the objects and bind the keyup (or other event) that way.
function validateCheckNumber(e) {
console.log(e);
console.log($('#'+e).val());
}
$('.validate').each(function() {
$(this).keyup(function() {
validateCheckNumber($(this).attr('id'));
});
});
So your report then looks like this<Report ID="LogiForum.jquer-validation">
<IncludeScriptFile IncludedScriptFile="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" />
<Body>
<DataTable ID="dt1">
<DataTableColumn>
<InputText ID="inptext01" Class="validate">
</InputText>
</DataTableColumn>
<DataLayer Type="Static">
<StaticDataRow row="1" />
<StaticDataRow row="2" />
<StaticDataRow row="3" />
<StaticDataRow row="4" />
</DataLayer>
</DataTable>
<IncludeScript IncludedScript="function validateCheckNumber(e) {
 console.log(e);
 console.log($('#'+e).val());
}

$('.validate').each(function() {
 $(this).keyup(function() {
 validateCheckNumber($(this).attr('id'));
 });
});" />
</Body>
</Report>0 -
Actually with the final method you don't even need to iterate over each element. you can just apply it globally to that css class or other selector:
function validateCheckNumber(e) {
console.log(e);
console.log($('#'+e).val());
}
$('.validate').keyup(function() {
validateCheckNumber($(this).attr('id'));
});Or to select all inputs within a table
$('#dt1 tbody input').keyup(function() {
validateCheckNumber($(this).attr('id'));
});0 -
Hi JonI had a thought about how you might do this and was about to post this when our friends from VISUI posted their answer. I guess these are 2 separate approaches, theirs validates each input as it's entered, this one validates all of the answers once submitted. Two different ways of doing things although at this point my money would be on theirs, validate as the answer as input so you know you're always submitting valid answers. Anyway, here you go with a block submission validation:This answer presumes you have three columns displayed in your table and a data value of isNumeric returned in the DataLayer which can be used to identify if the answer to the question should be numeric or notfunction validateAnswers() {// Get all of the table rows by using the tr selector within the tablevar rows = document.querySelectorAll("table tr");// Loop through each row starting at the second displayed row// (this has an index of 1 as JavaScript starts counting at 0)// presuming the table has a header row.// If it doesn't then change var i = 1; to var i = 0; to start from the first row.for (var i = 1; i < rows.length; i++) {// Get the cells for the current row// This will get all of teh TD values for each rowvar cells = rows[i].querySelectorAll("td");// Get the answer from the input field in the third columnvar answer = cells[2].querySelector("input").value;// Check if the answer should be numeric// This might need some playing with as I don't know how you're holding the flag// to say this question requires a numeric answer.var isNumeric = '@DataTransfer.isNumeric_Row' + i + '~';// If isNumeric is true and the answer goven is not then display an alertif (isNumeric && isNaN(answer)) {// Display an alert if the answer isn't numericalert("Question " + cells[0].innerText + " must have a numeric answer only. Please correct and try again.")// Exit the loopreturn false;}}// If all the answers are valid return truereturn true;}0
-
And finally adding an "invalid" css class to inputs that contain nonnumeric values.
function validateCheckNumber(e) {
if ($.isNumeric($('#'+e).val())) {
$('#'+e).removeClass('invalid');
}
else {
$('#'+e).addClass('invalid');
}
console.log(e);
console.log($('#'+e).val());
}
$('#dt1 tbody input').keyup(function() {
validateCheckNumber($(this).attr('id'));
});<Report ID="LogiForum.jquer-validation">
<IncludeScriptFile IncludedScriptFile="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" />
<Body>
<IncludeHtml Html="<style>
 .invalid, .invalid:focus {
 border: 2px solid red !important;
 outline: none;
 }
</style>" />
<DataTable ID="dt1">
<DataTableColumn>
<InputText ID="inptext01" Class="validate" />
</DataTableColumn>
<DataLayer Type="Static">
<StaticDataRow row="1" />
<StaticDataRow row="2" />
<StaticDataRow row="3" />
<StaticDataRow row="4" />
</DataLayer>
</DataTable>
<IncludeScript IncludedScript="function validateCheckNumber(e) {
 if ($.isNumeric($('#'+e).val())) {
 $('#'+e).removeClass('invalid');
 }
 else {
 $('#'+e).addClass('invalid');
 }
 console.log(e);
 console.log($('#'+e).val());
}

$('#dt1 tbody input').keyup(function() {
 validateCheckNumber($(this).attr('id'));
});" />
</Body>
</Report>0 -
Thank you both comments, I now have a working solution so thank you. I have incorporated both, so I have the JavaScript validation for the validation when trying to save the datatable and then also the onkeyup event to add css on error/text change.
With the VISUI solution how do I prevent the process/refresh from running when clicked when there are errors?
0 -
I typically don't use the Action.Process element, but instead grab the respective javascript to submit a process or use ajax to submit the process asynchronously without leaving the current page.
In this example the javascript contains an outer if -else which uses a jquery selector to count the number of elements with the 'invalid' classif ($('.invalid').length > 0) {
//code
return false;
}The 'return false' breaks out of the javascript and returns false.
the 'else' statement then submits the process
else {
$('#AlertScheduler').hide();
RunProcess('<rdProcessAction><Action ID="actproc" Process="myProcessFile" TaskID="myTaskID" Type="Process" rdIdeIdx="8"><WaitPage Caption="Please Wait" rdIdeIdx="9" \x2f><\x2fAction><\x2frdProcessAction>','false','','','{"async":true,"syncServer":true,"isGlobal":false,"waitMessage":"Please Wait","waitClass":"","waitCaptionClass":""}');
}<Report ID="LogiForum.jquer-validation">
<IncludeScriptFile IncludedScriptFile="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" />
<Body>
<IncludeHtml Html="<style>
 .invalid, .invalid:focus {
 border: 2px solid red !important;
 outline: none;
 }
</style>" />
<HtmlTag HtmlTagName="div" ID="AlertScheduler">
<Label Caption="Highlighted inputs require numeric values." HtmlTag="h3" />
<HtmlAttributeParams style="display: none;" />
</HtmlTag>
<DataTable ID="dt1">
<DataTableColumn>
<InputText Class="validate" ID="inptext01" />
</DataTableColumn>
<DataLayer Type="Static">
<StaticDataRow row="1" />
<StaticDataRow row="2" />
<StaticDataRow row="3" />
<StaticDataRow row="4" />
</DataLayer>
</DataTable>
<IncludeScript IncludedScript="function validateCheckNumber(e) {
 if ($.isNumeric($('#'+e).val())) {
 $('#'+e).removeClass('invalid');
 }
 else {
 $('#'+e).addClass('invalid');
 }
 console.log(e);
 console.log($('#'+e).val());
}

$('#dt1 tbody input').keyup(function() {
 validateCheckNumber($(this).attr('id'));
});" />
<Button ID="btnSubmit" Caption="Submit">
<Action Type="Javascript" Javascript="if ($('.invalid').length > 0) {
 $('#AlertScheduler').show();
 $("input.invalid").first().focus();
 return false;
}
else {
 $('#AlertScheduler').hide();
 RunProcess('<rdProcessAction><Action ID="actproc" Process="myProcessFile" TaskID="myTaskID" Type="Process" rdIdeIdx="8"><WaitPage Caption="Please Wait" rdIdeIdx="9" \x2f><\x2fAction><\x2frdProcessAction>','false','','','{"async":true,"syncServer":true,"isGlobal":false,"waitMessage":"Please Wait","waitClass":"","waitCaptionClass":""}');
}" />
</Button>
</Body>
</Report>Another option is to simply have your main validation javascript disable the Submit button until all validation is met.
Please note that in this example I have added the condition test isNumeric OR the value is blank. Disregard this if all inputs must have a value.function validateCheckNumber(e) {
if ($.isNumeric($('#'+e).val()) || $('#'+e).val() == '') {
$('#'+e).removeClass('invalid');
$('#btnSubmit').prop("disabled",false);
}
else {
$('#'+e).addClass('invalid');
$('#btnSubmit').prop("disabled",true);
}
console.log(e);
console.log($('#'+e).val());
}
$('#dt1 tbody input').keyup(function() {
validateCheckNumber($(this).attr('id'));
});<Report ID="LogiForum.jquer-validation">
<IncludeScriptFile IncludedScriptFile="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" />
<Body>
<IncludeHtml Html="<style>
 .invalid, .invalid:focus {
 border: 2px solid red !important;
 outline: none;
 }
</style>" />
<HtmlTag HtmlTagName="div" ID="AlertScheduler">
<Label Caption="Highlighted inputs require numeric values." HtmlTag="h3" />
<HtmlAttributeParams style="display: none;" />
</HtmlTag>
<DataTable ID="dt1">
<DataTableColumn>
<InputText Class="validate" ID="inptext01" />
</DataTableColumn>
<DataLayer Type="Static">
<StaticDataRow row="1" />
<StaticDataRow row="2" />
<StaticDataRow row="3" />
<StaticDataRow row="4" />
</DataLayer>
</DataTable>
<IncludeScript IncludedScript="function validateCheckNumber(e) {
 if ($.isNumeric($('#'+e).val()) || $('#'+e).val() == '') {
 $('#'+e).removeClass('invalid');
 $('#btnSubmit').prop("disabled",false);
 }
 else {
 $('#'+e).addClass('invalid');
 $('#btnSubmit').prop("disabled",true);
 }
 console.log(e);
 console.log($('#'+e).val());
}

$('#dt1 tbody input').keyup(function() {
 validateCheckNumber($(this).attr('id'));
});" />
<Button ID="btnSubmit" Caption="Submit">
<Action Type="Javascript" Javascript="if ($('.invalid').length > 0) {
 $('#AlertScheduler').show();
 $("input.invalid").first().focus();
 return false;
}
else {
 $('#AlertScheduler').hide();
 RunProcess('<rdProcessAction><Action ID="actproc" Process="myProcessFile" TaskID="myTaskID" Type="Process" rdIdeIdx="8"><WaitPage Caption="Please Wait" rdIdeIdx="9" \x2f><\x2fAction><\x2frdProcessAction>','false','','','{"async":true,"syncServer":true,"isGlobal":false,"waitMessage":"Please Wait","waitClass":"","waitCaptionClass":""}');
}" />
</Button>
</Body>
</Report>0 -
thank you both so much for your help with this. I have integrated both methods.
0 -
Glad to help :-)
0
Please sign in to leave a comment.
Comments
19 comments