Jump to content

Recommended Posts

I have an add more link that dynamically adds new fields, but these do not have a number after the initial letter.

How could I change the ID element of the newest fields to have the next number after the count of eventGroup divs.

$(document).ready(function(){
	$(".addMore").click(function(){
		var fieldHTML = '<div class="eventGroup">'+$(".eventGroupCopy").html()+'</div>';	$('body').find('.eventGroup:last').after(fieldHTML);
		// find last group, change ID to n p s e with next number.
		var eg = $('.eventGroup').length;
		// add the ID element to the newly added div group, with +1 of the count of divs with the class eventGroup
	});//add more fields group

	$("body").on("click",".remove",function(){	$(this).parents(".eventGroup").remove();	});//remove fields group
});
<!-- copy of input fields group -->
<div class="eventGroupCopy" style="display: none;">
	<input class="np" id="n" type="text" name="eventName[]" placeholder="Enter Event Name"><br>
	<input class="np" id="p" type="number" name="price[]" placeholder="Enter Price"><br>
	<input class="se" id="s"type="date" name="eventStart[]" value="">
	<input class="se" id="e"type="date" name="eventEnd[]" value=""><br>
	<a href="javascript:void(0)" class="remove">Remove</a><br>
</div>

 

Edited by jasonc310771
6 minutes ago, requinix said:

Stop using IDs.

Without the IDs how can I use the onClick error check to make sure the form is filled out correctly ?

One field is just text (n1), make sure the (n) fields are not duplicated text of another (n)

the next is a number only (p1), only check it is a number and not more than say 100000

the last two are named start (s1) and end (e1)

cross reference each groups start end to make sure that they do not overlap the other groups start/end dates

Each group has a different number so the error checker will highlight which boxes needs attention.

Edited by jasonc310771

you would use the same method that the 'add more click' function is using, of starting with the current element (this) and using tree traversal methods  with class selectors to navigate around in the DOM - https://api.jquery.com/category/traversing/tree-traversal/

50 minutes ago, mac_gyver said:

you would use the same method that the 'add more click' function is using, of starting with the current element (this) and using tree traversal methods  with class selectors to navigate around in the DOM - https://api.jquery.com/category/traversing/tree-traversal/

Ah, thank you.  I actually know very lttle, of JavaScript or jquery.  Just reading and trying to figure it out based on the knowledge I have other other languages.  The simple stuff I get there in the end. But this is all different.

Edited by jasonc310771

If not using IDs !

Then I am now trying to get the value of the item that calls the checkFormOK()

function checkFormOK() {
	var nameValue = $(this).val();
alert(nameValue);
}

Even though this does not work.  It was just to test if I could get the value of the input field that just changed.  But no way of know what field called it or which group the input field is in.  Which is why I had previously used IDs.  But now see that when I add or remove a new group the number is not added to new groups and the one that is removed means that I am missing a group number that causes the checkFormOK to break, even though I might of been able to check if it exists before doing a check.

There are only three checks:

To check that each field has content, if not change background color.

If the dates entered in each group is valid

That no date range in each group overlaps that of another groups date range.

1 hour ago, jasonc310771 said:

the item that calls the checkFormOK()

what item? we cannot help you unless you post the complete code the reproduces the problem. in programming, there are just too many different ways of accomplishing a task. it takes knowing how you go to a point, in order to help you.

This is what I have at the moment...

This is using IDs, how do I get the same results without using IDs as I was unable to add a new ID to the new group, also if one is deleted then their is a number missing which causes problems with the checker.

<!DOCTYPE html>
<html lang="en">
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<link href="scripts/jquery-ui.css" rel="stylesheet">
<script src="scripts/jquery-2.0.3.min.js"></script>
<script src="scripts/jquery-ui.js"></script>

