Fix_Code commited

This commit is contained in:
sanjeev.p 2026-03-18 10:39:57 +05:30
parent f3fbbddbe7
commit 28dfdc1494
4 changed files with 245 additions and 126 deletions

View File

@ -1876,10 +1876,10 @@ class ClientController extends AdminController
]
],
'designation.*' => [
'rules' => 'required|alpha_space',
'rules' => 'required|regex_match[/^[A-Za-z0-9\-_\/ ]+$/]',
'errors' => [
'required' => 'Designation is required',
'alpha_space' => 'Designation may contain only letters and spaces'
'regex_match' => 'Designation may only contain letters, numbers, /, -, _ and spaces'
]
],
'email.*' => [
@ -2283,10 +2283,10 @@ class ClientController extends AdminController
]
],
'designation.*' => [
'rules' => 'required|alpha_space',
'rules' => 'required|regex_match[/^[A-Za-z0-9\-_\/ ]+$/]',
'errors' => [
'required' => 'Designation is required',
'alpha_space' => 'Designation may contain only letters and spaces'
'regex_match' => 'Designation may only contain letters, numbers, /, -, _ and spaces'
]
],
'email.*' => [
@ -2467,10 +2467,10 @@ class ClientController extends AdminController
]
],
'designation.*' => [
'rules' => 'required|alpha_space',
'rules' => 'required|regex_match[/^[A-Za-z0-9\-_\/ ]+$/]',
'errors' => [
'required' => 'Designation is required',
'alpha_space' => 'Designation may contain only letters and spaces'
'regex_match' => 'Designation may only contain letters, numbers, /, -, _ and spaces'
]
],
'email.*' => [

View File

@ -115,12 +115,13 @@ class UserController extends AdminController
// ======================
'emp_code' => [
'label' => 'Employee Code',
'rules' => 'required|min_length[3]|max_length[15]|regex_match[/^[a-zA-Z0-9_\-\/]+$/]',
'rules' => 'required|min_length[3]|max_length[15]|regex_match[/^[a-zA-Z0-9_\-\/]+$/]|is_unique[user_profiles.emp_code]',
'errors' => [
'required' => 'Employee Code is required',
'min_length' => 'Employee Code must be at least 3 characters',
'max_length' => 'Employee Code cannot exceed 15 characters',
'regex_match' => 'Employee Code can only contain letters, numbers, underscores, hyphens, and forward slashes (/).'
'regex_match' => 'Employee Code can only contain letters, numbers, underscores, hyphens, and forward slashes (/).',
'is_unique' => 'This Employee Code already exists.'
]
],
@ -141,10 +142,11 @@ class UserController extends AdminController
// Email
// ======================
'email' => [
'rules' => 'required|regex_match[/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/]',
'rules' => 'required|regex_match[/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/]|is_unique[user_profiles.email]',
'errors' => [
'required' => 'Email address is required.',
'regex_match' => 'Please enter a valid email format (e.g., name@domain.com).'
'regex_match' => 'Please enter a valid email format (e.g., name@domain.com).',
'is_unique' => 'This Email address already exists.'
]
],
@ -152,10 +154,11 @@ class UserController extends AdminController
// Mobile
// ======================
'mobile' => [
'rules' => 'required|regex_match[/^[6-9][0-9]{9}$/]',
'rules' => 'required|regex_match[/^[6-9][0-9]{9}$/]|is_unique[user_profiles.mobile]',
'errors' => [
'required' => 'Mobile number is required',
'regex_match' => 'Enter a valid 10-digit mobile number starting with 6, 7, 8, or 9',
'is_unique' => 'This Mobile number already exists.'
]
],
@ -268,7 +271,10 @@ class UserController extends AdminController
if (!$this->request->getPost()) {
return redirect()->to(base_url('/user/list'));
} else {
// echo ":/ in 163";
$data = $this->request->getPost();
$userData = sanitizeInputArrayAdvanced($data);
$id = $userData['PrimaryKey'];
$rules = [
// ======================
@ -297,13 +303,13 @@ class UserController extends AdminController
// Employee Code
// ======================
'emp_code' => [
'label' => 'Employee Code',
'rules' => 'required|min_length[3]|max_length[15]|regex_match[/^[a-zA-Z0-9_\-\/]+$/]',
'rules' => "required|min_length[3]|max_length[15]|regex_match[/^[a-zA-Z0-9_\-\/]+$/]|is_unique[user_profiles.emp_code,id,{$id}]",
'errors' => [
'required' => 'Employee Code is required',
'min_length' => 'Employee Code must be at least 3 characters',
'max_length' => 'Employee Code cannot exceed 15 characters',
'regex_match' => 'Employee Code can only contain letters, numbers, underscores, hyphens, and forward slashes (/).'
'regex_match' => 'Employee Code can only contain letters, numbers, underscores, hyphens, and forward slashes (/).',
'is_unique' => 'This Employee Code already exists.'
]
],
@ -324,10 +330,11 @@ class UserController extends AdminController
// Email
// ======================
'email' => [
'rules' => 'required|regex_match[/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/]',
'rules' => "required|regex_match[/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/]|is_unique[user_profiles.email,id,{$id}]",
'errors' => [
'required' => 'Email address is required.',
'regex_match' => 'Please enter a valid email format (e.g., name@domain.com).'
'regex_match' => 'Please enter a valid email format (e.g., name@domain.com).',
'is_unique' => 'This Email address already exists.'
]
],
@ -335,10 +342,11 @@ class UserController extends AdminController
// Mobile
// ======================
'mobile' => [
'rules' => 'required|regex_match[/^[6-9][0-9]{9}$/]',
'rules' => "required|regex_match[/^[6-9][0-9]{9}$/]|is_unique[user_profiles.mobile,id,{$id}]",
'errors' => [
'required' => 'Mobile number is required',
'regex_match' => 'Enter a valid 10-digit mobile number starting with 6, 7, 8, or 9',
'is_unique' => 'This Mobile number already exists.'
]
],

View File

@ -388,7 +388,7 @@ table.dataTable tbody td {
<div class="btn-group dropdown" style="position: relative !important;left:0px !important;top:0px !important;">
<a href="javascript: void(0);" class="dropdown-toggle arrow-none btn btn-light btn-sm" data-toggle="dropdown" aria-expanded="false"><i class="mdi mdi-dots-horizontal"></i></a>
<div class="dropdown-menu dropdown-menu-right" style="cursor: pointer;">
<a data-toggle="modal" data-target="#con-close-modal" class="dropdown-item btnEdit" data-id="<?php echo $row->id; ?>"><i data-id="<?php echo $row->id; ?>" class="mdi mdi-pencil mr-2 text-muted font-18 vertical-middle btnEdit"></i>Edit</a>
<a class="dropdown-item btnEdit" data-id="<?php echo $row->id; ?>"><i data-id="<?php echo $row->id; ?>" class="mdi mdi-pencil mr-2 text-muted font-18 vertical-middle btnEdit"></i>Edit</a>
<a class="dropdown-item btnDelete" data-id="<?php echo $row->id; ?>"><i data-id="<?php echo $row->id; ?>" class="mdi mdi-delete mr-2 text-muted font-18 vertical-middle btnDelete"></i>Delete</a>
</div>
</div>
@ -493,7 +493,7 @@ table.dataTable tbody td {
<select class="form-control" id="nhance_branch_id" name="nhance_branch_id" required>
<option value="">Select Nhance Branch</option>
<?php foreach($NHanceBranchData as $value) { ?>
<option value="<?= $value['id'] ?>"><?= $value['branch_name'] ?></option>
<option value="<?= $value['id'] ?>" <?= old('nhance_branch_id') == $value['id'] ? 'selected' : '' ?>><?= $value['branch_name'] ?></option>
<?php } ?>
</select>
</div>
@ -502,7 +502,7 @@ table.dataTable tbody td {
<select class="form-control" id="rm_id" name="rm_id" required>
<option value="">Select Reporting Manager</option>
<?php foreach($user_data as $value) { ?>
<option value="<?= $value['id'] ?>"><?= $value['first_name'] ?></option>
<option value="<?= $value['id'] ?>" <?= old('rm_id') == $value['id'] ? 'selected' : '' ?>><?= $value['first_name'] ?></option>
<?php } ?>
</select>
</div>
@ -511,11 +511,11 @@ table.dataTable tbody td {
<div class="form-row">
<div class="form-group col-md-6">
<label for="emp_code">Employee Code<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="emp_code" placeholder="Enter Code" name="emp_code" onchange="validateInput(this, 'user_profiles', 'emp_code', 'btnSubmit')" required>
<input type="text" class="form-control" id="emp_code" placeholder="Enter Code" name="emp_code" onchange="validateInput(this, 'user_profiles', 'emp_code', 'btnSubmit')" required value="<?= old('emp_code') ?>">
</div>
<div class="form-group col-md-6">
<label for="first_name">Name<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="first_name" placeholder="Enter Name" name="first_name" required>
<input type="text" class="form-control" id="first_name" placeholder="Enter Name" name="first_name" required value="<?= old('first_name') ?>">
</div>
</div>
@ -523,19 +523,19 @@ table.dataTable tbody td {
<div class="form-row">
<div class="form-group col-md-6">
<label for="email">Email<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="email" placeholder="Enter Email" name="email" data-parsley-trigger="change" data-parsley-type="email" onchange="validateInput(this, 'user_profiles', 'email', 'btnSubmit')" required>
<input type="text" class="form-control" id="email" placeholder="Enter Email" name="email" data-parsley-trigger="change" data-parsley-type="email" onchange="validateInput(this, 'user_profiles', 'email', 'btnSubmit')" required value="<?= old('email') ?>">
</div>
<div class="form-group col-md-6">
<label for="mobile">Mobile Number<span class="text-danger">*</span></label>
<input type="text" class="form-control" id="mobile" placeholder="Enter Mobile Number ( starting with 6, 7, 8, or 9 only. )" name="mobile" onkeypress = "return onlyNumbers(event)" maxlength="10" minlength="10" pattern="^[6-9]\d{9}$" data-parsley-type-message="Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9." data-parsley-required-message="Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9." required>
<input type="text" class="form-control" id="mobile" placeholder="Enter Mobile Number ( starting with 6, 7, 8, or 9 only. )" name="mobile" onkeypress="return onlyNumbers(event)" onchange="validateInput(this, 'user_profiles', 'mobile', 'btnSubmit')" maxlength="10" minlength="10" pattern="^[6-9]\d{9}$" data-parsley-type-message="Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9." data-parsley-required-message="Please enter a valid 10-digit mobile number starting with 6, 7, 8, or 9." required value="<?= old('mobile') ?>">
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="emp_code">User Role<span class="text-danger">*</span>
<label for="role">User Role<span class="text-danger">*</span>
<span class="tooltip-trigger mdi mdi-information-outline" id="roleAccessMatrixTrigger"></span>
</label>
<select class="form-control" id="role" name="role" required>
@ -557,7 +557,7 @@ table.dataTable tbody td {
</div>
<div class="form-group col-md-6">
<label for="profile">User Team<span class="text-danger">*</span>
<label for="team">User Team<span class="text-danger">*</span>
<span class="tooltip-trigger mdi mdi-information-outline" id="accessMatrixTrigger"></span>
</label>
<select hidden class="form-control" id="team" name="team[]" multiple required>
@ -891,6 +891,21 @@ table.dataTable tbody td {
<?php foreach (session()->getFlashdata('errors') as $error): ?>
toastr.error("<?= addslashes($error) ?>", "Validation Error");
<?php endforeach; ?>
var errorModal = new bootstrap.Modal(document.getElementById('con-close-modal'));
errorModal.show();
<?php if(old('PrimaryKey')): ?>
$('#UserForm').attr('action', '<?= base_url('/user/edit') ?>');
$('#UserId').val('<?= old('PrimaryKey') ?>');
$('#btnSubmit').html('Update');
$('.modal-title').text('Update User');
$('#email').attr('data-original', '<?= old('email') ?>');
$('#mobile').attr('data-original', '<?= old('mobile') ?>');
$('#emp_code').attr('data-original', '<?= old('emp_code') ?>');
<?php else: ?>
$('#UserForm').attr('action', '<?= base_url('/user/create') ?>');
<?php endif; ?>
});
</script>
<?php endif; ?>
@ -1086,10 +1101,11 @@ table.dataTable tbody td {
$('.close').click(function(){
$('#UserId').val('');
$('#first_name').val('');
$('#email').val('');
$('#mobile').val('');
$('#emp_code').val('');
$('#email').val('').removeAttr('data-original');
$('#mobile').val('').removeAttr('data-original');
$('#emp_code').val('').removeAttr('data-original');
$('#role').val('')
$('#btnSubmit').prop('disabled', false);
})
// $('body').on('click', '#btnUsers', function () {
@ -1103,83 +1119,74 @@ table.dataTable tbody td {
// $(this).addClass('active');
// loadPartner();
// });
$('body').on('click', '.btnEdit', function () {
$('body').on('click', '.btnEdit', function () {
var user_id = $(this).attr('data-id');
$.ajax({
url: '<?php echo base_url('user/getuser/');?>'+user_id,
type: "GET",
dataType: 'json',
success: function (res) {
console.log(":():",res);
console.log(":():",res.data.nhance_branch_id);
$('#updateModal').modal('show');
$('#role').val('')
$('#UserForm').attr('action', '<?php echo base_url('user/edit');?>');
$('#UserId').val(res.data.id);
$('#first_name').val(res.data.first_name);
$('#last_name').val(res.data.last_name);
$('#email').val(res.data.email);
$('#mobile').val(res.data.mobile);
$('#emp_code').val(res.data.emp_code);
$('#role option[value="' + res.data.role + '"]').prop('selected', true);
$('#rm_id').val(res.data.rm_id).select2(); // ✅ correct trigger
if (res.data.nhance_branch_id !== null &&
res.data.nhance_branch_id !== "" &&
res.data.nhance_branch_id !== 0) {
$('#nhance_branch_id')
.val(res.data.nhance_branch_id)
.trigger('change.select2');
} else {
$('#nhance_branch_id')
.val(null) // ✅ MUST be null
.trigger('change.select2'); // ✅ correct trigger
}
$('#UserForm').parsley().reset();
$('#btnSubmit').html('Update');
var user_id = $(this).attr('data-id');
$.each(res.userTeamData, function(index, item) {
$('#team option[value="' + item.team_id + '"]').prop('selected', true);
$('#team').multiselect('refresh');
});
$.ajax({
url: '<?php echo base_url('user/getuser/');?>' + user_id,
type: "GET",
dataType: 'json',
success: function (res) {
// Set form action to edit
$('#UserForm').attr('action', '<?php echo base_url('user/edit');?>');
$('#UserId').val(res.data.id);
$('#first_name').val(res.data.first_name);
$('#email').val(res.data.email).attr('data-original', res.data.email);
$('#mobile').val(res.data.mobile).attr('data-original', res.data.mobile);
$('#emp_code').val(res.data.emp_code).attr('data-original', res.data.emp_code);
$('#role').val(res.data.role).trigger('change');
$('#rm_id').val(res.data.rm_id).trigger('change.select2');
},
error: function (xhr, status, error) {
console.error("Error Details:");
console.error("Status Code:", xhr.status);
console.error("Status Text:", xhr.statusText);
console.error("Response Text:", xhr.responseText);
console.error("Ready State:", xhr.readyState);
console.error("Response Headers:", xhr.getAllResponseHeaders());
console.error("Error Thrown:", error);
console.error("Status:", status);
if (xhr.status === 400) {
let response = JSON.parse(xhr.responseText);
let errorMessages = "";
let seenMessages = []; // Array to store unique messages
if (response.errors) {
$.each(response.errors, function (field, message) {
if (!seenMessages.includes(message)) {
errorMessages += `• ${message}<br>`;
seenMessages.push(message); // Mark this message as "seen"
}
});
toastr.error(errorMessages, 'Validation Error', { "allowHtml": true });
} else {
toastr.warning(response.message || 'Validation failed', 'Warning');
}
} else if (xhr.status === 403) {
let response = JSON.parse(xhr.responseText);
toastr.error(response.message, 'Security Policy');
} else if (xhr.status === 500) {
toastr.error('Something went wrong . Please try again later.', 'Server Error');
} else {
toastr.error('An unexpected error occurred. Please try again later.', 'Error');
}
if (res.data.nhance_branch_id) {
$('#nhance_branch_id').val(res.data.nhance_branch_id).trigger('change.select2');
} else {
$('#nhance_branch_id').val(null).trigger('change.select2');
}
});
// Reset team first, then set selected
$('#team').multiselect('deselectAll', false);
$.each(res.userTeamData, function(index, item) {
$('#team option[value="' + item.team_id + '"]').prop('selected', true);
});
$('#team').multiselect('refresh');
$('.modal-title').text('Update User');
$('#btnSubmit').html('Update');
// ✅ Open modal AFTER data is loaded
var myModal = new bootstrap.Modal(document.getElementById('con-close-modal'));
myModal.show();
},
error: function (xhr) {
if (xhr.status === 400) {
let response = JSON.parse(xhr.responseText);
let errorMessages = "";
let seenMessages = [];
if (response.errors) {
$.each(response.errors, function (field, message) {
if (!seenMessages.includes(message)) {
errorMessages += `• ${message}<br>`;
seenMessages.push(message);
}
});
toastr.error(errorMessages, 'Validation Error', { "allowHtml": true });
} else {
toastr.warning(response.message || 'Validation failed', 'Warning');
}
} else if (xhr.status === 403) {
let response = JSON.parse(xhr.responseText);
toastr.error(response.message, 'Security Policy');
} else if (xhr.status === 500) {
toastr.error('Something went wrong. Please try again later.', 'Server Error');
} else {
toastr.error('An unexpected error occurred.', 'Error');
}
}
});
});
$('body').on('click', '.btnDelete', function () {
@ -1296,13 +1303,95 @@ table.dataTable tbody td {
return false;
}
var form = document.getElementById("UserForm");
var form = document.getElementById("UserForm");
// Add submit event listener to the form
form.addEventListener("submit", function(event) {
// Disable the submit button to avoid multiple submissions
// document.getElementById("btnSubmit").disabled = true;
form.addEventListener("submit", function(event) {
event.preventDefault();
var btn = document.getElementById('btnSubmit');
var currentUserId = $('#UserId').val(); // capture BEFORE ajax
btn.disabled = true;
btn.innerText = "Saving...";
var actionUrl = $('#UserForm').attr('action');
var formData = new FormData(form);
$.ajax({
url: actionUrl,
type: "POST",
data: formData,
processData: false,
contentType: false,
success: function(responseText) {
// Parse returned HTML and look for toastr.error calls (validation errors injected by CI flashdata)
var tempDiv = document.createElement('div');
tempDiv.innerHTML = responseText;
var errorMessages = [];
tempDiv.querySelectorAll('script').forEach(function(script) {
var content = script.innerText || script.textContent;
var matches = content.match(/toastr\.error\("([^"]+)"/g);
if (matches) {
matches.forEach(function(m) {
var msg = m.replace(/toastr\.error\("/, '').replace(/"$/, '');
if (!errorMessages.includes(msg)) {
errorMessages.push(msg);
}
});
}
});
if (errorMessages.length > 0) {
// ❌ VALIDATION FAILED — keep modal OPEN, show all errors in one toast
var errorList = '<ul style="margin:4px 0 0 0; padding-left:18px; text-align:left;">';
errorMessages.forEach(function(msg) {
errorList += '<li>' + msg + '</li>';
});
errorList += '</ul>';
toastr.error(errorList, 'Validation Errors', {
"allowHtml": true,
"timeOut": 8000,
"closeButton": true
});
// ✅ Modal stays OPEN — do NOT hide it
} else {
// ✅ SUCCESS
toastr.success('User saved successfully!', 'Success');
// ✅ Bootstrap 4 way to close modal
$('#con-close-modal').modal('hide');
// Full reset
form.reset();
$('#UserForm').parsley().reset();
$('#UserId').val('');
$('#nhance_branch_id').val(null).trigger('change.select2');
$('#rm_id').val(null).trigger('change.select2');
$('#role').val('').trigger('change');
$('#team').multiselect('deselectAll', false);
$('#team').multiselect('refresh');
$('#email').removeAttr('data-original');
$('#mobile').removeAttr('data-original');
$('#emp_code').removeAttr('data-original');
$('.modal-title').text('Add User');
$('#btnSubmit').text('Submit').prop('disabled', false);
loadUser();
}
},
error: function(xhr) {
toastr.error('An unexpected error occurred. Please try again.', 'Error');
},
complete: function() {
btn.disabled = false;
btn.innerText = currentUserId ? 'Update' : 'Submit';
}
});
});
function submitPartner(event) {
event.preventDefault();
@ -1516,7 +1605,7 @@ table.dataTable tbody td {
<i class="mdi mdi-dots-horizontal"></i>
</a>
<div class="dropdown-menu dropdown-menu-right">
<a data-toggle="modal" data-target="#con-close-modal" class="dropdown-item btnEdit" data-id="${row.id}">
<a class="dropdown-item btnEdit" data-id="${row.id}" style="cursor:pointer;">
<i data-id="${row.id}" class="mdi mdi-pencil mr-2 text-muted font-18 vertical-middle btnEdit"></i>Edit
</a>
<a class="dropdown-item btnDelete" data-id="${row.id}">
@ -1962,22 +2051,30 @@ table.dataTable tbody td {
<script>
$(document).on('click', '#btnAdd', function() {
// Reset the form
$('#UserForm')[0].reset();
$('#UserId').val('');
// Specifically reset Select2 if you are using it
$('#nhance_branch_id').val('').trigger('change');
$('#rm_id').val('').trigger('change');
// Update Modal Title and Action
$('.modal-title').text('Add User');
$('#btnSubmit').text('Submit');
$('#UserForm').attr('action', '<?php echo base_url('/user/create');?>');
var myModal = new bootstrap.Modal(document.getElementById('con-close-modal'));
myModal.show();
});
$('#UserForm')[0].reset(); // 1⃣ reset form values first
$('#UserForm').parsley().reset(); // 2⃣ then reset parsley validation
$('#btnSubmit').prop('disabled', false); // 3⃣ re-enable submit button
$('#nhance_branch_id').val(null).trigger('change.select2');
$('#rm_id').val(null).trigger('change.select2');
$('#team').multiselect('deselectAll', false);
$('#team').multiselect('refresh');
// remove data-original attributes
$('#email').removeAttr('data-original');
$('#mobile').removeAttr('data-original');
$('#emp_code').removeAttr('data-original');
$('.modal-title').text('Add User');
$('#btnSubmit').text('Submit');
$('#UserForm').attr('action', '<?php echo base_url('/user/create');?>');
var myModal = new bootstrap.Modal(document.getElementById('con-close-modal'));
myModal.show();
});
// $(document).on('click', '#btnAdd', function(){
// $('#first_name').val('');
@ -2009,6 +2106,13 @@ table.dataTable tbody td {
function validateInput(input, table, field, submitButId){
let value = $(input).val();
let originalValue = $(input).attr('data-original');
if (originalValue && value.trim().toLowerCase() === originalValue.trim().toLowerCase()) {
$('#' + submitButId).prop('disabled', false);
return;
}
let label = $(input).closest('.form-group').find('label').text().replace('*', '').trim();
let message = "Value is duplicate!";
@ -2018,7 +2122,8 @@ table.dataTable tbody td {
checkDuplicateTableFieldValue(table, field, value, function(isDuplicate) {
if (isDuplicate) {
toastr.warning(message, 'Warning');
toastr.warning(message, 'Warning');
$(input).focus();
// $(input).val('')
$('#' + submitButId).prop('disabled', true);
} else{

View File

@ -254,7 +254,10 @@ input:checked + .slider-branch-contact:before {
<div class="form-group col-md-6">
<label for="designation">Designation<span class="text-danger">*</span></label>
<input value="" type="text" class="form-control" placeholder="Enter Designation Name"
name="designation[]" id="designation" required>
name="designation[]" id="designation" required
pattern="[A-Za-z0-9\-_/ ]+"
oninput="this.value = this.value.replace(/[^A-Za-z0-9\-_\/ ]/g, '')"
title="Designation may only contain letters, numbers, /, -, _ and spaces only allowed">
</div>
</div>
<div class="form-row">
@ -736,7 +739,10 @@ function appendContactHtml(contact = false, reset = false) {
</div>
<div class="form-group col-md-6">
<label for="${uniqueId}_designation">Designation<span class="text-danger">*</span></label>
<input value="${contact !== undefined && contact !== false ? contact.designation : ''}" type="text" class="form-control" placeholder="Enter Designation Name" name="designation[]" id="${uniqueId}_designation" required>
<input value="${contact !== undefined && contact !== false ? contact.designation : ''}" type="text" class="form-control" placeholder="Enter Designation Name" name="designation[]" id="${uniqueId}_designation" required
pattern="[A-Za-z0-9\-_/ ]+"
oninput="this.value = this.value.replace(/[^A-Za-z0-9\-_\/ ]/g, '')"
title="Designation may only contain letters, numbers, /, -, _ and spaces only allowed">
</div>
</div>
<div class="form-row">