How to find parent's child with querySelector instead of jQuery? - javascript

Requirements dictate that I cannot use jQuery and I'm trying to solve the following problem w/out it.
Layout has has identical multiple inputs like this
<div class="item">
<input type="text" />
<input type="file" />
</div>
<div class="item">
<input type="text" />
<input type="file" />
</div>​​​​​​​​​​​​​​​​​​​​​
And the javascript needs to find the sibling file input when a textbox is clicked.
$('input[type=text]').click(function() {
$(this).parent(".item")
.find('input[type=file]')
.trigger('click');
});
Note: I cannot use Ids because there are multiple (many) "items" on the page.

You can use vanila script event handlers and the next sibling relationship between the elements like
//get all the text input elements which are descendants of .item
var els = document.querySelectorAll('.item input[type="text"]');
for (var i = 0; i < els.length; i++) {
//add click handler
els[i].addEventListener('click', function() {
//nextElementSibling is supported from IE9
this.nextElementSibling.click()
//or
//this.parentNode.querySelector('input[type="file"]').click()
})
}
<div class="item">
<input type="text" />
<input type="file" />
</div>
<div class="item">
<input type="text" />
<input type="file" />
</div>
nextElementSibling

Related

How to get the element on clicking it's parent element

I want to get the specific input element on clicking on the click button. And there might be more input element with this class "quan" in the future. So, I want to get the specific input element with class "quan" on clicking the click button which associate with it. The way I did in the js file only give me the first element of that class name. How do I get the specific element? Thanks for your help.
HTML
<div>
<div>
<button onclick="click(event)>Click<button>
</div>
<div>
<input class="quan" type="number" min="0" value="2"/>
</div>
</div>
Javascript
function click(event){
console.log(document.querySelector(".quan"));
}
Use a selector finding the common ancestor (using closest) of them and find the correct child.
function my_click(elem) {
// ideally elem.closest(".group-name")
// but this will also do
var parent = elem.parentNode.parentNode
var child = parent.querySelector(".quan")
console.log(child.value);
}
<div>
<div>
<button onclick="my_click(this)">Click</button>
</div>
<div>
<input class="quan" type="number" min="0" value="1" />
</div>
</div>
<div>
<div>
<button onclick="my_click(this)">Click</button>
</div>
<div>
<input class="quan" type="number" min="0" value="2" />
</div>
</div>

set javascript variable using html attribute

