Selecting element to copy using jQuery Clone - javascript

I have a guide where each chapter is located in a separate LI of a UL. I am trying to use the jQuery Clone function to search through the parent UL that contains all of these 'chapter' LIs, and return those chapters that contain specific text.
Right now, I'm getting odd results, likely because it's copying elements at their smallest child, rather than just the entire div.
Also, each of these chapter LIs should only be returned once.
makeIntoSldieshowUL - UL that contains all 'chapters'
slideShowSlide - class name for each 'chapter'
searchResultsArea - Div in which to append 'chapters' that contain text
So far I have:
$("#makeIntoSlideshowUL").find(".slideShowSlide:contains('" + $(this).val() + "')").clone().appendTo("#searchResultsArea");
To give you an idea of the content I'm looking to clone, here is a brief sample
<ul id="makeIntoSlideshowUL">
<li class="slideShowSlide" id="0">
<div class="topicTitle">Cardholder responsibilities</div>
<p>Cardholders are responsible for ensuring proper use of the card. If your division or department has approved you for a Pro-Card, you must use the card responsibly in accordance with the following requirements:</p>
<ul>
<li>Purchase items for UCSC business use only</li>
<li>Never lend or share your Pro-Card</li>
<li>Purchase only allowable goods and services</li>
</ul>
</li>
<li class="slideShowSlide" id="1">
<div class="topicTitle"><strong>Restricted and Unallowable Pro-Card Purchases</strong></div>
<p>Some types of purchases are restricted are not allowed with the Pro-Card. Disputes with suppliers are initially handled by the Cardholder if, for example, they don't recognize a transaction on their statement, or the amount doesn't match their receipt. The Cardholder is responsible for contacting the supplier immediately to try to resolve the matter.</p>
</li>

Use jQuery's .children() method instead of .find() since it sounds like the .slideShowSlide elements are immediate children.
$("#makeIntoSlideshowUL").children(".slideShowSlide:contains('" + $(this).val() + "')").clone().appendTo("#searchResultsArea");
Or you could use the > child selector instead.
$("#makeIntoSlideshowUL > .slideShowSlide:contains('" + $(this).val() + "')").clone().appendTo("#searchResultsArea");
EDIT: At one point, you seem to refer to the chapters as divs. If they're a child of the <li> elements, you'll likely need something like:
$("#makeIntoSlideshowUL > li > .slideShowSlide:contains('"...

try using the has or contains selector
has will not change the current element on the jquery stack.
$("#makeIntoSlideshowUL")
.has(".slideShowSlide:contains('" + $(this).val() + "')")
.clone()
.appendTo("#searchResultsArea");

Related

Get inner HTML to id and tag

With the following TypeScript code
let inventory: HTMLElement = document.querySelector("dialog[type=inventory]");
I get the following HTML element
<dialog type="inventory">
<button type="button">Exit</button>
<ul>
<li id="Blue">
<name>Blue item</name>
<amount>2</amount>
</li>
<li id="Red">
<name>Red item</name>
<amount>1</amount>
</li>
</ul>
</dialog>
I am trying to get the inner HTML value for amount and a specific id. For example, id="Red" and its <amount> value.
How can this be done with JavaScript?
I tried as follows, but then I cannot select the id for which I want the amount
inventory: HTMLElement = document.querySelector("dialog[type=inventory] > ul > li > amount");
console.log(inventory.innerHTML); // Prints amount 2
I could imagine using querySelectorAll() and looping over the values, but there should be a better solution.
You can add the ID to your selector:
"dialog[type=inventory] > ul > li#Red > amount"
You could also simplify as you don't need all elements in the tree, just the ones that allow for selection.
"dialog[type=inventory] #Red amount"
By utilizing the querySelector method, you can target a specific li element with a specific id, and subsequently access the text within the amount element by using the textContent property.
example :
let inventory = document.querySelector("dialog[type=inventory]");
let element= inventory.querySelector("li#Red");
let amount = element.querySelector("amount").textContent;
As another answerer states, you can add the ID as a requirement when selecting the li element:
dialog[type=inventory] > ul > li#Red > amount
However, since you can only have one element with the same ID on the page at the same time, you can actually simplify this to just
li#Red > amount
This really feels like an XY problem though, where you're asking to do one thing, but really you only need to do this because of some greater overarching problem. Ideally you shouldn't be looking up the contents of your HTML tree to find values like this, because it's super fragile and unreliable (e.g. if you need to change the structure for styling reasons, etc, you now break all of this logic, and TypeScript won't be able to save / warn you about it at all).
A better approach would be to keep a copy of your data model in JavaScript, and then use that to generate the HTML.
It's also worth noting that neither <name> nor <amount> are valid tags in HTML5. You are allowed to create custom tags, but they must contain at least one - character in their names, e.g. <inventory-name> rather than <name>.
const amount = document.querySelector("dialog[type='inventory'] ul #Red amount").innerHTML;
console.log(amount); // Prints "1"

