jQuery/JS Output from array/loop - javascript

I have several links on a page, they are turned into an array with jQuery. Basically, when the user clicks "load more" on the page I would like to generate a <ul> with 4 images inside (or less if there aren't 4 remaining. I then need to shut the </ul>. I cannot figure out how I'd write this, does anyone know? Also, is this code ok or should it be tidied up somehow?
What I'd really like is a way to hide the 4 images while they load and then slide down the new <ul> but I don't know how as I don't know where I could write a callback function in there. Feel free to point me in the right direction if you know how!
My code so far;
var hrefs = jQuery.makeArray(jQuery('ul.js a'))
jQuery('#load_more').bind('click',function(){
jQuery('.img_gallery').append('<ul>')
for(var c = 0; c < 4; c++){
if((hrefs.length) > 0){
jQuery('<li>').append(jQuery('<img>', {src:hrefs[0]})).appendTo(jQuery('.img_gallery'))
hrefs.splice(0,1)
}
}
jQuery('.img_gallery').append('<ul>')
})
Thanks : )

Try this approach .. this is lot cleaner
var hrefs = jQuery.makeArray(jQuery('ul.js a'))
jQuery('#load_more').bind('click', function() {
var html = '<ul>'
for (var c = 0; c < 4; c++) {
if ((hrefs.length) > 0) {
html += '<li><img src="' + hrefs[0] + '" /></li>' ;
hrefs.splice(0,1);
}
}
html += '</ul>'
jQuery('.img_gallery').append(html )
})​

Your hrefs array contains DOM elements, not URLs. Try this instead:
var hrefs = jQuery.map(jQuery('ul.js a'), function(el,i) {
return $(el).attr('href');
});
Incidentally, you can optimize your for loop as follows:
for (var c = 0; c < 4; c++) {
if (hrefs.length) {
jQuery('<li>').append(jQuery('<img>', {
src: hrefs.shift() // removes and returns the first array element
})).appendTo(jQuery('.img_gallery'));
};
};​

When you use jQuery you are not appending html tags, you are appending html elements.
When you do $('.img_gallery').append('<ul>'), and then $('.img_gallery').append('<li>'), you end up with a structure like this:
<div class="img_gallery">
<ul></ul>
<li></li>
</div>
You do not have to worry about closing tags, just creating elements. jQuery "closes" all the tags for you in a sense. You need to append your li elements to the ul, not the .img_gallery. Just append to the last ul:
var hrefs = $.makeArray(jQuery('ul.js a'))
$('#load_more').bind('click',function(){
$('.img_gallery').append('<ul>');
for(var c = 0; c < 4; c++){
if((hrefs.length) > 0){
$('<li>').append($('<img>', {
src: $(hrefs[0]).attr('href'); // get the link reference from the element
})).appendTo($('.img_gallery ul').last()); // append to the last ul, not .img_gallery
hrefs.splice(0,1);
}
}
});
Or, you can keep your ul as a variable, add your li's and append the list after the loop:
var hrefs = $.makeArray(jQuery('ul.js a'))
$('#load_more').bind('click',function(){
var newul = $('<ul>'); // Makes an element, not a tag
for(var c = 0; c < 4; c++){
if((hrefs.length) > 0){
$('<li>').append($('<img>', {
src: $(hrefs[0]).attr('href'); // get the link reference from the element
})).appendTo(newul); // append to the ul you created
hrefs.splice(0,1);
}
}
$('.img_gallery').append(newul);
});

Related

Hide parent DIV when h4 contains certail text

