Accessing a specific li within a ul - javascript

After looking at past examples and source code I have made, I can't seem to work out accessing a specific <li><a>the value in this</a></li> based on a parameter sent in.
Mockup:
<ul class="selectBox-dropdown-menu selectBox-options size-dropdown mediumSelect footwear" style="top: 309px; left: 34px; display: none;">
<li class="" style="display: none;"><a rel=""></a></li>
<li class="size-not-in-stock"><a rel="3096786:6"> 6</a></li>
<li class="size-not-in-stock"><a rel="3096787:6.5"> 6.5</a></li>
<li class=""><a rel="3096788:7"> 7</a></li>
<li class="selectBox-selected"><a rel="3096789:7.5"> 7.5</a></li>
<li class=""><a rel="3096790:8"> 8</a></li>
<li class=""><a rel="3096791:8.5"> 8.5</a></li><li><a rel="3096792:9"> 9</a></li>
<li><a rel="3096793:9.5"> 9.5</a></li><li><a rel="3096794:10"> 10</a></li>
<li><a rel="3096795:10.5"> 10.5</a></li><li><a rel="3096796:11"> 11</a></li>
<li><a rel="3096797:11.5"> 11.5</a></li><li><a rel="3096798:12"> 12</a></li>
<li><a rel="3096799:12.5"> 12.5</a></li><li><a rel="3096800:13"> 13</a></li>
<li><a rel="3096801:14"> 14</a></li><li><a rel="3096802:15"> 15</a></li></ul>
</ul>
Here is what I am trying to get. Let us say that a user puts in a value of 7, well than it should find the corresponding <li><a></a></li> that contains the number 7 and click it.
My troubles are with finding that value inside this, I know I need to use find within the <ul> but what stumps me is based on a value.
UPDATE:
I just want to make clear that, this is something that is going to be an auto process so I am trying to make it so I don't have to do anything except load the page.

You need something like
var test = "the content to seek";
$('ul.footwear').find('a').filter(function(idx, el){
return $.trim($(this).text()) == $.trim(test);
}).closest('li').trigger('click')
Demo: Fiddle

There is no need to loop through and read the innerHTML of every element like all of the other solutions appear to be doing. You can just do it with a selector.
Since the rel attribute seems to have the data you are after at the end :size, you can use use :has() and ends with $= selectors to get the lis you are after.
var num = 7;
var elems = $(".footwear li:has(a[rel$=':" + num + "'])");
console.log(elems.length);
And if you want to click it, than you call .click() or .trigger("click")
function findAndClick (size) {
var elem = $(".footwear li:has(a[rel$=':" + size + "'])");
elem.trigger("click");
}
And to trigger it on the page load it would be something like
$(window).on("load", function() { findAndClick(7); } );
or document ready
$( function() { findAndClick(7); } );
Sad thing is, this solution appears to be great with a simple selector, but the performance can be subpar. If there is only going to be one element with the size, the best performance would be an each() loop and breaking out of it when you find the one element. No need to look at the other elements.
The best performing would be an each()
function findAndClick (size) {
var elem;
size = size.toString();
$('.footwear').find('a').each(function () {
if ($.trim($(this).text()) == size) { //compare the text
elem = $(this).parent(); //set the element that contains the link
return false; //exit each loop
}
});
if (elem) {
elem.trigger("click"); //fire click
}
}
For even better performance, eliminate the need to read the text of the element or use a ends with selector. Add a data attribute to the element.
<li data-size="7">
and than you would just use a selector
function findAndClick (size) {
$('.footwear li[data-size="' + size + '"]').trigger("click");
}

I would optimize this by making your structure better suited for these types of queries
<li id="10"><a rel="3096793:9.5"> 9.5</a></li><li><a rel="3096794:10"> 10</a></li>
Put an id on the li that corresponds to the value of the a tags.
Then you can do a simple $("#10") selector
While it's possible to make complex selectors based on filters etc, keep in mind that performance will not be great in general for non browser backed selectors (pseudo selectors)

Since you have an attribute rel that finish with the content, you can use this:
$('a[rel$="\:'+valueToMatch+'"]').parent()

Related

Adding a Space when using addClass and variables using jQuery

