I have been creating some form elements like name, age, address and also I have to add blocks for the achievements, skills, projects and education, but I have an issue while dealing with jQuery repeaters, it's just a made a node list to fill it with multi-values information like achievement or skills but the DevTools shows up this error:
Uncaught TypeError: Cannot read properties of undefined (reading 'value')
and here is an exp:
this is a simple form elements and a multi-values element
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>EXP</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
<section id="about-user" class="">
<div class="container">
<div class="about-data">
<form action="" class="cv-form" id="cv-form">
<!-- if i deal with a static data like personal information i font have a problem-->
<div class="cv-form-blk">
<div class="cv-form-row-title">
<h3>about user</h3>
</div>
<div class="cv-form-row cv-form-row-about">
<div class="form-elem">
<label for="" class="form-label">firstname</label>
<input type="text" name="firstname" class="form-control firstname" id="" onkeyup="generateCV()">
</div>
</div>
<div class="form-elem">
<label for="" class="form-label">firstname</label>
<input type="text" name="firstname" class="form-control firstname" id="" onkeyup="generateCV()">
</div>
<div class="form-elem">
<label for="" class="form-label">address</label>
<input type="text" name="address" class="form-control address" id="" onkeyup="generateCV()">
</div>
<div class="form-elem">
<label for="" class="form-label">age</label>
<input type="text" name="age" class="form-control age" id="" onkeyup="generateCV()">
</div>
</div>
<div class="cv-form-blk">
<div class="cv-form-row-title">
<h3>Achievements</h3>
</div>
<div class="row-separator repeater">
<div class="repeater" data-repeater-list="group-a">
<div data-repeater-item>
<div class="cv-form-row cv-form-row-acheivement">
<div class="form-elem">
<label for="" class="form-label">Title</label>
<input type="text" name="acheiv-title" class="form-control acheiv-title" id="" onkeyup="generateCV()">
<span class="form-text"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</section>
<!-- jquery cdn -->
<script src="https://code.jquery.com/jquery-3.7.1.js" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
<!-- jquery repeater -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.repeater/1.2.1/jquery.repeater.js" integrity="sha512-bZAXvpVfp1+9AUHQzekEZaXclsgSlAeEnMJ6LfFAvjqYUVZfcuVXeQoN5LhD7Uw0Jy4NCY9q3kbdEXbwhZUmUQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- custom js -->
<script type="text/javascript" src="exp.js"></script>
</body>
</html>
and this the generator function
const strRegex = /^[a-aA-Z\s]*$/; // containing only letters
const mainForm = document.getElementById('cv-form');
// user input elemnts
let firstnameElem = mainForm.firstname,
addressElem = mainForm.address,
ageElem = mainForm.age;
const validType = {
TEXT: 'text',
EMAIL: 'email',
}
// first value is for attributes and seconde one passes the nodelists
const addValues = (attrs, ...nodeLists) => {
let elemsAttrCount = nodeLists.length;
let elemsDataCount = nodeLists[0].length;
let tempDataArr = [];
//first loop deals with the no of repeaters value
for(let i = 0; i<elemsDataCount; i++ ){
let dataObj = {}; // creating an empty obj to fill the data
//second loop fetches the data for each repeaters value or attributes
for (let j = 0; j < elemsAttrCount; i++ ) {
/* setting the key name for the obj and fill it with data ,
which is the expectable thing*/
dataObj[`${attrs[j]}`] = nodeLists[j][i].value; // but in this part exact the node list can't find a value
}
tempDataArr.push(dataObj);
}
return tempDataArr;
}
const getUserInputs = () => {
// achievements
let achievementsTitleElem = document.querySelectorAll('.acheiv-title');
console.log(addValues(['achiev-title'],achievementsTitleElem));
// event listeners for validation
firstnameElem.addEventListener('keyup', (e) => validateFormData(e.target, validType.TEXT, 'First name'));
addressElem.addEventListener('keyup', (e) => validateFormData(e.target, validType.TEXT, 'last name'));
ageElem.addEventListener('keyup', (e) => validateFormData(e.target, validType.ANY, 'designation'));
achievementsTitleElem.forEach(item => item.addEventListener('keyup' ,(e) => validateFormData(e.target, validType.TEXT ,'Title')));
return {
firstname: firstnameElem.value,
address: addressElem.value,
age: ageElem.value,
acheivements: addValues(['acheiv-title'],achievementsTitleElem)
}
}
function validateFormData(elem, elemType, elemName) {
// checking for text string and non empty string
if (elemType == validType.TEXT) {
if (!strRegex.test(elem.value) || elem.value.trim().length == 0) {
addErrMsg(elem, elemName);
}
else{
removeErrMsg(elem);
}
}
}
// adding the invalid text
function addErrMsg(formElem, formElemName){
formElem.nextElementSibling.innerHTML = '${formElemName} is invalid !';
}
//removing the invalid text
function removeErrMsg(formElem){
formElem.nextElementSibling.innerHTML = "";
}
const generateCV = () => {
let userData = getUserInputs();
}
I tried also to test the element without "addVlues( )" if it's returning something but it shows me 1 and with out any reference to the element, also when tried ".values" instead of ".length" it shows no error but the values are undefined
const getUserInputs = () => {
// achievements
let achievementsTitleElem = document.querySelectorAll('.acheiv-title');
console.log(achievementsTitleElem.length);
/*
// event listeners for validation
firstnameElem.addEventListener('keyup', (e) => validateFormData(e.target, validType.TEXT, 'First name'));
addressElem.addEventListener('keyup', (e) => validateFormData(e.target, validType.TEXT, 'last name'));
ageElem.addEventListener('keyup', (e) => validateFormData(e.target, validType.ANY, 'designation'));
achievementsTitleElem.forEach(item => item.addEventListener('keyup' ,(e) => validateFormData(e.target, validType.TEXT ,'Title')));
*/
return {
firstname: firstnameElem.value,
address: addressElem.value,
age: ageElem.value,
// acheivements: addValues(['acheiv-title'],achievementsTitleElem)
}
}