What I'd like to do is try to hide the parent div of the following (it would be hiding the div class called "eB cer") if h4 includes the word "bulk."
<div class="eB cer">
<h4>Bulk Load Files to CERs</h4>
<div class="tooltip"><b>Description: </b>You will add files to your CERs using the Bulk Load and Attribute Update Utility.<span class="tooltiptext">In this module you will learn how to add files to your CERs in bulk and modify any attributes as needed.</span>
</div>
<p><b>Link: </b>Bulk Load Files to CERs</p>
</div>
I have this and it's hiding the h4, but not the entire div.
var searched_string = "eB cer";
var foundmatch = [];
for(i=0; i < leftFilteredArray.length; i++){
if(leftFilteredArray[i].match(searched_string)){
foundmatch.push(leftFilteredArray[i]);
$("div h4:contains('" + searched_string +"')").hide();
}
Any suggestions what I'm doing wrong?
You can use indexOf() which returns the first index at which the specified string is found. Else it returns -1.
if($('.eB.cer>h4').text().toLowerCase().indexOf('bulk')!==-1)
$('.eB.cer').hide()
To recreate your situation I ended up looking at the jQuery line. Then I plugged it into the rest of the code. Here is what I got working.
var searched_string = "Bulk";
var foundmatch = [];
for(i=0; i < leftFilteredArray.length; i++){
if(leftFilteredArray[i].match(searched_string)){
foundmatch.push(leftFilteredArray[i]);
$("div h4:contains('" + searched_string +"')").parent().hide();
}
}
This line sets the text to lower case for less issues.
var searched_string = "Bulk";
var foundmatch = [];
for(i=0; i < leftFilteredArray.length; i++){
if(leftFilteredArray[i].match(searched_string)){
foundmatch.push(leftFilteredArray[i]);
// $("div h4:contains('" + searched_string +"')").parent().hide();
if( $(".eB.cer h4").html().toLowerCase().indexOf(searched_string.toLowerCase()) > -1) {
$(".eB.cer").hide();
}
}
}

Add Different Data Attribute to Anchors

I'm attempting to add data-webpart attributes to all the anchors within a document, but populate their values with the data attributes of their containing divs.
However the code I wrote appears to be populating all of the anchors with only one of the data attributes (or rather, adding the first one to all, then adding the second).
Any help would be much appreciated!
HTML
<body>
<div data-webpart="form">
Test Link
Test Link
Test Link
</div>
<div data-webpart="icon-grid">
Test Link
Test Link
Test Link
</div>
</body>
JavaScript
// data attributer
var webParts = document.querySelectorAll("[data-webpart]");
var webPartAnchors = document.querySelectorAll("[data-webpart] > a");
function addDataAttr() {
var closestWebPartAttr;
for (i = 0; i < webPartAnchors.length; i++) {
for (e = 0; e < webParts.length; e++) {
closestWebPartAttr = webParts[e].getAttribute("data-webpart");
webPartAnchors[i].setAttribute("data-web-part", closestWebPartAttr);
}
}
}
window.onload = function() {
if (webParts !== null) { addDataAttr(); }
};
Your nested loops are copying the data attribute from every DIV to every anchor, because there's nothing that relates each anchor to just their parent. At the end they all have the last data attribute.
Since the anchors are direct children of the DIV, you don't need to use querySelectorAll() to get them, you can just use .children() within the loop.
function addDataAttr() {
for (var i = 0; i < webParts.length; i++) {
var webpart = webParts[i].dataset.webpart;
var children = webParts[i].children;
for (var j = 0; j < children.length; j++) {
children[j].dataset.webpart = webpart;
}
}
}

jQuery Clone several "li" and append at a specific position of ul (not its end)

am developping a dynamic pagination bar , where the "li" are cloned n times depending of a number received from an external webservice.
here is my pagination element:
<ul class="pagination">
<li class="pagePrevious" name="previous">
<span aria-hidden="true">«</span>
</li>
<li class="page" name="1">1</li>
<li class="pageNext" name="next">
<span aria-hidden="true">»</span>
</li>
</ul>
evidently you may note that my first Li and my last Li inside the Ul are the button next and previous which are not cloned and they are statically always present .
my cloning fonction consits of selecting the last-1 child of the li which is directly the second , and clone it with dynamic incremental id , and finally its inserts it in the ul.
my fonction :
createPagination: function (nb) {
var lastLI = $('.pagination li').last().prev();
var num = lastLI.attr('name');
for (var i = num; i <= nb ; i++) {
if (i != num) {
var cloned = lastLI.clone().attr('name', i);
$(cloned).find('a').text(i);
$('ul').append(cloned);
}
}
}
my problem is how to make it append the cloned li always before the last li of next button. ???
note that i mays not change the name of class attribute for other specifications
Any suggestions ??
Use .before() to put something immediately before another element.
createPagination: function (nb) {
var nextLI = $('pagination .pageNext');
var lastLI = nextLI.prev();
var num = lastLI.attr('name');
for (var i = num+1; i <= nb ; i++) {
var cloned = lastLI.clone().attr('name', i);
cloned.find('a').text(i);
nextLI.before(cloned);
}
}
BTW, you don't need to write $(cloned), since cloned is already a jQuery object. And if you start the for loop at num+1, you don't need to check if (i != num).
the solution is to use simlply the fonction insertBefore instead of append :
var lastLI = $('.pagination li').last().prev();
var nextLI= $('.pagination li').last();
var num = lastLI.attr('name');
for (var i = num; i <= nb ; i++) {
if (i != num) {
var clone = lastLI.clone().attr('name', i);
$(clone).find('a').text(i);
clone.insertBefore(nextLI);
clone.removeClass("is-active")
}
}

JavaScript: how to get img and div elements using getElementsByTagName

I have a tree structure as follows:
<ul id="theul275">
<li>
<div id="red"></div>
<img id="green" />
<script></script>
<div id="blue"></div>
</li>
</ul>
There are multiple UL's likes this on my page each with a different id. I am getting each UL by doing this:
var child = document.getElementById('theul' + id).getElementsByTagName('*');
the problem is, I only want to get the children of each ul which are either div's or img's.
Is there a way to get elements by multiple tag names?
I really appreciate any help because I am kind of new to JavaScript! Thanks!
Depending on what browsers you may to support, you could use the CSS selector interface.
document.getElementById('theul275').querySelectorAll('div, img');
Or use a library. There are plenty of options out there. I am familiar with two,
MooTools
$('theul275').getElements('div, img');
jQuery
$('#theul275').find('div, img');
Or get a reference to the li node, and loop through each node and check if the nodeName is DIV or IMG.
for (var i = 0, l = child.length; i < l; i++)
{
if (child[i].nodeName == 'DIV' || child[i].nodeName == 'IMG')
{
//...
}
}
You could use a iterative method for this.
var elemArray = document.getElementById('theul' + id).childNodes,
getChildByNodeName = function (elem, pattern) {
var childCollection = [],
re = new RegExp(pattern, 'g'),
getChild = function (elements) {
var childs = elements.childNodes,
i = 0;
if (childs) {
getChild(childs);
for (i = 0; i < childs.length; i += 1) {
if (childs[i].nodeName.match(pattern)) {
childCollection.push(childs[i]);
}
}
}
};
getChild(elem);
return childCollection;
}
var childs2 = getChildByNodeName(elemArray, '^(DIV|IMG)$'); // array of match elements
And just change the pattern ('^(DIV|IMG)$') to suite your needs.
If you can use jQuery, try
var child = $("#theul" + id).find("div,img");
Otherwise, see JavaScript NodeList.

Pure javascript way to update CSS class attribute from all list items?

I'd like to use Javascript (not jquery) to access all items in a <ul> list and remove the active class from everything except my chosen menu item.
Here is the list:
<ul id='flash-menu'>
<li id="menu1" class='something active'>item 1</li>
<li id="menu2" class='somethingelse'>item 2</li>
<li id="menu3" class='somethingelse'>item 3</li>
</ul>
This is my javascript:
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').childNodes;
for (var i=0 ; i<list_items.length ; i++){
list_items[i].className = list_items[i].className.replace('/\bactive\b/','');
}
document.getElementById(view_name).className += " active";
}
The last line of the Javascript (adding the active class) works, but I don't think I'm accessing the list items right to remove the classes from the other items. Any suggestions? - thanks!
First off, your regex is wrong:
list_items[i].className.replace(/\bactive\b/, '');
Note: No quotes on regex'es in JavaScript. A slighty altered, working version is available on JsFiddle.
Furthermore, I get a few instances of HTMLTextElements in list_items. They're breaking the loop (Fx3.6/Win7) when trying to access the non-existing className attribute. You can avoid this by either using:
var list_items = document.getElementById('flash-menu').getElementsByTagName('li');
// Selecting _all_ descendant <li> elements
or by checking for the existence of .className before read/write within the loop body (example). The latter is probably the cleanest choice since it still only affects direct children (you may have several levels of <ul>s in each <li>).
I.e.,
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').childNodes;
for (var i=0, j=list_items.length; i<j; i++){
var elm = list_items[i];
if (elm.className) {
elm.className = elm.className.replace(/\bactive\b/, '');
}
}
document.getElementById(view_name).className += ' active';
}
You can use javascript function getElementsByTagName:
var listitems = document.getElementsByTagName("li");
this would return an array of all the lists and can be iterated for each list element and processed as required.
You can try:
In the case that you can have more than ul, first you have to get all references to them and then process each ul:
var uls = document.getElementsByTagName("ul");
for (uli=0;uli<uls.length;uli++) {
ul = uls[uli];
if (ul.nodeName == "UL" && ul.className == "classname") {
processUL(ul);
}
}
An illustration of proccessUL can be:
function processUL(ul) {
if (!ul.childNodes || ul.childNodes.length == 0) return;
// Iterate LIs
for (var itemi=0;itemi<ul.childNodes.length;itemi++) {
var item = ul.childNodes[itemi];
if (item.nodeName == "LI") {
// Iterate things in this LI
in the case that you need it put your code here
.....
}
}
}
Of course you can also use: item.className = "classname"; if you dont need to iterate between childs of LI
document.getElementById('flash-menu').childNodes will also include white space nodes.
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').getElementsByTagName('li'), i;
for (i=0 ; i<list_items.length ; i++){
if (list_items[i].className.indexOf('active') > -1) {
list_items[i].className = list_items[i].className.replace(/\bactive\b/,'');
}
}
document.getElementById(view_name).className += " active";
}
i agree with jensgram,and you'd better code like this:
list_items[i].className.replace(/\bactive\b/g, '');
add the regex string a 'g'
g is for Global ,using ‘/g’ can replace all the same Which Match the regex ,but if you don't use '/g',you just replace the first string .
like this :
var test= "testeetest" ;
alert(test.replace(/e/,"")) ;//result
: tsteetest but using 'g' var
test= "testeetest" ;
alert(test.replace(/e/g,"")) ;//result
: tsttst
Have a look at this here: https://developer.mozilla.org/en-US/docs/Web/API/element.classList
It helped me a lot with finding class elements!
This is my solution, maybe not the best, but for my works fine.
window.addEventListener('load', iniciaEventos, false);
function iniciaEventos(e)
{
var menu = document.querySelectorAll('nav li');
for(var i = 0; i < menu.length; i++ )
{
menu[i].addEventListener('mousedown', clickMenu);
}
}
function clickMenu()
{
var menu = document.querySelectorAll('nav li');
for(var i = 0; i < menu.length; i++)
menu[i].classList.remove('active');
this.classList.add('active');
}

Categories

Resources