I have jQuery read some text then add a class based on the value of this text. (The text read is rendered by my CMS).
The HTML Looks like this:
<ul class="zoneSubscriptions">
<li>
<ul>
<li class="zoneName">Professional</li>
<li>Never</li>
</ul>
</li>
<li>
<ul>
<li class="zoneName">RTTM</li>
<li>Never</li>
</ul>
</li>
</ul>
I want to read the text of class="zoneName"and add a class based on this.
JS to do this:
$(function() {
var zone = $( ".zoneName" ).text();
$( "#zones" ).addClass( zone );
});
This works without issue, however, I need it to add two classes, Professional and RTTM. What it adds is ProfessionalRTTM.
My question is how would I add the classes while keeping a space between the words?
In other words it should render like this: class="Professional RTTM" not class="ProfessionalRTTM"
Note: In my example there are two "zoneName"s. There could be anywhere from 1 to 5 or more when used live.
Try iterating the tags:
var $zones = $("#zones");
$(".zoneName").each(function () {
$zones.addClass( $(this).text() );
});
Also possible (if you want to reuse the list of class names)
var classes = [];
$(".zoneName").each(function () {
classes.push($(this).text());
});
$("#zones").addClass(classes.join(" "));
You're calling .text() on multiple results which is joining them together.
Why not do something like this instead:
var zone = $( ".zoneName" ).each(function(){
$("#zones").addClass($(this).text());
});
Find all your .zoneNames and then call addClass for each one.
jsFiddle example
You need to iterate across the .zoneNames, otherwise your .text() will be a one undivided string (unless you have whitespace in there)
$(".zoneName").each(function() {
$("#zones").addClass($(this).text());
});
You can use the callback function of addClass(), and use map() to get an array of the text, then simply join with a space:
$('#zones').addClass(function() {
return $('.zoneName').map(function() {
return $(this).text();
}).get().join(' ');
});
Here's a fiddle

Is there a better way to map menu click events to it's corresponding code

Okay, basically when I click a menu option a corresponding html is loaded into the content block of the layout page after executing some other set of codes, Now I have mapped each menu options' click event to it's corresponding set of codes to execute as follows;
<li onclick="changeContentTo('home');">About Us</li>
<li onclick="changeContentTo('rules');">Rules</li>
The mapping is done using switch case
case "rules":
/* something here */
$c.load("actsAndRules.htm" ) ;
break;
case "home":
/* something else here*/
$c.load("content.htm" ) ;
break;
I was wondering is there any better/proper method to do this?
I don't want to bind click event to a selector say $('.myLink').click() for example and no HTML5 coding, event handling will be the same as above
Basically what I want is to strip that mapping as much as possible out of the code and place it in a seperate obj ( which maybe resides in a seperate JS file ) something that will imitate a table/reference for mapping i.e. if I were to change a mapping I will only have to update that make-believe table.
Define a dictionary?
var $map = {'rules': 'actsAndRules.html', 'home': 'content.html'};
Now, instead of switch you can directly
$c.load($map[$arg]);
Assuming $arg is your function argument name.
EDIT
To run code only if any of the switch cases were satisfied, you can do something like this:
var $flag = false;
// your switch
...
case default:
$flag = true;
break;
...
// after switch
if (!$flag) {
// common code.
}
Try it like,
HTML
<li onclick="changeContentTo('home','content.htm');">About Us</li>
<li onclick="changeContentTo('rules','actsAndRules.htm');">Rules</li>
<script>
function changeContentTo(type,page){
$elesToHide=something;// let $elesToHide and $c are pre defined
if(!$elesToHide.is(":visible"))
$elesToHide.slideDown()
$c.load(page) ;
}
</script>
Try
<li class="nav-item" data-location="content.htm">About Us</li>
<li class="nav-item" data-location="actsAndRules.htm">Rules</li>
Then
$(function(){
$('.nav-item').click(function(){
if(!$elesToHide.is(":visible")){
$elesToHide.slideDown();
}
$c.load($this.data('location') ) ;
})
})
if(!$elesToHide.is(":visible"))
$elesToHide.slideDown();
this part seems to always be the same.
Just put it before your switch part.
Then, it only boils down to distinguish the url. You could just pass that directly:
<li onclick="changeContentTo('content.htm');">About Us</li>
<li onclick="changeContentTo('actsAndRules.htm');">Rules</li>
$c.load(parameterOfFunction ) ;
<li clickable load-link="content.htm">About Us</li>
<li clickable load-link="actsAndRules.htm">Rules</li>
$(function(){
$('clickable').click(function(e){
e.preventDefault();
$c.load($this.data('location') ) ;
});
});
<li id="l1" class="menuItem" data-item="home.htm" ></li>
<li id="l2" class="menuItem" data-item="actsAndRules.htm" ></li>
<li id="l3" class="menuItem" data-item="content.htm" ></li>
$(document).ready(function(){
$('.menuItem').click(function(e){
$c.load($(this).attr('data-item'));
});
});
Edit:
The HTML5 "data-" attribute will not be a problem even if you are not using HTML5. In ASP.Net the attributes are passed as-is to the client. Just leave the value blank where you don't need processing.
If you don't want to bind click on li, then you can bind it on the parent using event-delegation:
<ul id="list">
<li.....
<li.....
</ul>
$(document).ready(function(){
$('#list').click(function(e){
var $elem = $(e.target);
var content = $elem.attr('data-item');
if ($.trim(content)) {
$c.load(content);
}
});
});
Binding click to a selector is preferable over specifying onclick inline with each element.
You can easily wrap that snippet into a function and store it separately in external js file to be called from here.

