I'm coding a small web app to log team members work time. It all works well, except one thing. When you tab on a fieldset a new page opens with a form to change the time for that person. The first time you tab it works, but when you click on the next fieldset it changes all input fields with the name 'begin-time' ?
I think i'm missing something but I'm not sure what it is.
I have the following form;
<form id="time-form">
<fieldset>
<div class="row">
<input type="text" value="Jonh Doe" id="fullname" name="fullname" readonly="">
<div class="time">
<input type="text" value="00:00" id="begin-time" name="begin-time" readonly="">
<input type="text" value="00:00" id="end-time" name="end-time" readonly="">
</div>
</fieldset>
<fieldset>
<div class="row">
<input type="text" value="Jane Doe" id="fullname" name="fullname" readonly="">
<div class="time">
<input type="text" value="00:00" id="begin-time" name="begin-time" readonly="">
<input type="text" value="00:00" id="end-time" name="end-time" readonly="">
</div>
</fieldset>
</form>
with the new form 'on tab';
<form id="add-time">
<input type="time" name="begin_time">
<input type="time" name="end_time">
</form>
and the javascript;
$$('#time-form fieldset').tap(function() {
var beginTime = $(this).find("[name='begin-time']");
$('#add-time input[name=begin_time]').change(function() {
beginTime.val(this.value);
});
$$('.add-time').tap(function() {
$('#addTimePage').addClass('pt-page-moveToRightEasing pt-page-ontop');
$('#timePage').addClass('pt-page-moveFromLeft pt-page-current');
setTimeout(function () {
$('#timePage').removeClass('pt-page-moveFromLeft');
$('#addTimePage').removeClass('pt-page-moveToRightEasing pt-page-ontop pt-page-current');
}, 400);
});
});
edit: I have setup a simple fiddle of the problem.
Okay, so I noticed a few problems:
Your first .click() call was targeting ALL time-form fieldsets when it should have only been targeting input fields.
Your .change() and second .click() are called inside the first .click() meaning the new methods will be called multiple times (because each use of .click() and .change() adds on to the actual event.
Your submit button wasn't actually submitting anything. It was just hiding itself.
To fix this, I gave each fieldset a class name of .fieldset-time so they can easily be looped through. I added an onclick() event to each <fieldset> to easily manipulate the one (and its children) that was clicked.
Here's the new JavaScript code:
// invoked each time an input with the onclick() attribute is clicked
function editTime(obj) {
$("#addTimePage").fadeIn();
$(obj).attr("id", "active"); // set id to active so we know this is the one we want to change
}
$("#submit").click(function() {
// get the new beginning and end times set by the user
var newBeginTime = $("#add-time input[name=begin_time]").val();
var newEndTime = $("#add-time input[name=end_time]").val();
// loop through all elements with class .fieldset-time and find the active one
$(".fieldset-time").each(function() {
if ($(this).attr("id") == "active") {
$(this).attr("id", "");
$("input[name=begin-time]", this).val(newBeginTime);
$("input[name=end-time]", this).val(newEndTime);
return false; // break out of the .each() loop
}
});
// finally, clear and hide the add time box
$("#add-time input[name=begin_time], #add-time input[name=end_time]").val("");
$("#addTimePage").fadeOut();
});
And the new JSFiddle: http://jsfiddle.net/J4Hjf/7/
I hope that's what you were looking for. :)
Related
I'm building a multipage form. On a few of the form's pages, I have questions that allow the user to add inputs dynamically if they need to add a job, or an award, etcetera. Here's what I'd like to do/what I have done so far.
What I Want to Do:
As the user adds fields dynamically, I want to validate those fields to make sure they have been filled in, and they are not just trying to move to the next page of the form with empty inputs.
After all the fields are successfully validated, a "Next" button at the bottom of the page, which up until this point was disabled, will become reenabled.
What I know How To Do
With some help, I've been able to workout a validation pattern for the inputs that are not dynamically added (such as First Name, Last Name) and I can extend this same logic to the first set of inputs that are not added dynamically. I have also worked out how to re-enable the "Next" button once all fields are good.
What I do Not Know How To Do
How do I write a function that extends the logic of the simple validation test to also check for dynamically added iterations.
http://codepen.io/theodore_steiner/pen/gwKAQX
var i = 0;
function addJob()
{
//if(i <= 1)
//{
i++;
var div = document.createElement("div");
div.innerHTML = '<input type="text" class="three-lines" placeholder="School Board" name="schoolBoard_'+i+'"> <input type="text" class="three-lines" placeholder="Position" name="position_'+i+'"> <input type="date" class="three-lines" name="years_'+i+'"> <input type="button" value="-" onclick="removeJob(this)">';
document.getElementById("employmentHistory").appendChild(div);
//}
}
function removeJob(div)
{
document.getElementById("employmentHistory").removeChild(div.parentNode);
i--;
};
function checkPage2()
{
var schoolBoard_1 = document.getElementById("schoolBoard_1").value;
if(!schoolBoard_1.match(/^[a-zA-Z]*$/))
{
console.log("something is wrong");
}
else
{
console.log("Working");
}
};
<div id="page2-content">
<div class="input-group" id="previousTeachingExperience">
<p class="subtitleDirection">Please list in chronological order, beginning with your most recent, any and all full-time or part-time teaching positions you have held.</p>
<div class="clearFix"></div>
<label id="teachingExpierience">Teaching Experience *</label>
<div id="employmentHistory">
<input type="text" class="three-lines" name="schoolBoard_1" id="schoolBoard_1" placeholder="School Board" onblur="this.placeholder='School Board'" onfocus="this.placeholder=''" onkeyup="checkPage2()" />
<input type="text" class="three-lines" name="position_1" placeholder="Position" onblur="this.placeholder='Position'" onfocus="this.placeholder=''" onkeyup="checkPage2()" />
<input type="date" class="three-lines" name="years_1" />
<input type="button" name="myButton" onclick="addJob()" value="+" />
</div>
</div><!--end of previousTeachingExperience Div -->
Instead of trying to validate each individual input element, I would recommend trying to validate them all at once. I believe that is what your checkPage2 function is doing.
You can add the onBlur event handler or the onKeyUp event handler you are currently using to all added inputs to run your form wide validation. This has the effect of checking each individual form element if it is valid so you know for sure you can enable the submit button.
Lastly, when removeJob is called, you should also run the form wide validation. It would look something like this:
function addJob()
{
i++;
var div = document.createElement("div");
div.innerHTML = '<input type="text" class="three-lines" placeholder="School Board" name="schoolBoard_'+i+'" onkeyup="checkPage2()"> <input type="text" class="three-lines" placeholder="Position" name="position_'+i+'" onkeyup="checkPage2()"> <input type="date" class="three-lines" name="years_'+i+'" onkeyup="checkPage2()"> <input type="button" value="-" onclick="removeJob(this)">';
document.getElementById("employmentHistory").appendChild(div);
}
function removeJob(div)
{
document.getElementById("employmentHistory").removeChild(div.parentNode);
i--;
checkPage2();
};
For every element that you make with document.createElement(...), you can bind to the onchange event of the input element, and then perform your validation.
Here's an updated version of your CodePen.
For example:
HTML
<div id="container">
</div>
Javascript
var container = document.getElementById("container");
var inputElement = document.createElement("input");
inputElement.type = "text";
inputElement.onchange = function(e){
console.log("Do validation!");
};
container.appendChild(inputElement);
In this case I'm directly creating the input element so I have access to its onchange property, but you can easily also create a wrapping div and append the inputElement to that.
Note: Depending on the freqency in which you want the validation to fire, you could bind to the keyup event instead, which fires every time the user releases a key while typing in the box, IE:
inputElement.addEventListener("keyup", function(e){
console.log("Do validation!");
});
I'm trying to check whether a check box is checked, and if it is checked, then I want to add the "required" attribute to an adjacent text field. I've tried it two different ways with no success. Here are the form elements and my two JQuery attempts.
neither of those will actually trigger the event. My browser either does nothing at all or triggers an "Empty string passed to getElementById()." event
Form elements:
<div class="col-sm-5">
<label id="checkboxNumber-label" class="toplabel" for="checkboxNumber">Checkbox</label>
<g:textField name="checkboxNumber" value="${...checkboxNumber}" class="form-control" required="" aria-labelledby="checkboxNumber-label"/>
<label class="checkbox-inline">
<g:checkBox name="checkboxYesNo" id="checkboxYesNo" value="${...checkboxYesNo}" onclick="chkboxYesChecked()"/>
</label>
</div>
<div class="col-sm-5">
<label id="someTextField-label" class="toplabel" for="someTextField">Some Text Field Here</label>
<g:textField name="someTextField" id="someTextField" value="${...someTextField}" class="form-control" aria-labelledby="someTextField-label"/>
</div>
JQuery:
function chkboxYesChecked(){
if($('#checkboxYesNo').prop('checked')){
$('#someTextField').prop('required',true);
$('#someTextField').append('<span class="required-indicator">*</span>');
}else{
$('#someTextField').removeAttr('required');
}
}
$(document).ready(function() {
$('#checkboxYesNo').click(function() {
if($(this).is(":checked"))
{
$('#someTextField').prop('required',true);
$('#someTextField').append('<span class="required-indicator">*</span>');
} else {
$('#someTextField').removeAttr('required');
}
});
});
With your markup this becomes more convoluted than it needs to be.
$(document).on("click", ".checkbox-inline :checkbox", function () {
var $nextTextbox = $(this).closest("div").next("div").find(":text").first();
if (this.checked) {
$nextTextbox.prop("required", true).after('<span class="required-indicator">*</span>');
} else {
$nextTextbox.prop("required", false).next('.required-indicator').remove();
}
});
Notes
This approach uses event delegation.
There are no IDs involved, because I suppose you need the same thing more than once on your page. Tying it to a specific element ID is counter-productive.
This approach relies on the specific document structure from your sample Grails template. If you want something more flexible and easier-to-read, change your HTML.
This applies to all checkboxes that have a text field in the immediately following <div>. Use CSS classes on your elements to filter it/make it apply to specific ones only.
If there is no immediately following <div> with a text box, the function does nothing.
$(this).is(":checked") is superfluous. You don't need jQuery to find out if the current DOM element is checked. this.checked is a lot simpler and has the same effect.
Don't use inline event handlers (onclick="..."). Ever.
See it in action:
$(document).on("click", ".checkbox-inline :checkbox", function () {
var $nextTextbox = $(this).closest("div").next("div").find(":text").first();
if (this.checked) {
$nextTextbox.prop("required", true).after('<span class="required-indicator">*</span>');
} else {
$nextTextbox.prop("required", false).next('.required-indicator').remove();
}
});
input[required] {
background-color: #FFD1D1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="col-sm-5">
<label id="checkboxNumber-label" class="toplabel" for="checkboxNumber">Checkbox</label>
<input type="text" name="checkboxNumber" value="${...checkboxNumber}" class="form-control" required="" aria-labelledby="checkboxNumber-label" />
<label class="checkbox-inline">
<input type="checkbox" name="checkboxYesNo" id="checkboxYesNo" value="${...checkboxYesNo}" />
</label>
</div>
<div class="col-sm-5">
<label id="someTextField-label" class="toplabel" for="someTextField">Some Text Field Here</label>
<input type="text" name="someTextField" id="someTextField" value="${...someTextField}" class="form-control" aria-labelledby="someTextField-label" />
</div>
This is my code:
Javascript:
$(".test").on("focusout", function (e) {
$("#output").append("Lost focus<br>");
});
HTML:
Inputs inside div:
<div class="test">
<input type="text" />
<input type="text" />
</div><br>
Inputs outside div:<br>
<input type="text" />
<div id="output">
</div>
I want to detect if user leaves "div.test". Unfortunately, "focusout" works also when I move focus to other object inside this div.
Look at this fiddle: http://jsfiddle.net/Piotrek1/wfukje3g/6/
Click on first input and use Tab to switch through textboxes. "
Lost focus" should appear only if user move out from the div, but it happens always. Why is that and how to change it?
The $ operator returns a collection. You have two inputs inside the <div class="test">. So it matches all elements and children with the .test class.
I think what you want two divs with separate input elements and two different classes OR, use an ID on the actual input element so the $ operator only matches the input id you want this event to fire on. http://jsfiddle.net/wfukje3g/7/
$("#test").on("focusout", function (e) {
$("#output").append("Lost focus<br>");
});
<div class="sometest">
<input id="test" type="text" />
<input type="text" />
</div><br>
Inputs outside div:<br>
<input type="text" />
<div id="output">
</div>
I have implemented piece of code to handle div focus out
$(document).ready(function () {
var count = 1;
$("#name").focusout(function (e) {
if($(this).has(e.relatedTarget).length === 0) {
$("#output").append("<label style='width:100%;'>"+ count++ +" Name div focus out </label>");
}
});
});
Inputs inside div:
<div id="name" class="test">
<input type="text" id="firstname"/>
<input type="text" id="lastname"/>
</div>
Inputs outside div:<br>
<input type="text" id="dob"/>
<div id="output" style="width:100%"></div>
In this piece of code I have used relatedTarget.
relatedTarget will provide the next focused element If next element is not the child of this div then it is div focus out.
Try this in your code.
I hope this will be helpful.
Thanks
JSFIDDLE LINK - Sample code
i have this html form
<form action="" method="post" name="login_form">
Email : <input type="text" id="email2" name="email" /><br />
<span id="passwordT" >Password : </span>
<input type="password" name="password" id="password2"/><br />
<input type="button" id="submit_botton" value="Login" />
<div><input id="forgot" type="button" value="Forgot your Password?" /></div>
</form>
and the javascript here
var forgot = $('#forgot');
var forgot2 = $('#forgot2');
forgot.click(function() {
$('#password2').hide();
$('span#passwordT').hide();
$('input#submit_botton').prop('value', 'Reset Passowrd');
$('input#forgot').replaceWith('<input id="forgot2" type="button" value="Login here" />');
});
$('input#forgot2').click(function() { // this function didnt want to work
$('input#forgot2').prop('value', 'Forgot your Password?');
$('#password2').show();
$('span#passwordT').show();
$('input#submit_botton').prop('value', 'Login');
});
HERE JS-DEMO
what i want is :
when i click on second function i will get back the buttons as they were in first time.
I tried to make this second function inside the first but what i got is the function works but only one time , i mean if i click again to reset password will not work.
thanks for the help.
Your problem is that you're trying to attach an event handler to an element that doesn't exist yet. That's not possible with direct event handlers. Use delegated events instead.
$(document).on('click','#forgot2', function(){ ... });
document can be replaced with any #forgot2 container that exists at binding time.
As a side note, take into account that when you use selectors by id (e.g #forgot2) it's not necessary to add anything else since an id identify one and just one element (repeated ids are not allowed). So this selector input#forgot2 is not wrong but more complex than necessary.
how can I add a wild card into this jquery bind event so that form fields with 'PauNumber' are ignored? This field is repeated for each entity. Unfortunately I can't easily assign a css class to it because the text box is created server side.
many thanks
<div class="PassengerWrapper">
<input type="text" value="" name="PauNumber0" id="PauNumber0">
</div>
<div class="PassengerWrapper">
<input type="text" value="" name="PauNumber1" id="PauNumber1">
</div>
<div class="PassengerWrapper">
<input type="text" value="" name="PauNumber2" id="PauNumber2">
</div>
$('.PassengerWrapper input[type=text], .PassengerWrapper select').not(':hidden').each(function () {
You can do it inside the .not('selector') to filter the elements you don't want
$('.PassengerWrapper input[type=text], .PassengerWrapper select').not(':hidden,input[name*=PauNumber]').each(function () {
You can use [name*=PauNumber] or [id*=PauNumber]
Here's an example fiddle for you http://jsfiddle.net/XQWmf/
Also link to the different selectors