<style>
.eventGroup { float: left; padding: 0 3em 3em 0; }
.eventGroup .np { width: 20em; }
.eventGroup .se { float: left; width: 10em; }
.addMore { padding-right: 1.5em; }
.formError { background-color: #FF4747; }
</style>

<script>
	$(document).ready(function(){
		$(".addMore").click(function(){
			var fieldHTML = '<div class="eventGroup">'+$(".eventGroupCopy").html()+'</div>';	$('body').find('.eventGroup:last').after(fieldHTML);
// find last group, change ID to n p s e with next number.
//				var eg = $('#form .eventGroup').length;
//				document.getElementById('n').setAttribute('id', 'n' + (eg + 1));
//				document.getElementById('p').setAttribute('id', 'p' + (eg + 1));
//				document.getElementById('s').setAttribute('id', 's' + (eg + 1));
//				document.getElementById('e').setAttribute('id', 'e' + (eg + 1));
//			var lastChildID = lastChild.id;
				// add the ID element to the newly added div group, with +1 of the count of divs with the class eventGroup
//			newEventGroup.setAttribute("id", "eg + 1");
		});//add more fields group
	$("body").on("click",".remove",function(){	$(this).parents(".eventGroup").remove();	});//remove fields group
});

function checkFormOK() {
//alert($('.eventGroup').length - 1);
// When a field is changed, check if it is empty, if so, mark as red.
		for (var id = 0; id < $('.eventGroup').length - 1; id++) {
//alert(id);
			if ($('#n' + id).val() == '') { document.getElementById('n' + id).className = 'np formError';
			} else { document.getElementById('n' + id).className = 'np';
			}
			if ($('#p' + id).val() == '') { document.getElementById('p' + id).className = 'np formError';
			} else { document.getElementById('p' + id).className = 'np';
			}
			if ($('#s' + id).val() == '') { document.getElementById('s' + id).className = 'se formError';
			} else { document.getElementById('s' + id).className = 'se';
			}
			if ($('#e' + id).val() == '') { document.getElementById('e' + id).className = 'se formError';
			} else { document.getElementById('e' + id).className = 'se';
			}
		}

// When a date field is changed, check if the dates entered overlap any of the other dates in other groups.
		for (var s1 = 0; s1 < $('.eventGroup').length - 1; s1++) {
				for (var s2 = 0; s2 < $('.eventGroup').length - 1; s2++) {
					if (s1 != s2) { // do not check a group with itself !, skip to next one.
						if (document.getElementById('s' + s1).value >= document.getElementById('s' + s2).value &&
						document.getElementById('e' + s1).value < document.getElementById('e' + s2).value) {
								document.getElementById('s' + s1).className = 'se formError'; document.getElementById('s' + s2).className = 'se formError';
								document.getElementById('e' + s1).className = 'se formError'; document.getElementById('e' + s2).className = 'se formError';
						}
					}
				}
		}
}
</script>

</head>
<body>

<form method="post" action="editDatePrices.php">
		<div class="centerText">
			<div class="eventGroup">
				<input class="np" id="n0" onchange="checkFormOK()" type="text" name="eventName[]" placeholder="Enter name" value="Event 1"><br>
				<input class="np" id="p0" onchange="checkFormOK()" type="number" name="price[]" placeholder="Enter Price i.e.&nbsp;&nbsp;&nbsp;1000&nbsp;&nbsp;&nbsp;no decimals" value="123"><br>
				<input class="se" id="s0" onchange="checkFormOK()" type="date" name="eventStart[]" value="2023-08-13">
				<input class="se" id="e0" onchange="checkFormOK()" type="date" name="eventEnd[]" value="2023-08-14">
				<div class="clearFloat"></div>
				<a href="javascript:void(0)" class="remove">Remove</a>
			</div>
			<div class="eventGroup">
				<input class="np" id="n1" onchange="checkFormOK()" type="text" name="eventName[]" placeholder="Enter name" value="Event 1"><br>
				<input class="np" id="p1" onchange="checkFormOK()" type="number" name="price[]" placeholder="Enter Price i.e.&nbsp;&nbsp;&nbsp;1000&nbsp;&nbsp;&nbsp;no decimals" value="123"><br>
				<input class="se" id="s1" onchange="checkFormOK()" type="date" name="eventStart[]" value="2023-08-13">
				<input class="se" id="e1" onchange="checkFormOK()" type="date" name="eventEnd[]" value="2023-08-14">
				<div class="clearFloat"></div>
				<a href="javascript:void(0)" class="remove">Remove</a>
			</div>
		<div class="eventGroup" style="display: none;"></div>
		<div class="clearFloat"></div>
		</div>
	<br><a href="javascript:void(0)" class="addMore">Add more</a>
	<input type="submit" name="submit" value="SUBMIT" onclick="checkFormOK()">
</form>

			<!-- copy of input fields group -->
			<div class="eventGroupCopy" style="display: none;">
				<input class="np" id="n" type="text" name="eventName[]" placeholder="Enter Event Name"><br>
				<input class="np" id="p" type="number" name="price[]" placeholder="Enter Price"><br>
				<input class="se" id="s"type="date" name="eventStart[]" value="">
				<input class="se" id="e"type="date" name="eventEnd[]" value=""><br>
				<a href="javascript:void(0)" class="remove">Remove</a><br>
			</div>


</body>
</html>

 

Edited by jasonc310771

So I have removed all reference to IDs.

But still not able to get the value of the input or set the BG color of the fields if they are empty.

<!DOCTYPE html>
<html lang="en">
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<link href="scripts/jquery-ui.css" rel="stylesheet">
<script src="scripts/jquery-2.0.3.min.js"></script><?php // this line nust be first before the jquery-ui.js ?>
<script src="scripts/jquery-ui.js"></script>


<style>
.eventGroup { float: left; padding: 0 3em 3em 0; }
.eventGroup .n, .eventGroup .p { width: 20em; }
.eventGroup .s, .eventGroup .e { float: left; width: 10em; }
.addMore { padding-right: 1.5em; }
.formError { background-color: #FF4747; }
</style>

<script>
	$(document).ready(function(){
			$(".addMore").click(function(){
				var fieldHTML = '<div class="eventGroup">'+$(".eventGroupCopy").html()+'</div>';	$('body').find('.eventGroup:last').after(fieldHTML);
			});//add more fields group

		$("body").on("click",".remove",function(){	$(this).parents(".eventGroup").remove();	});//remove fields group
	});

function checkFormOK(field) {
alert(field + ' ' + $(this).find('value').val());
// When a field is changed, check if it is empty, if so, mark as red.
	if (field == 'n') { // process the names.
		if ($(this).find('value').val() == '') { $(this).attr('class', 'n formError');		//		does not change the BG color.
		} else { $(this).attr('class', 'n');
		}
	}
	if (field == 'p') { // process the prices.
	}

//	When a date field is changed, check if the dates entered overlap any of the other dates in other groups.
	if (field == 's' || field == 'e') { // process the dates.
	}

}

/*
// When a date field is changed, check if the dates entered overlap any of the other dates in other groups.
//var startDates = document.getElementsByClassName('s');
//var endDates = document.getElementsByClassName('e');
//	for (let s = 0; s < startEndDates.length; s++) {
//		for (let e = 0; e < startEndDates.length; e++) {
			//console.log(groups[i].value);

			if (s1 != s2) { // do not check a group with itself !, skip to next one.
				if (document.getElementsByClassName('s' + s1).value >= document.getElementsByClassName('s' + s2).value &&
				document.getElementsByClassName('e' + s1).value < document.getElementsByClassName('e' + s2).value) {
						document.getElementsByClassName('s' + s1).className = 'se formError'; document.getElementsByClassName('s' + s2).className = 'se formError';
						document.getElementsByClassName('e' + s1).className = 'se formError'; document.getElementsByClassName('e' + s2).className = 'se formError';
				}
			}

//		}
//	} 
*/
</script>

</head>
<body>

<form method="post" action="editDatePrices.php">
		<div class="centerText">
			<div class="eventGroup">
				<input class="n" onchange="checkFormOK('n')" type="text" name="eventName[]" placeholder="Enter name" value="Event 1"><br>
				<input class="p" onchange="checkFormOK('p')" type="number" name="price[]" placeholder="Enter Price i.e.&nbsp;&nbsp;&nbsp;1000&nbsp;&nbsp;&nbsp;no decimals" value="123"><br>
				<input class="s" onchange="checkFormOK('s')" type="date" name="eventStart[]" value="2023-08-13">
				<input class="e" onchange="checkFormOK('e')" type="date" name="eventEnd[]" value="2023-08-14">
				<div class="clearFloat"></div>
				<a href="javascript:void(0)" class="remove">Remove</a>
			</div>
			<div class="eventGroup">
				<input class="n" onchange="checkFormOK('n')" type="text" name="eventName[]" placeholder="Enter name" value="Event 1"><br>
				<input class="p" onchange="checkFormOK('p')" type="number" name="price[]" placeholder="Enter Price i.e.&nbsp;&nbsp;&nbsp;1000&nbsp;&nbsp;&nbsp;no decimals" value="123"><br>
				<input class="s" onchange="checkFormOK('s')" type="date" name="eventStart[]" value="2023-08-13">
				<input class="e" onchange="checkFormOK('e')" type="date" name="eventEnd[]" value="2023-08-14">
				<div class="clearFloat"></div>
				<a href="javascript:void(0)" class="remove">Remove</a>
			</div>
		<div class="eventGroup" style="display: none;"></div>
		<div class="clearFloat"></div>
		</div>
	<br><a href="javascript:void(0)" class="addMore">Add more</a>
	<input type="submit" name="submit" value="SUBMIT" onclick="checkFormOK()">
</form>

			<!-- copy of input fields group -->
			<div class="eventGroupCopy" style="display: none;">
				<input class="n" onchange="checkFormOK('n')" type="text" name="eventName[]" placeholder="Enter Event Name" value=""><br>
				<input class="p" onchange="checkFormOK('p')" type="number" name="price[]" placeholder="Enter Price" value=""><br>
				<input class="s" onchange="checkFormOK('s')" type="date" name="eventStart[]" value="">
				<input class="e" onchange="checkFormOK('e')" type="date" name="eventEnd[]" value=""><br>
				<a href="javascript:void(0)" class="remove">Remove</a><br>
			</div>


</body>
</html>

 

Slowly getting there with yet more hours of trial and error, story of my entire life...

I now know which one of the group is being checked and got the value from the input.

Just to get the BG to change.

function checkFormOK(field) {
alert(	field + ' ' + $('input:text').val());
// When a field is changed, check if it is empty, if so, mark as red.
	if (field == 'n') { // process the names.
		if ($('input:text').val().length == 0) { $(this).attr('class', 'n formError');		//		does not change the BG color.
		} else { $(this).attr('class', 'n');
		}
	}
//	if (field == 'p') { // process the prices.
//	}

//	When a date field is changed, check if the dates entered overlap any of the other dates in other groups.
//	if (field == 's' || field == 'e') { // process the dates.
//	}

}

 

And using AddClass is not adding to the class

function checkFormOK(field) {
//alert(	field + ' ' + $('input:text').val());
// When a field is changed, check if it is empty, if so, mark as red.
	if (field == 'n') { // process the names.
		if ($('input:text').val().length == 0) {
//			alert('empty');
			$(this).addClass('formError');		//		does not change the BG color.
		} else { $(this).removeClass('formError');
		}
	}
//	if (field == 'p') { // process the prices.
//	}

//	When a date field is changed, check if the dates entered overlap any of the other dates in other groups.
//	if (field == 's' || field == 'e') { // process the dates.
//	}

}

So now I have it change the BG color, but on every field with theat class name.

How do I correctly add to the class to just the one being checked by the onchange click and not all that have the same name ?

function checkFormOK(field) {
//alert(	field + ' ' + $('input:text').val());
// When a field is changed, check if it is empty, if so, mark as red.
	if (field == 'n') { // process the names.
		if ($('input:text').val().length == 0) {
//			alert('empty');
			$('.n').addClass('formError');		//		does not change the BG color.
		} else { $('.n').removeClass('formError');
		}
	}
//	if (field == 'p') { // process the prices.
//	}

//	When a date field is changed, check if the dates entered overlap any of the other dates in other groups.
//	if (field == 's' || field == 'e') { // process the dates.
//	}

}

 

Edited by jasonc310771

You need to change your approach, and stop using onchange="" attributes on your fields.  Notice how in order to make your remove link work, you bound your event to the body rather than the actual remove link?

$("body").on("click", ".remove", function() {
    $(this).parents(".eventGroup").remove();
  }); //remove fields group

You need to do the same sort of thing with your change event.  Bind it to a parent element, then get the element that triggered it in the event handler.  The event handler is passed an event object which has a property called target which will be a reference to the element which triggered the event.  You can use that to obtain the input, then check which type of input it is by checking for your various classes.

$('form').on('change', checkFormOK);

function checkFormOK(event) {
  //Get the input which triggered the change event.
  const input = $(event.target);
  
  //If the input has class n
  if (input.is('.n')) { // process the names.
    if (input.val() === '') {
      input.addClass('formError');
    } else {
      input.removeClass('formError');
    }
  }
  
  //If the input has class p
  if (input.is('.p')) { // process the prices.
  }

  //If the input has class s or class e
  if (input.is('.s, .e')) { // process the dates.
  }
}

Full example.

 

we after a time...  this is what I have and all works so far apart from date fields.

I need to make sure none of the dates over lap another group.  But just can not get this to work.

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <style>
    .error {
      background-color: red;
    }
  </style>
</head>
<body>
  <form id="my-form">
    <div class="group">
      <input type="text" name="name[]" required><br>
      <input type="number" name="price[]" required><br>
      <input type="date" name="start[]" class="start" required>
	  <input type="date" name="end[]" class="end" required>
    </div>
	<br>
    <div class="group">
      <input type="text" name="name[]" required><br>
      <input type="number" name="price[]" required><br>
      <input type="date" name="start[]" class="start" required>
      <input type="date" name="end[]" class="end" required>
    </div>
	<br>
    <div class="group">
      <input type="text" name="name[]" required><br>
      <input type="number" name="price[]" required><br>
      <input type="date" name="start[]" class="start" required>
      <input type="date" name="end[]" class="end" required>
    </div>
    <input type="submit" value="Submit">
  </form>

  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script>
    $(document).ready(function() {
      // Add error class to empty fields
      $('form').on('blur', 'input', function() {
        var value = $(this).val();
        if (value === '') {
          $(this).addClass('error');
        } else {
          $(this).removeClass('error');
        }
      });

      // Validate date fields
      $('form').on('change', '.start, .end', function() {
        var startDate = $(this).closest('.group').find('.start').val();
        var endDate = $(this).closest('.group').find('.end').val();

alert('startDate ' + startDate + ' | endDate ' + endDate);

        // Check if date is in the past
        //var currentDate = new Date();
		const date = new Date();
		var currentDate = date.toLocaleDateString('en-GB').split('/').reverse().join('-'); // '2021-11-24'
alert(currentDate);
        if (startDate < currentDate || endDate < currentDate) {
          $(this).addClass('error');
        } else {
          $(this).removeClass('error');
        }

        // Check if start date is after end date
        if (startDate > endDate) {
          $(this).closest('.group').find('.end').addClass('error');
        } else {
          $(this).closest('.group').find('.end').removeClass('error');
        }

        // Check if start date conflicts with other groups
        var startDates = $('.start').not($(this));
        startDates.each(function() {
          var otherStartDate = new Date($(this).val());
          if (startDate > otherStartDate) {
            $(this).addClass('error');
          } else {
            $(this).removeClass('error');
          }
        });
      });

      // Allow one group to use the same start date as another group's end date
      $('form').on('change', '.start', function() {
        var startDate = new Date($(this).val());
        var endDates = $('.end').not($(this).closest('.group').find('.end'));
        endDates.each(function() {
          var otherEndDate = new Date($(this).val());
          if (startDate.getTime() === otherEndDate.getTime()) {
            $(this).removeClass('error');
          }
        });
      });

      // Prevent form submission if there are errors
      $('form').on('submit', function(event) {
        var errors = $('.error');
        if (errors.length > 0) {
          event.preventDefault();
          alert('Please fill in all required fields correctly.');
        }
      });
    });
  </script>
</body>
</html>

 

46 minutes ago, jasonc310771 said:

edit:

I have placed an alert in the code to show what the actual dates are and it all looks ok, but for some reason JS/JQuery is not seeing it as a date, is that right ?

alert results...

|2023-08-13| currentDate
|2023-08-09| startDate
|2023-08-25| endDate

the startDate is old so should be mark as red.

-----------------

we after a time...  this is what I have and all works so far apart from date fields.

I need to make sure none of the dates over lap another group.  But just can not get this to work.

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <style>
    .error {
      background-color: red;
    }
  </style>
</head>
<body>
  <form id="my-form">
    <div class="group">
      <input type="text" name="name[]" required><br>
      <input type="number" name="price[]" required><br>
      <input type="date" name="start[]" class="start" required>
	  <input type="date" name="end[]" class="end" required>
    </div>
	<br>
    <div class="group">
      <input type="text" name="name[]" required><br>
      <input type="number" name="price[]" required><br>
      <input type="date" name="start[]" class="start" required>
      <input type="date" name="end[]" class="end" required>
    </div>
	<br>
    <div class="group">
      <input type="text" name="name[]" required><br>
      <input type="number" name="price[]" required><br>
      <input type="date" name="start[]" class="start" required>
      <input type="date" name="end[]" class="end" required>
    </div>
    <input type="submit" value="Submit">
  </form>

  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script>
    $(document).ready(function() {
      // Add error class to empty fields
      $('form').on('blur', 'input', function() {
        var value = $(this).val();
        if (value === '') {
          $(this).addClass('error');
        } else {
          $(this).removeClass('error');
        }
      });

      // Validate date fields
      $('form').on('change', '.start, .end', function() {
        var startDate = $(this).closest('.group').find('.start').val();
        var endDate = $(this).closest('.group').find('.end').val();

alert('startDate ' + startDate + ' | endDate ' + endDate);

        // Check if date is in the past
        //var currentDate = new Date();
		const date = new Date();
		var currentDate = date.toLocaleDateString('en-GB').split('/').reverse().join('-'); // '2021-11-24'
alert(currentDate);
        if (startDate < currentDate || endDate < currentDate) {
          $(this).addClass('error');
        } else {
          $(this).removeClass('error');
        }

        // Check if start date is after end date
        if (startDate > endDate) {
          $(this).closest('.group').find('.end').addClass('error');
        } else {
          $(this).closest('.group').find('.end').removeClass('error');
        }

        // Check if start date conflicts with other groups
        var startDates = $('.start').not($(this));
        startDates.each(function() {
          var otherStartDate = new Date($(this).val());
          if (startDate > otherStartDate) {
            $(this).addClass('error');
          } else {
            $(this).removeClass('error');
          }
        });
      });

      // Allow one group to use the same start date as another group's end date
      $('form').on('change', '.start', function() {
        var startDate = new Date($(this).val());
        var endDates = $('.end').not($(this).closest('.group').find('.end'));
        endDates.each(function() {
          var otherEndDate = new Date($(this).val());
          if (startDate.getTime() === otherEndDate.getTime()) {
            $(this).removeClass('error');
          }
        });
      });

      // Prevent form submission if there are errors
      $('form').on('submit', function(event) {
        var errors = $('.error');
        if (errors.length > 0) {
          event.preventDefault();
          alert('Please fill in all required fields correctly.');
        }
      });
    });
  </script>
</body>
</html>

 

client-side validation is a nicety for legitimate visitors. since you must validate the data on the server before using it, why go to all this trouble to duplicate the logic in the client that you (already) have in the server-side code? and if you want to pre-validate the data in the client, why not just send the relevant data values to the server using ajax, run it through the (existing) validation logic, and display the result returned by that validation logic?

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.