Jquery to copy first link to second ul and then change class of first link

Short question:
http://jsfiddle.net/wF4FH/2/
What I want is for Page1 to be right above Page2 and Page10 above Page 20 before I change the classes. This should work for any number of elements.
The code provided gives an "Uncaught TypeError: Object # has no method 'append' ".
Long question:
I'm having problem finding the correct way to insert an li element based on the first link. The problem is I cant use id's on my markup so I have to "walk through" each class and check for names. I might just make this a lot more complicated than it is because my first two solutions didn't work the way I thought they would.
html
<ul class="nav">
<li class="active">
Start
</li>
<li class="has-child">
page1
<ul class="">
<li>
page2
</li>
</ul>
</li>
<li class="has-child">
page10
<ul class="">
<li>
page20
</li>
<li>
page30
</li>
</ul>
</li>
javascript
//Copy first link to child ul li
var pageLinks = $("li.has-child > a:first-child");
if (pageLinks != null) {
//var dropdownMenus = $("li.dropdown > a:first-child");
for (var i = 0; i < pageLinks.length; i++) {
for (var x = 0; x < pageLinks.length; x++) {
if (pageLinks[i].innerHTML === pageLinks[x].innerHTML) {
pageLinks[x].childNodes.append(pageLinks[i]);
}
}
}
}
//Change css classes
$("li.has-child").attr('class', 'dropdown');
$(".dropdown ul").addClass("dropdown-menu");
$(".dropdown a").attr("href", "#").addClass("dropdown-toggle").attr('data-toggle', 'dropdown');
strong text
What I want is for Page1 to be right above Page2 and Page10 above Page 20 before I change the classes. This should work for any number of elements.
When they are copied to the inner ul I change the top level menu item to a different class to work as a clickable dropdown men item.
The code provided gives an "Uncaught TypeError: Object # has no method 'append' ".
It is the navigation of a cms I cant change the markup on.
try this:
$links = $('li.has-child').children('a:first-child');
if($links.length > 0){
$links.each(function(i,link){
$(link).next().prepend($('<li></li>').append($(link)))
})
}
http://jsfiddle.net/wF4FH/6/
You need .clone() method to copy elements..
UPDATED
$links = $('li.has-child').children('a:first-child');
if($links.length > 0){
$links.each(function(i,link){
$(link).next().prepend($('<li></li>').append($(link).clone()))
})
}
http://jsfiddle.net/wF4FH/7/
When you have a jQuery object and you access it by numeric index, you're left with an HTML element. So $('body')[0] == document.body. This means that when you access pageLinks[x], you're really getting a raw element. This means that you want pageLinks[x].appendChild(pageLinks[i]);, not pageLinks[x].childNodes.append(pageLinks[i]);

find an element by style with jquery

