<div class="search-input" onclick="getSearch()">
<input
oninput="getPorts(value)"
type="text"
id="pick"
name="pick"
placeholder="Enter Pickup Location"
required
/>
<div class="autocom-box">
<!-- dynamic portsData map box -->
</div>
</div>
<div class="search-input" onclick="getSearch()">
<input
oninput="getPorts(value)"
type="text"
id="dest"
name="dest"
placeholder="Enter Destination"
required
/>
<div class="autocom-box">
<!-- dynamic portsData map box -->
</div>
</div>
This is Js
let searchWrapper;
let inputBox;
let suggBox;
const getSearch = () => {
searchWrapper = document.querySelector(".search-input");
console.log(searchWrapper);
inputBox = searchWrapper.querySelector("input");
console.log(inputBox);
suggBox = searchWrapper.querySelector(".autocom-box");
console.log(suggBox);
};
I am trying to get class selected based click as the class name is same (search-input) but here whichever div i click it always gets selected the 1st one. (In searchWrapper console.log it gives 1st div and its elements)
Can anyone tell me What am i doing wrong here so that i can get 2nd div and its elements if i click on 2nd div.
Two answers for you.
Using modern event handling
I suggest you don't use onxyz-attribute-style event handlers. There are multiple issues with them, but probably the most significant two are:
They can only call global functions.
The generated context for them is very complex, making it very easy to run into conflicts (for instance, if your function had the name removeChild or appendChild or in some cases submit, you wouldn't end up calling your function, you'd call a method on a DOM element instead).
Instead, look at using addEventListener. Here's an example where the event handlers are directly attached to your div elements:
<div class="search-input">
<input
oninput="getPorts(value)"
type="text"
id="pick"
name="pick"
placeholder="Enter Pickup Location"
required
/>
<div class="autocom-box">
<!-- dynamic portsData map box -->
</div>
</div>
<div class="search-input">
<input
oninput="getPorts(value)"
type="text"
id="dest"
name="dest"
placeholder="Enter Destination"
required
/>
<div class="autocom-box">
<!-- dynamic portsData map box -->
</div>
</div>
const getSearch = (event) => {
const searchWrapper = event.currentTarget;
const inputBox = searchWrapper.querySelector("input");
const suggBox = searchWrapper.querySelector(".autocom-box");
// ...
};
for (const element of document.querySelectorAll(".search-input")) {
element.addEventListener("click", getSearch);
}
I only did the div elements there, but you'd want to do the input elements as well.
You might also look at delegated event handling.
Continuing with onclick attribute
If you really want to keep using the onclick attribute, pass this into it:
<div class="search-input" onclick="getSearch(this)">
<!-- −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^ -->
this in the context generated for onxyz-attribute-style event handlers is the element the onclick attribute is on (the .search-input div in this case).
Then, in getSearch, search within that div:
const getSearch = (searchWrapper) => {
const inputBox = searchWrapper.querySelector("input");
const suggBox = searchWrapper.querySelector(".autocom-box");
// ...
};
First of all stop using inline event listeners. Use addEventListener instead. To do so, grab a list of all search input wrappers and iterate over the list, adding a click listener to each and every one.
When you have done so, the handler function automatically gets passed the event object, which contains the currentTarget property holding a reference to the element the event listener is bound to. This then allows you to find descendants of that element using querySelector on it instead of document.
To access the event object, you need to define a parameter name in your handler function. I've used event in below example, but you can name it anything you like.
let searchWrapper;
let inputBox;
let suggBox;
const getSearch = (event) => {
searchWrapper = event.currentTarget;
console.log(searchWrapper);
inputBox = searchWrapper.querySelector("input");
console.log(inputBox);
suggBox = searchWrapper.querySelector(".autocom-box");
console.log(suggBox);
};
for (const searchInput of document.querySelectorAll('.search-input')) {
searchInput.addEventListener('click', getSearch);
}
<div class="search-input">
<input type="text" id="pick" name="pick" placeholder="Enter Pickup Location" required />
<div class="autocom-box">
1. abc
</div>
</div>
<div class="search-input">
<input type="text" id="dest" name="dest" placeholder="Enter Destination" required />
<div class="autocom-box">
2. def
</div>
</div>
Related
I have a HTML page with an input field that the user enters a value into. The HTML code looks like this:
<div class="d-flex mg-b-0 mb-3" id="cbWrapper2">
<input type="number" name="message_average" class="form-control" id="id_message_average">
</div>
I'm trying to use JavaScript to get the value entered by the user so that I can then compare it against another value and write out the result, but I'm not sure how I collect the initial value being entered. What I have so far:
<script>
var value = document.getElementById("id_message_average").value;
console.log(value);
</script>
I'm just trying to write the value out for now so that I can tell it's working. Do I need to put it into some kind of event listener maybe when the user clicks onto another input field, or is there a way to have the script fire when a character is added?
There are indeed events to use to listen to changes in the input. One of them is called input, and you can use it like below.
The input event fires when the value of an <input>, <select>, or <textarea> element has been changed. More on MDN's doc.
var input = document.getElementById("id_message_average");
input.addEventListener("input", ()=>{
console.log(input.value)
});
<div class="d-flex mg-b-0 mb-3" id="cbWrapper2">
<input type="number" name="message_average" class="form-control" id="id_message_average">
</div>
For that you have add event listener.
let userInput = document.getElementById("id_message_average");
userInput.addEventListener("input", (e)=> {
console.log(e.target.value)
})'
You can use onClick function. If you choose onClick then you must need a button. Here is the example,
<form>
<div class="d-flex mg-b-0 mb-3" id="cbWrapper2">
<input type="number" name="message_average" class="form-control" id="id_message_average">
</div>
<button type='button' onclick="getInputValue()">Click me</button>
</form>
<script>
function getInputValue() {
var value = document.getElementById("id_message_average").value;
console.log(value);
}
</script>
I'm trying to insert a new label and input to my form when a button is clicked. Still quite new to JavaScript. I'm not really getting the hang of it.
I have the following form in my HTML file:
<form id="form" action="">
<label for="round">Runda:</label>
<input type="number" id="formRound">
<label for="">Datum:</label>
<input type="date" id= "formDate">
<label for="">Markör:</label>
<input type="text" id="formMarker">
<button id="addNewHole">Lägg till hål</button>
</form>
When I click my button with the ID "addNewHole" I was to create a new label and input.
This is my javascript code thus far.
let newInput = "<label>Hål:</label><br><input type=\"Text\" id=\"hole\"></input>"
document.querySelector("#addNewHole").addEventListener("click", function(newInput){
document.querySelector("#form").innerHTML = newInput;
})
I though this code would do what I wanted but when I click my button all I see is:
[object MouseEvent]
You are expecting that newInput will be passed into your event handler through the argument newInput, but event callbacks are automatically passed the Event object that triggered them and that is what your argument is representing. Since you've already declared newInput, you should just remove the argument declaration from the callback and access your variable.
let newInput = "<label>Hål:</label><br><input type=\"Text\" id=\"hole\"></input>"
document.querySelector("#addNewHole").addEventListener("click", function(){
document.querySelector("#form").innerHTML = newInput;
});
<form id="form" action="">
<label for="round">Runda:</label>
<input type="number" id="formRound">
<label for="">Datum:</label>
<input type="date" id= "formDate">
<label for="">Markör:</label>
<input type="text" id="formMarker">
<button id="addNewHole">Lägg till hål</button>
</form>
Beyond that:
An input element does not have a closing input tag.
A button element within a form will be a submit button by default. If you just want a button that doesn't submit, you need to add type="button".
You shouldn't search the document for the same DOM element over and over again as you are doing in your event callback. Get the DOM reference just once, outside of the function, and refer to that as often as you need to. Also, when accessing an element with an id, use .getElementById() as opposed to .querySelector() because .getElementById() is usually optimized to be faster.
You should avoid .innerHTML when you can as it has security and performance implications and (as you've seen) forces you to have to deal with quotes and concatenation. Instead, create new DOM objects, configure them and then append them into the document. This is more code, but the code is much easier to maintain.
So, here's your code reworked:
// Get your DOM references just once and use `.getElementById()` when
// searching for elements that have ID's
let myForm = document.getElementById("form");
// Create new DOM Object instead of building HTML strings
let newCode = document.createElement("div");
let newLabel = document.createElement("label");
newLabel.textContent = "Hål:";
let br = document.createElement("br");
let newInput = document.createElement("input");
newInput.type = "text";
newInput.id = "hole";
// Append the elements
newCode.appendChild(newLabel);
newCode.appendChild(br);
newCode.appendChild(newInput);
document.getElementById("addNewHole").addEventListener("click", function(){
// Append to the document
form.appendChild(newCode);
});
<form id="form" action="">
<label for="round">Runda:</label>
<input type="number" id="formRound">
<label for="">Datum:</label>
<input type="date" id= "formDate">
<label for="">Markör:</label>
<input type="text" id="formMarker">
<button id="addNewHole" type="button">Lägg till hål</button>
</form>
I have a div which I called quote_div and is the parentElement. It contains two input type="number" elements, a <label> element which I called r_lbl (variable name) and another <label> element called r_position (so that's four elements in one div).
I put an event listener on the div so that when either input type="number" element is changed I can perform a calculation.
quote_div.addEventListener("change", calculateCost);
Now I'm trying to access the r_position element on the div using the event trigger e (which is parsed to calculateCost(e) function) but i get an undefined error which is strange because I've predefined the value for r_position.
console.log("li element position: " + e.target.parentElement.r_position.value);
Is it not possible to do things this way? If so, what have I not understood?
Depending on your HTML structure, you could use NonDocumentTypeChildNode.previousElementSibling or NonDocumentTypeChildNode.nextElementSibling:
const div = document.getElementById('quote_div');
div.addEventListener('change', (e) => {
const target = e.target;
const label = target.previousElementSibling;
console.log(label.innerText);
});
<div id="quote_div">
<label class="r_lbl" for="input1">Label 1</label>
<input id="input1" type="number" />
<label class="r_position" for="input2">Label 2</label>
<input id="input2" type="number" />
</div>
Otherwise, you could use Element.querySelector() from the parent <div> using an id, class, name or any other selector:
const div = document.getElementById('quote_div');
div.addEventListener('change', (e) => {
const div = e.target.parentElement;
const label1 = div.querySelector('.r_lbl');
const label2 = div.querySelector('.r_position');
console.log(label1.innerText, label2.innerText);
});
<div id="quote_div">
<label class="r_lbl" for="input1">Label 1</label>
<input id="input1" type="number" />
<label class="r_position" for="input2">Label 2</label>
<input id="input2" type="number" />
</div>
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!");
});
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