Add Magento custom validation to a form field using adding a new rule using $.validator.addMethod
using $.validator.addMethod
we can create number of custom rules and via class name we can access those custom rules.
so back to the question, need of question is without using calendar validate input fields like days/month/year.
so assuming where you adding these days/month/year fields that wrap with form tag, In this form magento default validation added data-mage-init='{"validation":{}}
' or via js.
create all days/month/year fields under form or add below html code
<div class="field date field-dob" data-mage-init='{
"Vendor_Module/js/custom-validation-dob":{
"day" : "[name=\"day\"]",
"month" : "[name=\"month\"]",
"year" : "[name=\"year\"]",
"classPrefix": "custom-dob",
"maxYearDiff": 150
}
}'>
<label class="label" for="dob">
<span><?= __('Your Birthday'); ?></span>
</label>
<div class="input-box customer-dob">
<div class="dob-day">
<label for="day"><?= __('DD'); ?></label>
<input type="text" id="day" name="day" title="<?= __('Day'); ?>" class="input-text required-entry" autocomplete="off">
</div>
<div class="dob-month">
<label for="month"><?= __('MM'); ?></label>
<input type="text" id="month" name="month" title="<?= __('Month'); ?>" class="input-text required-entry" autocomplete="off">
</div>
<div class="dob-year">
<label for="year"><?= __('YYYY'); ?></label>
<input type="text" id="year" name="year" title="<?= __('Year'); ?>" class="input-text required-entry" autocomplete="off">
</div>
</div>
</div>
Alter or update the HTML as your need expect name attribute of input field. if need to modify name attribute too then do same change in
data-mage-init='{
"Vendor_Module/js/custom-validation-dob":{
"day" : "[name=\"day\"]",
"month" : "[name=\"month\"]",
"year" : "[name=\"year\"]",
"classPrefix": "custom-dob",
"maxYearDiff": 150
}
}'
as well with respective fields.
Now create a js file custom-validation-dob.js
under your module something like that Vendor/Module/view/frontend/web/js/custom-validation-dob.js
the paste below js code
define([
'jquery',
'jquery/ui',
'jquery/validate',
'mage/translate'
], function($){
'use strict';
var enterValueIsNumeric = function (input) {
return (input - 0) == input && input.length > 0;
}
return function(config, element) {
var dayObj = $(element).find(config.day || '[name="day"]');
var monthObj = $(element).find(config.month || '[name="month"]');
var yearObj = $(element).find(config.year || '[name="year"]');
var classPrefix = config.classPrefix || 'custom';
var maxYearDiff = config.maxYearDiff || 100; // max limit for year gap
$.validator.addMethod(
classPrefix+"-day-validate",
function(value, element) {
var result = false,
validatorObj = this,
isElementOptional = this.optional(element),
days = 31; // just to assume no value set on year and month fields
var year = yearObj.val();
var month = monthObj.val();
var currentDateObj = new Date();
var maxMonth = currentDateObj.getMonth() + 1;
var maxYear = currentDateObj.getFullYear();
var currentDay = currentDateObj.getDate();
var message = $.mage.__("Please enter valid day value in this field.");
if(enterValueIsNumeric(value)) {
if(year && month){ //Checks days in the specific month with year
days = new Date(year, month, 0).getDate();
}
result = days >= value;
if(result && year == maxYear && month == maxMonth) { // for current year & month
result = currentDay >= value;
message = $.mage.__("Entered day value will be less then or equal to %1 that is current day because Entered Year and Month value respectively equal to current year and month value.").replace('%1', currentDay);
}
}
if (!result) {
validatorObj.customDayMessage = message;
}
return isElementOptional || result;
}, function () {
return this.customDayMessage;
}
);
$.validator.addMethod(
classPrefix+"-month-validate",
function(value, element) {
var result = false,
validatorObj = this,
isElementOptional = this.optional(element);
var year = yearObj.val();
var currentDateObj = new Date();
var maxMonth = currentDateObj.getMonth() + 1;
var maxYear = currentDateObj.getFullYear();
var message = $.mage.__("Please enter valid month value in this field.");
if(enterValueIsNumeric(value)) {
result = ( value >= 1 && value <= 12);
if(result && year == maxYear) { // For current year
result = ( value <= maxMonth);
message = $.mage.__("Entered month value will be less then or equal to %1 that is current month because Entered Year value is equal to current year value.").replace('%1', maxMonth);
}
}
if (!result) {
validatorObj.customMonthMessage = message;
}
return isElementOptional || result;
}, function () {
return this.customMonthMessage;
}
);
$.validator.addMethod(
classPrefix+"-year-validate",
function(value, element) {
var result = false,
validatorObj = this,
isElementOptional = this.optional(element),
prevDateObj = new Date(),
currentDateObj = new Date();
prevDateObj.setFullYear(prevDateObj.getFullYear() - maxYearDiff);
currentDateObj.setFullYear(currentDateObj.getFullYear());
var minYear = prevDateObj.getFullYear();
var maxYear = currentDateObj.getFullYear(); // because DOB value will be less then the current year
var message = $.mage.__("Please enter valid year value in this field and year value will be in between %1 and %2").replace('%1', minYear).replace('%2', maxYear);
if(enterValueIsNumeric(value)) {
result = (value.length == 4 && value >= minYear && value <= maxYear ); // always be year value in 4 digit
}
if (!result) {
validatorObj.customYearMessage = message;
}
return isElementOptional || result;
}, function () {
return this.customYearMessage;
}
);
// binding class with respective element to apply validation rule properly.
dayObj.addClass(classPrefix+"-day-validate");
monthObj.addClass(classPrefix+"-month-validate");
yearObj.addClass(classPrefix+"-year-validate");
}
});
using these 2 code set, first html markup and second magento custom js will help to validate calendar like function. and these rules are linked also so proper validation come in picture hope this will match all you expectation mention in question.
Add on -
For future reuse of this custom js with valid name instead of full path, alias the js path with a good name.
So create a requirejs config file requirejs-config.js
in your module Vendor/Module/view/frontend/requirejs-config.js
if not exist and add below code
var config = {
"map": {
"*": {
"customValidationForDMY": "Vendor_Module/js/custom-validation-dob" // D = Day,M = Month, Y = Year
}
}
};
then in above mention html code update
data-mage-init='{
"Vendor_Module/js/custom-validation-dob":{
"day" : "[name=\"day\"]",
"month" : "[name=\"month\"]",
"year" : "[name=\"year\"]",
"classPrefix": "custom-dob",
"maxYearDiff": 150
}
}'
with
data-mage-init='{
"customValidationForDMY":{
"day" : "[name=\"day\"]",
"month" : "[name=\"month\"]",
"year" : "[name=\"year\"]",
"classPrefix": "custom-dob",
"maxYearDiff": 150
}
}'
In given sample I used Vendor_Module, In your case this will be change with your respective module name.
Any help will be appreciated.