How could I find an element in an HTML document using it's style properties?
here is an example:
HTML:
<ul>
<li style='z-index=1;'>e1</li>
<div style='z-index=8;'>div</div>
<li style='z-index=2;'>e2</li>
<li style='z-index=3;'>e3</li>
<li style='z-index=4;'>e4</li>
<li style='z-index=5;'>e5</li>
<ul>
The question is how do i select, for example..: the element <li> with z-index=4.
and how to select all div's with z-index=8 ...
If the style is set inline, you can use an attribute selector:
$('li[style*="z-index:4"]') //returns any li's with z-index = 4
see here. The advantage to this method is that it is very fast.
If the style is set via a stylesheet, you can access it this way:
var elem;
var elems = $("li");
for(var i=0; i<elems.length; i++) {
if($(elems[i]).css('z-index') == '4') {
elem = elems[i]; //assign elem we found
break; //exit loop early
}
}
Note Webkit browsers, (Safari, Chrome, etc), will not return a z-index value unless it is positioned as well. See this example
Also, for loop is still faster than .filter()
There isn't a style selector (how would it work, the style is a combination of inherited and explicitly stated rules), but you can filter (demo):
var things = $("li").filter(function() {
return $(this).css('z-index') == '4';
});
Now if you are using z-index to attach a piece of data to an HTML element you might have more luck using data attributes (cleaner, and searchable by Sizzle). One interpretation might look like this: (demo)
<div data-id='8'>div</div>
<ul>
<li data-id='1'>e1</li>
<li data-id='2'>e2</li>
<li data-id='3'>e3</li>
<li data-id='4'>e4</li>
<li data-id='5'>e5</li>
<ul>
<script>
alert($('[data-id=4]').text())
alert($('[data-id=8]').text())
</script>

reorder list elements - jQuery? [duplicate]

This question already has answers here:
How may I sort a list alphabetically using jQuery?
(10 answers)
Closed 5 years ago.
Is it possible to reorder <li> elements with JavaScript or pure jQuery. So if I have a silly list like the following:
<ul>
<li>Foo</li>
<li>Bar</li>
<li>Cheese</li>
</ul>
How would I move the list elements around? Like put the list element with Cheese before the list element with Foo or move Foo to after Bar.
Is it possible? If so, how?
var ul = $("ul");
var li = ul.children("li");
li.detach().sort();
ul.append(li);
This is a simple example where <li> nodes are sorted by in some default order. I'm calling detach to avoid removing any data/events associated with the li nodes.
You can pass a function to sort, and use a custom comparator to do the sorting as well.
li.detach().sort(function(a, b) {
// use whatever comparison you want between DOM nodes a and b
});
If someone is looking to reorder elements by moving them up/down some list one step at a time...
//element to move
var $el = $(selector);
//move element down one step
if ($el.not(':last-child'))
$el.next().after($el);
//move element up one step
if ($el.not(':first-child'))
$el.prev().before($el);
//move element to top
$el.parent().prepend($el);
//move element to end
$el.parent().append($el);
One of my favorite things about jQuery is how easy it is to write tiny little add-ons so quickly.
Here, we've created a small add-on which takes an array of selectors, and uses it to order the children of the target elements.
// Create the add-on
$.fn.orderChildren = function(order) {
this.each(function() {
var el = $(this);
for(var i = order.length - 1; i >= 0; i--) {
el.prepend(el.children(order[i]));
}
});
return this;
};
// Call the add-on
$(".user").orderChildren([
".phone",
".email",
".website",
".name",
".address"
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="user">
<li class="name">Sandy</li>
<li class="phone">(234) 567-7890</li>
<li class="address">123 Hello World Street</li>
<li class="email">someone#email.com</li>
<li class="website">https://google.com</li>
</ul>
<ul class="user">
<li class="name">Jon</li>
<li class="phone">(574) 555-8777</li>
<li class="address">123 Foobar Street</li>
<li class="email">jon#email.com</li>
<li class="website">https://apple.com</li>
</ul>
<ul class="user">
<li class="name">Sarah</li>
<li class="phone">(432) 555-5477</li>
<li class="address">123 Javascript Street</li>
<li class="email">sarah#email.com</li>
<li class="website">https://microsoft.com</li>
</ul>
The function loops backwards through the array and uses .prepend so that any unselected elements are pushed to the end.
Here is a jQuery plugin to aid with this functionality: http://tinysort.sjeiti.com/
something like this?
​var li = $('ul li').map(function(){
return this;
})​.get();
$('ul').html(li.sort());
demo
I was somewhat lost you may be wanting something like this...
$('ul#list li:first').appendTo('ul#list'); // make the first to be last...
$('ul#list li:first').after('ul#list li:eq(1)'); // make first as 2nd...
$('ul#list li:contains(Foo)').appendTo('ul#list'); // make the li that has Foo to be last...
more of it here1 and here2
Have a look at jquery ui sortable
http://jqueryui.com/demos/sortable/

Categories

Resources