match elements by data attribute and id

I am looking for a way to compare elements using jQuery. Basically for every element with a certain data attribute, I want to "appendChild" another element that has a matching ID.
So in the following example, 'a' has a data attribute of data-dropdown="drop-delivery-options". The second element has an ID="drop-delivery-options", so they match. I can select elements with this ID but how do I select elements that match data-attributes/IDs?
So a function that would be like:
If elementA[data-attribute] = elementB[ID] {
(elementA).appendChild(elementB)
}
Add Option
<div id="drop-delivery-options" data-dropdown-content class="f-dropdown content table-options drop-delivery-options">
<ul>
<li>Add Deposit Account</li>
<li>Add Cash Pickup</li>
<li>Send to Card</li>
<li>Add Home Delivery</li>
</ul>
</div>
You can use the data-dropdown attribute to select the select element, then use appendTo() to append it to the a. Note though that given your example you will end up with nested a elements, which is invalid. You should look to change the parent a element to something else.
$('.button').click(function() {
$('#' + $(this).data('dropdown')).appendTo(this);
});
Working example

Obtaining Upper level li text

So I currently have a list like so on my page
<li class="head">
<b>Introduction</b>
<ul>
<li class="sub">somethingsomething</li>
</ul>
</li>
This list is being used with sortable, so the user can decide on the order, and I am passing this information to a grails controller for use in application logic. So, I am trying to read it in, and place the text contained in the "head" and "sub" classes in 2 different arrays. However, when I use a jquery selector to obtain the head elements, and obtain the text attribute of the element, it contains the inside list as well.
$('#divname').find("ul > li.head").each(function()
{
var current = $(this);
console.log(current.text());
});
results in Introductionsomethingsomething
Is there any way to only obtain the 'Introduction' text from the list, and ignore the text in the nested <ul> and <li.sub>? Due to it being nested, I am unable to figure out how to use jQuery's :not() selector
You can find the b tag using jquery tagname selector.Like this:
var current = $(this).find('b');
console.log(current.text());
Working Demo
May be this is solution:
<script>
$('#divname').find("ul > li.head").each(function()
{
var current = $(this).find("b");
console.log(current.text());
});
</script>

Table made from list (<ul>,<li>), how to select a row? (:nth-child())?

