That's is the html structure: (see also in jsfiddle here: http://jsfiddle.net/hQ5dZ/)
<div id="fields">
<div>
<input type="file" />
<input type="button" value="+add">
<div>
<div>
<input type="file" />
<input type="button" value="+add">
<div>
</div>
The second jQuery-statement below does not work, why?
$('#fields').children().hide();
$('#fields :first-child').show();
EDIT: Desired Behaviour -> First div-child (with its content) should appear
Your markup is invalid — you are not closing the <div> and <input> tags:
<div id="fields">
<div>
<input type="file" />
<input type="button" value="+add" />
</div>
<div>
<input type="file" />
<input type="button" value="+add" />
</div>
</div>
After changing the markup to a valid syntax, it's working - http://jsfiddle.net/teddyrised/nBbxY/
You were not closing the div elements, instead was creating new div child which was causing the #fields element to have only one child.
So $('#fields').children().hide() was hiding the child and then $('#fields > :first-child').show() was displaying it back.
<div id="fields">
<div> <!-- fc-1 -->
<input type="file" /> <!-- fc-2 -->
<input type="button" value="+add" />
</div> <!--not closed-->
<div>
<input type="file" /> <!-- fc-3 -->
<input type="button" value="+add" />
</div>
</div> <!--not closed-->
$('#fields').children().hide();
$('#fields > :first-child').show();
Demo: Fiddle
Also the second selector is updated because #fields :first-child will select all descendant elements of #fields which are the first child of its parent, in the above markup it will select all fields marked as fc-x
Besides closing the needed tags you can shorten you jQuery code like so, for example:
$('#fields').children().hide().eq(0).show();
Working example online: http://jsfiddle.net/nBbxY/1/
Related
I'm writing a Django form with an ImageField, which by default has a ClearableFileInput widget which inserts an additional checkbox to clear the file if one is already selected.
I'm implementing the form using Materialize (http://materializecss.com/forms.html), by which the file <input> is wrapped in a div with class "btn". In the case that a file is already uploaded, however, the additional 'clear' checkbox also appears inside the button, whereas I'd like to have it outside.
So far, I've tried calling wrapAll() on the selected elements and then following the approach described in jQuery move node out of its parent:
$("input[id*='-clear_id']").add("label[for*='-clear_id']").wrapAll("<div />").each(function() {
$(this).parent().after(this);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
<div class="row">
<div class="file-field input-field col s12">
<label class="active" for="id_headshot">Headshot</label>
<div class="btn">
<span>File</span>
Currently: IMG_3515.png
<input type="checkbox" name="headshot-clear" id="headshot-clear_id" />
<label for="headshot-clear_id">Clear</label><br />
Change:
<input type="file" name="headshot" id="id_headshot" />
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text">
</div>
</div>
</div>
However, what I'm getting is an empty div element after the parent, followed by the selected input and label elements:
How can I get the input and label to first get wrapped inside a div, and then have that div moved after its parent div?
Give the wrap a class so it's easier to handle, then use that new class as a selector with insertAfter() method.
Demo
$(":checkbox, :checkbox + label").wrapAll("<div class='wrap'></div>");
$('.wrap').insertAfter('.btn');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
<div class="row">
<div class="file-field input-field col s12">
<label class="active" for="id_headshot">Headshot</label>
<div class="btn">
<span>File</span>
Currently: IMG_3515.png
<input type="checkbox" name="headshot-clear" id="headshot-clear_id" />
<label for="headshot-clear_id">Clear</label><br />
Change:
<input type="file" name="headshot" id="id_headshot" />
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text">
</div>
</div>
</div>
Got a 3 selection radio button options and also a number field, in case somebody wants to select more than radio buttons can offer. And i'm trying to pass a radio button value to the number field when radio value is changed.
Here is my html code for it
<!-- this is main add to cart form -->
<form>
<!-- and this is secondary form for radio buttons, so, only one could be selected -->
<form class="quanform">
<div class="pricelinewrap">
<div class="priceline">
<div class="pricelinecellval">
<input type="radio" id="quanlineradio1" value="1" name="quanline" />
</div>
</div>
</div>
<div class="pricelinewrap">
<div class="priceline">
<div class="pricelinecellval">
<input type="radio" id="quanlineradio2" value="2" name="quanline" />
</div>
</div>
</div>
<div class="pricelinewrap">
<div class="priceline">
<div class="pricelinecellval">
<input type="radio" id="quanlineradio3" value="3" name="quanline" />
</div>
</div>
</div>
</form>
<div class="newquanfield tablecell almiddle">
<input type="number" min="1" size="2" class="quantity" name="quantity" id="quantity" value="2" />
</div>
</form>
And this is my jquery code for it
$("form.quanform .pricelinewrap .priceline .pricelinecellval input[type=radio]").each(function(){
$(this).click(function(){
var quanval = $(this).val();
$(this).parents().find(".newquanfield input[type=number]").val(quanval);
});
});
Nothing happens and there are no errors in the console
The problem lies purely in your selector:
$("form.quanform) won't work, as your <form class="quanform"> is wrapped inside another <form>, which is invalid markup; <form> cannot be nested inside another <form>.
Because the 'desired' markup is invalid, it actually never gets added to the DOM. You can confirm this by viewing the source yourself with CTRL + U - <form class="quanform"> doesn't exist. Thus, you cannot target it with jQuery.
You can validate your markup with the W3 Validation service to ensure that your HTML is indeed valid, ensuring that your jQuery selectors work the way you expect.
As for your current structure, you can omit the .quanform component, and simply use $("form .pricelinewrap .priceline .pricelinecellval input[type=radio]"), which will work based off of the outer <form> element (which does indeed exist in the DOM).
This can be seen working in the following example:
$("form .pricelinewrap .priceline .pricelinecellval input[type=radio]").each(function() {
$(this).click(function() {
var quanval = $(this).val();
$(this).parents().find(".newquanfield input[type=number]").val(quanval);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- this is main add to cart form -->
<form>
<!-- and this is secondary form for radio buttons, so, only one could be selected -->
<form class="quanform">
<div class="pricelinewrap">
<div class="priceline">
<div class="pricelinecellval">
<input type="radio" id="quanlineradio1" value="1" name="quanline" />
</div>
</div>
</div>
<div class="pricelinewrap">
<div class="priceline">
<div class="pricelinecellval">
<input type="radio" id="quanlineradio2" value="2" name="quanline" />
</div>
</div>
</div>
<div class="pricelinewrap">
<div class="priceline">
<div class="pricelinecellval">
<input type="radio" id="quanlineradio3" value="3" name="quanline" />
</div>
</div>
</div>
</form>
<div class="newquanfield tablecell almiddle">
<input type="number" min="1" size="2" class="quantity" name="quantity" id="quantity" value="2" />
</div>
</form>
Hope this helps! :)
What
I am trying to create a CSS selector which selects all children within a given parent; but excludes them as long as any element on the path has a certain class.
Context
I am creating some materialisation class in Javascript which replaces some elements into their material versions. This runs on a top-level app. Each user can create their own apps, and I want to be able to say that a certain group of elements should not go through this process.
Example
This should be selected:
<div>
<input />
</div>
This should not be selected:
<div class="no-material">
<input />
</div>
The main challenge is that this label can be at any place. Example:
<main>
<section class="no-material">
<form>
<fieldset>
<input />
</fieldset>
</form>
</section>
</main>
Or it could be:
<main>
<section>
<form class="no-material">
<fieldset>
<input />
</fieldset>
</form>
</section>
</main>
Already tested
I tried a few attempts. The best scenario was:
div:not(.no-material) > input:not(.no-material), div:not(.no-material) *:not(.no-material) input:not(.no-material)
However, it stills gives some false positives. I could get more accurate by adding a lot of levels like:
div:not(.no-material) > input:not(.no-material),
div:not(.no-material) > *:not(.no-material) > input:not(.no-material),
div:not(.no-material) > *:not(.no-material) > *:not(.no-material) > input:not(.no-material)
And like that for 20-50 levels (or more?), but that's not very smart.
Live version
You can test your selectors by editing cssSelector in Javascript.
let cssSelector = [
// Independent selectors
'div:not(.no-material) > input:not(.no-material)',
'div:not(.no-material) *:not(.no-material) input:not(.no-material)'
].join(',');
// This will get elements and run their names. We should get yes1-5, but not no1-5.
let inputs = document.querySelectorAll(cssSelector);
for (let input of inputs) console.log(input.getAttribute('name'));
<!-- Do not edit HTML, just the CSS selector -->
<main style="display: none;">
<!-- Not selectable -->
<div class="no-material">
<input name="no-1">
</div>
<div>
<input name="no-2" class="no-material">
</div>
<div>
<label class="no-material">
<input name="no-3">
</label>
</div>
<div>
<label class="no-material">
<span>
<input name="no-4">
</span>
</label>
</div>
<div>
<label>
<span class="no-material">
<input name="no-5">
</span>
</label>
</div>
<!-- Selectable -->
<div>
<input name="yes-1">
</div>
<div>
<input name="yes-2">
</div>
<div>
<label>
<input name="yes-3">
</label>
</div>
<div>
<label>
<span>
<input name="yes-4">
</span>
</label>
</div>
<div>
<label>
<span>
<input name="yes-5">
</span>
</label>
</div>
</main>
<!-- Do not edit HTML, just the CSS selector -->
Note: I already have thought of other ways of solving this like iterating all the children of an element called '.no-material' and add the class 'no-material' to all, but that is resource consuming and I want to solve this from a CSS selector standpoint if possible.
Thank you
Find all the elements (all), then the elements with no-material on the element or its parent (no), then remove those in the second from those in the first to find those that remain (yes).
const difference = (a, b) => a.filter(elt => b.indexOf(elt) === -1);
const all = document.querySelectorAll("input");
const no = document.querySelectorAll(".no-material input, input.no-material");
const yes = difference([...all], [...no]);
console.log(yes.map(elt => elt.name));
<main style="display: none;">
<!-- Not selectable -->
<div class="no-material">
<input name="no-1">
</div>
<div>
<input name="no-2" class="no-material">
</div>
<div>
<label class="no-material">
<input name="no-3">
</label>
</div>
<div>
<label class="no-material">
<span>
<input name="no-4">
</span>
</label>
</div>
<div>
<label>
<span class="no-material">
<input name="no-5">
</span>
</label>
</div>
<!-- Selectable -->
<div>
<input name="yes-1">
</div>
<div>
<input name="yes-2">
</div>
<div>
<label>
<input name="yes-3">
</label>
</div>
<div>
<label>
<span>
<input name="yes-4">
</span>
</label>
</div>
<div>
<label>
<span>
<input name="yes-5">
</span>
</label>
</div>
</main>
In modern browsers, you can use css variables.
Define it at root level, redefine it in your class:
:root {
--mycolor: lightblue;
}
.container {
--mycolor: lightgreen;
}
.test {
background-color: var(--mycolor);
}
<div class="test">BASE</div>
<div class="container">
<div class="test">BASE</div>
</div>
:not(.no-material, .no-material *)
This will select all elements except those that have the class "no-material" or are a children of an element that has the class "no-material"
The key is using a space instead of the > selector, see https://stackoverflow.com/a/2636396/10002734 for the differences between them.
If you want to only select the elements you have marked as "yes" in the example you could also combine this with the :empty pseudo-selector, like so:
:not(.no-material, .no-material *):empty
How can I get the input elements form a certain div inside a form , not from all divs?
I want to use JAVASCRIPT not JQUERY.
I tried to use like this discountForm.oldDivIdName.elements[i].value.length, but its not working.
UPDATE:
I have a form like this,
<form action="action.php" method="post">
<div id='div1'>
<input type="text" id="id[]" />
</div>
<div id='div2'>
<input type="text" id="id[]" />
</div>
<input type="submit" name="submit" />
</form>
Both text fields id are named the same and I want to get the value of the text field of div named div1 and not from div2, how can I do that.
Any help?
If the input elements have id's, you can do something like
var value = document.getElementById('div1').children[0].value;
where you have
<form action="action.php" method="post">
<div id="div1">
<input type="text" id="id" />
<input type="submit" name="submit" />
</div>
</form>
if we have div like this
<div id="1">
<input type="text" />
<div id="2"></div>
</div>
<div id="3">
<div id="4">
<input type="text" />
</div>
</div>
now if i want to jump from div of id=4 to input tag of <div id="1">
using parent child relationship how can i jump to that particular input tag.
Please help
Thanks..
$('#4').parent().prev().children('input:first')
Of course this assumes that div#1 is always the previous sibling of div#3, like you have in the example.
document.getElementById("4").childNodes[0].
Though if you are using jquery it would be something like:
$("#4").children(":input")
IDs can't start with a number, so I change your code to:
<div id="id1">
<input type="text" />
<div id="id2"></div>
</div>
<div id="id3">
<div id="id4">
<input type="text" />
</div>
</div>
So, that makes it:
$("#id4").parents("body").children("div:first").children("input")
Another, shorter version:
$("#id4").parents("body").find('input')
Or the fast way:
$("input:first")