I am trying to re-create the functionality of https://chriscoyier.net/ where you have a form with radio buttons, and as you click a radio button, the text changes.
What I started with was:
window.onload=function() {
document.getElementById("hidden_elements").style.display="none";
// attach the click event handler to the radio buttons
var radios = document.forms[0].elements["group1"];
for (var i = [0]; i < radios.length; i++)
radios[i].onclick=radioClicked;
}
function radioClicked() {
if (this.value == "two") {
document.getElementById("hidden_elements").style.display="block";
} else {
document.getElementById("hidden_elements").style.display="none";
}
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="one" />
Item 2: <input type="radio" name="group1" value="two" />
Item 3: <input type="radio" name="group1" value="three" /><br />
<br />
<div id="hidden_elements">
Input 1: <input type="text" id="intext" />
Input 2: <input type="text" id="intext2" />
Input 3: <input type="text" id="intext3" /><br /><br />
</div>
<input type="submit" id="submitbutton" value="Send form" />
</form>
This allows me hide or display the div with id="hidden_elements" if input number 2 is selected.
What I want to do is hide or display the individual elements of "hidden_elements" based on the input 1, 2 or 3.
I tried changing the "hidden_elements" attributes to:
<div id="hidden_elements">
Input 1: <input type="text" name="one" />
Input 2: <input type="text" name="two" />
Input 3: <input type="text" name="three" /><br /><br />
</div>
and JS to:
var hide = document.getElementById("hidden_elements");
for (var i = [0]; i < hide.length; i++)
hide[i].style.display = "none";
function radioClicked() {
document.getElementsByName(this.value).style.display = "block"
}
But that doesn't work either.
I've tried a less appealing approach using if/else statements, but that too doesn't work.
<div id="paragraphs">
<div id="hidden_element" name="one">Paragraph 1 </div>
<div id="hidden_element" name="two">Paragraph 2 </div>
<div id="hidden_element" name="three">Paragraph 3 </div>
</div>
function radioClicked() {
if (this.value == "one") {
document.getElementById("hidden_element_one").style.display="block";
} else if (this.value == "two") {
document.getElementById("hidden_element_two").style.display="block";
} else if (this.value == "three") {
document.getElementById("hidden_element_three").style.display="block";
}
}
I've tried a few more approaches but the behaviour isn't what I want. Any idea how I can change the display from "none" to "block" based on the selected radio-button? (I know you can do it with JQuery but I'm trying to learn Javascript)
A few notes:
getElementsByName returns a list of elements. That list doesn't have a style property (the entries on the list do).
ids must be unique, you can't put the same ID on multiple elements. Use a class to group elements together.
data-* attributes would probably be a better choice than name, since you can use them on any element type.
If you want to show/hide elements based on the radio button value, you'll need to select all of the elements you show/hide, not just the one matching the radio button's value. Then loop through that list, showing/hiding depending on whether they match the selected value.
The load event happens very late in the page load cycle (e.g., right at the end). Instead of using load, put your script tags at the very end of your document, just before the closing </body> tag, and do your event hook-up immediately.
I'd probably use a class to toggle visibility rather than style.display.
You can get the attribute from an element via getAttribute.
You can use querySelectorAll to get a list of elements matching any CSS selector. Use it on document to look globally, or on a specific element to only look within that element. For instance, to get a list of elements in the document with an attribute called data-val, you'd use the CSS selector [data-val], e.g. `document.querySelectorAll("[data-val]").
Here's a version of your snippet with some minimal updates; see comments:
// I'd use querySelectorAll rather than the old-style
// forms and elements collections (but those work too)
var radios = document.querySelectorAll("#picker input[type=radio]");
// Initial value is 0, not [0]
for (var i = 0; i < radios.length; i++) { // You were missing { on this line
// Recommend modern event handling, not onclick
radios[i].addEventListener("click", radioClicked);
}
function radioClicked() {
var hidden = document.getElementById("hidden_elements");
hidden.classList.remove("hidden");
// Get all elements within it that have a data-val attribute
var list = hidden.querySelectorAll("[data-val]");
for (var i = 0; i < list.length; ++i) {
var el = list[i];
// Add/remove the hidden class depending on whether it matches
el.classList.toggle("hidden", el.getAttribute("data-val") != this.value);
}
}
.hidden {
display: none;
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="one" />
Item 2: <input type="radio" name="group1" value="two" />
Item 3: <input type="radio" name="group1" value="three" /><br />
<br />
<!-- Hide this initially with markup rather than code -->
<div id="hidden_elements" class="hidden">
<!-- Use data-val to identify them -->
Input 1: <input type="text" data-val="one" />
Input 2: <input type="text" data-val="two" />
Input 3: <input type="text" data-val="three" /><br /><br />
</div>
<input type="submit" id="submitbutton" value="Send form" />
</form>
Some further changes you might make:
Wrap all the code in an IIFE so nothing is global.
Wrap the inputs and their labels in label elements, and toggle the visibility of them rather than the inputs directly.
Wrap things in containers for line breaks rather than using br.
You could do something like this :
Add a common class on the elements you want to toggle (can wrap label and field in span)
Toggle their display, can use a css class for hiding and a class same as the value of the checkbox
function radioClicked(e) {
//hide previously shown
var elem = document.getElementById("hidden_elements").getElementsByClassName("shown")[0];
if (elem) {
elem.classList.remove("shown");
elem.classList.add("hide");
}
//show currently selected
elem = document.getElementById("hidden_elements").getElementsByClassName(e.value)[0];
elem.classList.remove("hide");
elem.classList.add("shown");
}
.hide {
display: none;
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="one" onclick="radioClicked(this)" />
Item 2: <input type="radio" name="group1" value="two" onclick="radioClicked(this)" />
Item 3: <input type="radio" name="group1" value="three" onclick="radioClicked(this)" /><br />
<br />
<div id="hidden_elements">
<span class="hide one elem">Input 1: <input type="text" id="intext" /></span>
<span class="hide two elem">Input 2: <input type="text" id="intext2" /></span>
<span class="hide three elem">Input 3: <input type="text" id="intext3" /></span>
</div>
<input type="submit" id="submitbutton" value="Send form" />
</form>
My solution changes the values of the radio buttons to the numeric value rather than the the text value. This enabled it to be used to select the input element by id and appending the number.
Each time radioClicked() is run it hides all the inputs and only shows the selected one. To do this I've wrapped all the inputs and their labels in span elements.
window.onload=function() {
// attach the click event handler to the radio buttons
var radios = document.forms[0].elements["group1"];
for (var i = [0]; i < radios.length; i++)
radios[i].onclick=radioClicked;
}
function radioClicked() {
var allRadio = document.querySelectorAll('#hidden_elements span');
Array.prototype.forEach.call(allRadio, function(el, i){
el.style.display="none";
});
var selectedRadio = this.value;
document.getElementById("intext" + selectedRadio).parentNode.style.display="block";
}
#hidden_elements span {
display: none;
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="1" />
Item 2: <input type="radio" name="group1" value="2" />
Item 3: <input type="radio" name="group1" value="3" /><br />
<br />
<div id="hidden_elements">
<span>Input 1: <input type="text" id="intext1" /></span>
<span>Input 2: <input type="text" id="intext2" /></span>
<span>Input 3: <input type="text" id="intext3" /></span><br /><br />
</div>
<input type="submit" id="submitbutton" value="Send form" />
</form>
My solution add extra div for all inputs and id for this div
window.onload = function() {
var hide = document.getElementsByClassName("hidden");
for (var i = [0]; i < hide.length; i++)
hide[i].style.display = "none";
// attach the click event handler to the radio buttons
var radios = document.forms[0].elements["group1"];
for (var i = [0]; i < radios.length; i++)
radios[i].onclick = radioClicked;
}
function radioClicked() {
var hide = document.getElementsByClassName("hidden");
for (var i = [0]; i < hide.length; i++)
hide[i].style.display = "none";
document.getElementById("hidden_" + this.value).style.display = "block"
}
<form id="picker" method="post" action="">
Item 1: <input type="radio" name="group1" value="one" />
Item 2: <input type="radio" name="group1" value="two" />
Item 3: <input type="radio" name="group1" value="three" /><br />
<br />
<div id="hidden_elements">
<div class="hidden" id="hidden_one">Input 1: <input type="text" /></div>
<div class="hidden" id="hidden_two">Input 2: <input type="text" /></div>
<div class="hidden" id="hidden_three">Input 3: <input type="text" /><br /><br /></div>
</div>
<input type="submit" id="submitbutton" value="Send form" />

Interact with all forms of the page with a <button>

I have a <button type="reset">, used in a context menu which contains a lot of buttons and displays only the ones needed for each page.
My problem is that this button is supposed to reset all the forms of the page it is in, but it is in a lot of different pages. The only way I found is to pass the id of the form (which is the only way according to the doc) but every page is different so I can't use that method.
If anyone has a solution for this that would be awesome.
Using jquery you can select and reset all forms like this
$("button[type='reset']").click(function(){
$('form').each(function() { this.reset() });
});
This can be accomplished quite easily, but you would need to use javascript, either plain or with some kind of library, such as jQuery.
The plain javascript way
function reset() {
var elements = document.getElementsByTagName("form");
for (var i = 0; i < elements.length; i++) {
elements[i].reset();
}
}
the above will iterate through all forms of your page and reset them one-by-one.
Demo:
function reset() {
var elements = document.getElementsByTagName("form");
for (var i = 0; i < elements.length; i++) {
elements[i].reset();
}
}
<form>
Form 1
<input type="text" />
<input type="text" />
</form>
<form>
Form 2
<input type="text" />
<input type="text" />
</form>
<form>
Form 3
<input type="text" />
<input type="text" />
</form>
<button onClick="reset();">Reset</button>
The jQuery way
You can also use jQuery to do the same thing, much like #AaronUllal´s answer.
$("button[type='reset']").on('click', function() {
$('form').each(function() {
this.reset();
});
});
Demo:
$("button[type='reset']").on('click', function() {
$('form').each(function() {
this.reset();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form>
Form 1
<input type="text" />
<input type="text" />
</form>
<form>
Form 2
<input type="text" />
<input type="text" />
</form>
<form>
Form 3
<input type="text" />
<input type="text" />
</form>
<button type="reset">Reset</button>
If you can use jquery assign class to the forms that should be reset and select them by class.

How can I add a div around two elements yourself using JQuery? [duplicate]

How would I go about using wrap() to wrap multiple elements (with different classes) inside a <div>?
For example, on the form I'm working on there is a big list of checkbox inputs and labels in the form of:
<input>
<label>
<input>
<label>
etc
I'm wanting to wrap a <div> around the input and label, so the result would be:
<div>
<input>
<label>
</div>
<div>
<input>
<label>
</div>
Thanks!
You can use the .wrapAll() method.
$('form > input').each(function(){
$(this).next('label').andSelf().wrapAll('<div class="test"/>');
});
If your markup has always the exact same order, I'd prefer to use:
var $set = $('form').children();
for(var i=0, len = $set.length; i < len; i+=2){
$set.slice(i, i+2).wrapAll('<div class="test"/>');
}
Should be significant faster.
Ref.: .wrapAll(), .andSelf(), .slice()
$('input+label').each(function(){
$(this).prev().andSelf().wrapAll('<div>');
});​
If you have something like this:
<input id="input1">
<label id="label1">
<input id="input2">
<label id="label2">
Then you can use jQuery:
jQuery("#input1").next().andSelf().wrapAll('<div id="newDiv" />');
jQuery("#input2").next().andSelf().wrapAll('<div id="newDiv" />');
and get this:
<div id="newDiv">
<input id="input1">
<label id="label1">
</div>
<div id="newDiv">
<input id="input2">
<label id="label2">
</div>
Worked for me :-)
jQuery function wrapAll allows you to wrap multiple elements but if you have a DOM like you wrote then it won't work too well as you can't easily match a part of label and input with a selector. I suggest adding some classes to each part and then using wrapAll.
<input class="i1"/>
<label class="i1"/>
<input class="i2"/>
<label class="i2"/>
$('.i1').wrapAll('<div/>');
$('.i2').wrapAll('<div/>');
This will give you
<div>
<input class="i1"/>
<label class="i1"/>
</div>
<div>
<input class="i2"/>
<label class="i2"/>
<div>

JQuery Selector for multiple elements of one ancestor

I have a DOM structure similar to this:
<div id="ans1">
<input id="in1" />
<input id="in2" />
</div>
<div id="ans2">
<input id="in1" />
<input id="in2" />
</div>
How can I select some of the descendants of an ancestor?
Something like:
$("#ans1 #in1, #ans1 #in2")
If you replace your 'id's with classes (since ids should be unique), then,
<div id="ans1">
<input class="in1" />
<input class="in2" />
</div>
<div id="ans2">
<input class="in1" />
<input class="in2" />
</div>
Then, to select all the descendants of id=ans1 having class="in1", you go like,
$('#ans1 .in1')
This will return an array of all the .in1 class elements inside id=ans1 element
You can use the children function
$("#ans1").children("#in1, #in2")
You should use unique ids thought the DOM, use classes to specify elements that are the same in nature.
change your children to have same class of in1
$("#ans1 > .in1")
Will select all direct descendants of ans1 with class of in1.

Categories

Resources