I made a table out of a simple list structure:
<html>
<body>
<ul id="Column:0">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
<ul id="Column:1">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
<ul id="Column:2">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
</body>
</html>
Now I want to add a simple .mouseover() to every row, for e.g. changing the color of a row, when hovered. And this is what I figured out, so far:
for (var i = 2; i <= _totalRows; i++) {
var row = $('#TimeTable ul li:nth-child(' + i + ')')
row.each(function() {
$(this).click(function(evt) {
var $target = $(evt.target);
console.log($target.nodeName)
if (evt.target.nodeName == 'DIV') {
console.log(evt.parent('li'));
}
}); //end $(this).click(fn)
}); // end each(fn)
}
I get a set of all <li> objects matching to :nth-child(i) where i is the rows number.
var row = $('#TimeTable ul li:nth-child(' + i + ')')
Now I just iter this set through to add a .click(fn) to every <li>.
This works fine. Every cell has it's .click(fn) attached to it.
But the following, what to do on a click, is where I'm stuck for several hours now:
var $target = $(evt.target);
console.log($target.nodeName)
if (evt.target.nodeName == 'DIV') {
console.log(evt.parent('li'));
}
I simply don't get it to run.
You can actually ignore this gibberish, as it's just the last of several things I already tried here.
What I'm trying to do is simply select every <li> with an id='Row:X' and manipulate its CSS. The best I yet had was, that I can click a cell, but no matter in what row this cell is, the last one gets colored. I remember having used i as the row-index, when that happened, so I might miss some understanding of event-handling here, too.
Use a class name for duplicate groups of elements not an ID. If you give row one a class of "Row1" the selector is simply:
$('.Row1')
Then:
$('#TimeTable li').removeClass('highlight');
$('.Row1').addClass('highlight');
If you just wish to change the color on mouseover:
$('#TimeTable ul li').mouseover(function(){
$(this).css('background','red');
});
$('#TimeTable ul li').mouseout(function(){
$(this).css('background','green');
});
Make your ID's like so: C1R1 (Column1Row1) and so on
JQuery read/google up "jquery each"
JQuery read/google up "jquery bind click"
JQuery read/google up "jquery attr" and "JQuery val()"
This will give you the knowledge to write your own and most importantly understand it better. You will want to achieve the following (your close but no for loop required):
A list which JQuery attaches a click event handler to each LI, and then when the click happens the ID can be retrieved.
PS. There's a time and place for tables, they 9/10 times nearly always better for displaying data than CSS is. If you have a complex multi column row and want fiexed hights and no JS to fix things or do anything smart you can have a table and css :Hover on TR for stying mouse over and out etc. Heights are also constant.
PS. PS. If your data is dynamic and coming from a database and the whole row is an ID from the database I tend to avoid using the html ID attribute for this and make my own. You can retrieve this via attr("myattribute");
NOTE ON CSS and IDS:
Standard practice for ID's are to be used once on a page.
Class for repeatable content
Good luck.

How would I prevent JQuery from selecting more than 1 level of children dom elements?

How would I only select Item A and Item B pragmatically while excluding the sub item?
<div id="nav">
<ul>
<li>
<p>Item A</p>
<ul>
<li>
<p>Sub Item A</p>
</li>
</ul>
</li>
<li>Item B</li>
</ul>
</div>
Well after a quick test run - this is my contribution to this issue
$("#nav p:first, #nav > ul > li:eq(1)");
You specified that you wanted only those two items and no sub items so this is what jQuery will capture :
[<p>​Item A​</p>​, <li>​Item B​</li>​]
You can easily separate selectors by placing a comma between them.
Now that you have seen my solution I would strongly suggest that you take Xenon06's advice...
Giving your markup classes really helps you to keep track of them. Especially with jQuery. The class attribute while IMO mostly used for styling is a perfectly valid selector to use and abuse in your jQuery code. That is of course if you actually have access to that HTML. If you don't kindly ignore my last paragraph :)
This will select any first level li's that have only text and no children and any children of a li that isnt a ul. Given this is not a good way to do it. You should really put classes on your stuff to start with. But if that's not an option this will get you there.
$($('#nav').children()).children().each(function(){
if($(this).text() !== "" && $(this).children().length === 0 ){
$(this).addClass("IwantThisElement");
}
});
$($($('#nav') .children()) .children()) .children(':not(ul)').each(function(){
if($(this).text() !== ""){
$(this).addClass("IwantThisElement");
}
});
$('.IwantThisElement').text('Assuming Control');
Well, if your structure was more consistent, you could use direct children selectors, ie:
$("#nav ul li > p")
However your Item B is not in a paragraph. Without defining more what you want, you'll need to put classes on the items you want and do
$("#nav .yourclass")

Categories