I wanna be able to select a specific set of child in which an attribute is defined.
But how to select childs which are first child of the root selector that having the attribute data-role
first-of-type selector doesn't work due to the type of the element.
Here we have a sample of the DOM.
<body>
<div data-role="ca:panel" title="foo">
<div data-role="ca:vbox" width="100%">
<div data-role="ca:form">
<div data-role="ca:formitem">
<div data-role="ca:hbox">
<input data-role="ca:textinput">
<div data-role="ca:menu"></div>
</div>
</div>
<div data-role="ca:formitem">
<input data-role="ca:passwordinput">
</div>
<div data-role="ca:formitem">
<select data-role="ca:combobox">
<option>[...]</option>
</select>
</div>
</div>
<table>
<tbody>
<tr>
<td>
<span data-role="ca:label"></span>
</td>
<td>
<button data-role="ca:button"></button>
</td>
<td>
<button data-role="ca:button"></button>
</td>
</tr>
</tbody>
</table>
</div>
</body>
My filter should select only
<div data-role="ca:form">
<span data-role="ca:label"></span>
<button data-role="ca:button"></button>
<button data-role="ca:button"></button>
It should work in any case, meanings, it shouldn't be linked to a specific structure of the dom and must use data-role as 'selector'.
I'm not a relevant jQuery developer. I tried some selector such as $('[data-role]:first-of-type'); but it doesn't work.
Do you have an idea to select the right set of child.
Note: Finding the first parent is not a concern.
It is possible to do this generically using a filter, so long as you have a start node:
JSFilter: http://jsfiddle.net/TrueBlueAussie/2uppww9s/5/
var root = $('[data-role="ca:vbox"]');
var matches = root.find('[data-role]').filter(function(){
return $(this).parentsUntil(root, '[data-role]').length == 0;
});
alert(matches.length);
You can use the :first pseudonym to select the first occurance of a element like for example:
var elm = $('*[data-role="ca:form"]:first');
this will select * any type of DOM-element, with the data-role that matches "ca:form"
Since you want to return two buttons with the same data-role, we cant use ":first" for that. You would have to get the first child of a that matches in that case
var elm = $('td').children('button[data-role="ca:button"]:first');
This will look through the child elements of all TD-tags and find the first button with data-role matching "ca:button"
If you want first of all overall specifications, then you can simply use selector on all three tag types and filter them as so:
$('div, span, button').filter(function(i){
if (this.tagName == 'DIV' && $(this).data('role') == 'ca:form') return true;
if (this.tagName == 'SPAN' && $(this).data('role') == 'ca:label') return true;
if (this.tagName == 'BUTTON' && $(this).data('role') == 'ca:button') return true;
}).first();
Using .first grabs the first of them.
Also, filter can be used in a million ways to get what you want and sounds like it may get you to what you need. Just set what you're filtering for in an if/for/switch statement and return true on items that match.
jsFiddle
However, if you wanted first of each you could do something like:
$('div[data-role="ca:form"]:first, span[data-role="ca:label"]:first, button[data-role="ca:button"]:first')
If variable driven in someway, just use string concatenation.
jsFiddle
Related
I'm trying to figure out a jquery selector where I can grab all DOM elements with name A, that ALSO have a grandparent with class X. Here's an example HTML, I will have many of these
<div class="interface_controlgroup">
<div class="form-switch me-3">
<input name="layout[]" type="checkbox" class="form-check-input">
</div>
</div>
<!-- note some inputs will have "d-none" on the grandparent -->
<div class="interface_controlgroup d-none">
<div class="form-switch me-3">
<input name="layout[]" type="checkbox" class="form-check-input">
</div>
</div>
...
<!-- repeated -->
Now I would like to select all inputs, as well as all inputs where the grandparent has d-none
let all_inputs = $('input[name=layout\\[\\]]');
//cannot use this because the entire section may be hidden when this is run
let hidden_inputs = $('input[name=layout\\[\\]]:hidden');
//I need something more like
let hidden_inputs = $('input[name=ide_layout_std\\[\\]]'.parent().parent()".d-none");
I am looking for a solution that allows me to only select when the parent's parent has a certain class, but I don't know how to create this match. I also can't rely on ":hidden" in the jquery selector because the entire section/page may be hidden when this javascript is running.
Using JQuery 3.6 and Bootstrap 5
You can use the x > y child selector to solve this. x > * > z matches z with a grandparent x (the parent in the middle can be anything).
let hidden_inputs = $('.d-none > * > input[name=ide_layout_std\\[\\]]:hidden');
I have a very large HTML that contains lots of divs with the same name, I want a way to only filter or extract that value from that div.
Here is an example:
<td class="last">
<div class="container-relative">
<div class="name" title=""User" <John Appleseed>"></div>
<div class="date">9/17/2019</div>
<div class="tool"></div>
</div>
</td>
I need to extract only what's between <John Appleseed>, in this case is 'John Appleseed'.
You could use querySelectorAll to take all the elements with class name, then get the title attribute with getAttribute, and finally use a regular expression to match text between <>.
document.querySelectorAll('.name').forEach(item => {
let title = item.getAttribute('title');
console.log(title.match(/\<.*\>/));
});
<td class="last">
<div class="container-relative">
<div class="name" title=""User" <John Appleseed>"></div>
<div class="date">9/17/2019</div>
<div class="tool"></div>
</div>
</td>
var divs=[];
for(i=0,j=0,obj=document.getElementsByClassName("name");i<obj.length;i++)
if(obj[i].title.includes("John Appleseed") &&
/* obj[i].title.split("\"")[2].trim()=="<John Appleseed>" && */
obj[i].tagName.toLowerCase()=="div"){
divs[j++]=obj[i];
}
console.log(divs);
separate your div using div ID. Then get your respective div using that value of ID. Then in javascript you can use getElementByID.
You can use Xpath,
.//div[contains(#class, 'Test')]
Then extract you required text from it.
I want to get leaf elements containing specific text, and I used :contains selector. However, this selector selects includes every parent nodes too. Here is my example.
<div id='parent1'>
<p id='target1'>Red balloon</p>
<div id='target2'>Blue balloon</div>
</div>
<div id='parent2'>
<span id='target3'>Brown balloon</span>
</div>
In this case, I just want to get elements containing text balloon. I expected to get 3 elements(target1, target2, target3) by $(":contains('balloon')"), but it returns every nodes including parent nodes of targets. (e.g. html, body, and every parent div)
How can I select only targets?
p.s Above HTML is only example. HTML can be vary, so the answer should be generic.
use indexOf("balloon") > -1 to find id the word balloon is found
var arr = $("div").children().map(function(){
if($(this).text().indexOf("balloon") > -1 )
return $(this).attr("id")
}).get();
console.log(arr)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='parent1'>
<p id='target1'>Red balloon</p>
<div id='target2'>Blue balloon</div>
</div>
<div id='parent2'>
<span id='target3'>Brown balloon</span>
</div>
The solution below, look for all elements containing the word and clone these elements, This way we can be sure only to get "correct" amount of elements
Just remove .length and you have access to the elements.
var s = $(":contains('balloon')").not("script").filter(function() {
return (
$(this).clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.filter(":contains('balloon')").length > 0)
}).length;
console.log(s)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='parent1'>
<p id='target1'>Red balloon</p>
<div id='target2'>Blue balloon</div>
</div>
<div id='parent2'>
<span id='target3'>Brown balloon</span>
</div>
In a div with two classes, the first inner div
<div class="datacheck">
<div class="classic_div_data customdataid_305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
I need to get a substring (here the number 305) from the second class(customdataid_305) of the first inner div. For this need to get the classes.
I wrote in jquery and succeed
var xyz= $($(".datacheck").find("div")[0]).attr("class").split(" ")[1]
from which I gets the class.
Is there any simpler approach for this.
I am searching for something like this $(element).class() probably returns an array of classes
There's nothing that gives you an array of classes, although the native DOM classList is close. But I don't think classList will make things much simpler.
I'd do this:
var xyz = $(".datacheck .classic_div_data").attr("class").match(/\bcustomdataid_(\d+)\b/);
xyz = xyz && xyz[1];
The regex extracts the numeric portion of the class, without being fragile (sensitive to whether the class is the first or second in the list of classes, for instance).
Example:
var xyz = $(".datacheck .classic_div_data").attr("class").match(/\bcustomdataid_(\d+)\b/);
xyz = xyz && xyz[1];
console.log("xyz = '" + xyz + "'");
<div class="datacheck">
<div class="classic_div_data customdataid_305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
If you can change the HTML, though, I wouldn't use a class for this at all, I'd us a data-* attribute instead:
<div class="classic_div_data" data-custom-id="305">
then
var xyz = $(".datacheck [data-custom-id]").attr("data-custom-id");
Example:
var xyz = $(".datacheck [data-custom-id]").attr("data-custom-id");
console.log("xyz = '" + xyz + "'");
<div class="datacheck">
<div class="classic_div_data" data-custom-id="305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
One of the major problems you have with your current design is that if the order of the classes changes, or someone adds another class, your logic breaks. You're also getting a DOMElement from a jQuery object which you turn back in to a jQuery object again.
It would be a much better approach to use data-* attributes to store your custom data, like this:
$('.classic_div_data').click(function() {
console.log($(this).data('customdataid'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="datacheck">
<div class="classic_div_data" data-customdataid="305">
some values come here
</div>
<div class="optiondiv"></div>
</div>
<div class="datacheck">
<div class="classic_div_data" data-customdataid="205">
some more values come here
</div>
<div class="optiondiv"></div>
</div>
You can get the nth class easily from the classList of element object,
var x = $(".datacheck").find("div").get(0);
var nthClass = x.classList[1]
var res = nthClass.replace("customdataid_", "");
console.log(res); //305
You can use regex in .match() to finding last digit in class.
var digit = $(".datacheck > :first").attr("class").match(/[\d]+$/g)[0];
console.log(digit);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="datacheck">
<div class="classic_div_data customdataid_305">some values come here</div>
<div class="optiondiv"></div>
</div>
I would like to select all elements with the attribute magic. But I do not like to get any children that does not have an attribute named magic.
Selected elements should not change their order according to the parent with attribute magic.
For instance,
I have an HTML like this:
<div magic="row">
<div magic="inputWrapper">
<input magic="input"></input>
<input magic="input"></input>
</div>
<div>
<div class="row">
<div>
<button magic="write">Write</button>
</div>
<div>
<button magic="delete">Delete</button>
</div>
<div>
<button magic="new">New</button>
</div>
</div>
</div>
</div>
What I want to obtain is this:
<div magic="row">
<div magic="inputWrapper">
<input magic="input"></input>
<input magic="input"></input>
</div>
<button magic="write">Write</button>
<button magic="delete">Delete</button>
<button magic="new">New</button>
</div>
Is this an easy task with selectors only or should I use loops etc. ?
I couldn't think of a way to do it with selectors. You could loop over every element, if it doesn't have the magic attribute, then just replace it with its child elements:
$('*').each(function(){
var $this = $(this);
if( typeof $this.attr('magic') === 'undefined' ){
$this.replaceWith( $this.find('*') );
}
});
Since it uses the everything selector (*), it would be good to provide a parent element. Also, using data attributes would be more semantic:
$('#parent').find('*').each(function(){
var $this = $(this);
if( !$this.data('magic') ){
$this.replaceWith( $this.find('*') );
}
});