Accessing jQuery IDs with for loop - javascript

I have a simple problem and hopefully a simple answer.
So, I have a JSON file which I'm utilizing that has a ton of data in it. I'm trying to make a slideshow with such data, which is built, but I'm having trouble appending the proper information to the slides without hard coding everything.
My idea is to use a for loop to target specific IDs (slides), but I can't for the life of me figure out how to target each item for the loop.
I was thinking something like this, which is not working at all lol.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script>
$(function() {
for (var i=0; i<10; i++) {
$('#slide(i)').append("<p>Hello World</p>");
}
})();
</script>
</head>
<body>
<div id="slide0"></div>
<div id="slide1"></div>
<div id="slide2"></div>
<div id="slide3"></div>
<div id="slide4"></div>
<div id="slide5"></div>
<div id="slide6"></div>
<div id="slide7"></div>
<div id="slide8"></div>
<div id="slide9"></div>
</body>
As far as actually targeting individual slides, any syntax I try I can't get it to go.
Any help is appreciated!

Use string concatenation
jQuery(function ($) {
for (var i = 0; i < 10; i++) {
//use string concatenation
$('#slide' + i).append("<p>Hello World</p>");
}
});//also there is no () here... it is not a IIFE... it is a callback registration which will be invoked by jQuery when dom ready is fired
Demo: Fiddle

Related

Can I select classes by order like this?

So I have this HTML here generated by Wordpress. I want to select the DIVs seperately using JS. Is this possible? Can I maybe select them by the order on which JS finds them in my HTML?
I tried if something like this would be possible (By adding an index number) but I believe that is used only for the LI element. But you get the idea. The end result is to add a different classname to each div object using .className
var koffie = document.getElementsByClassName("g-gridstatistic-item-text2")[0];
var brain = document.getElementsByClassName("g-gridstatistic-item-text2")[1];
var tevred = document.getElementsByClassName("g-gridstatistic-item-text2")[2];
console.log(koffie);
console.log(brain);
console.log(tevred);
<div class="g-gridstatistic-wrapper g-gridstatistic-3cols">
<div class="g-gridstatistic-item">
<div class="g-gridstatistic-item-wrapper">
<div class="g-gridstatistic-item-text1 odometer" data-odometer-value="4"></div>
<div class="g-gridstatistic-item-text2">Kopjes koffie per dag</div>
</div>
</div>
<div class="g-gridstatistic-item">
<div class="g-gridstatistic-item-wrapper">
<div class="g-gridstatistic-item-text1 odometer" data-odometer-value="14"></div>
<div class="g-gridstatistic-item-text2">Brainstormsessies per week</div>
</div>
</div>
<div class="g-gridstatistic-item">
<div class="g-gridstatistic-item-wrapper">
<div class="g-gridstatistic-item-text1 odometer" data-odometer-value="12"></div>
<div class="g-gridstatistic-item-text2">Tevreden klanten</div>
</div>
Your JavaScript code is looking for DOM elements before it checks whether the DOM has even loaded. Try wrapping it in an event listener, like so:
JS
document.addEventListener('DOMContentLoaded', function () {
var koffie = document.getElementsByClassName("g-gridstatistic-item-text2")[0];
var brain = document.getElementsByClassName("g-gridstatistic-item-text2")[1];
var tevred = document.getElementsByClassName("g-gridstatistic-item-text2")[2];
//console.log(koffie);
//console.log(brain);
//console.log(tevred);
/* to evidence that targeting works: */
brain.classList.add('addedClass');
});
CSS
.addedClass {
font-size:22px;
color:red;
}
Full demo here:
https://jsbin.com/saxizeyabo/edit?html,css,js,console,output
simply like this
var yourVariableName = document.getElementsByClassName("g-gridstatistic-item-text2");
console.log(youVariableName[0]);
console.log(youVariableName[1]);
and so on like an array
document.querySelectorAll('.g-gridstatistic-item-text2').item(0);
https://developer.mozilla.org/de/docs/Web/API/Document/querySelectorAll
This way, you can just use CSS-Selectors
The below code should work.
var classes = document.getElementsByClassName('g-gridstatistic-item-text2');
for(var i=0; i<=classes.length; i++) {
var appendClass = 'your_class_name'+i;
classes[i].classList.add(appendClass);
}

Searching items causes lags

I have following problem. Let's say I have DOM like this.
<div class="results">
<div class="result">
<div class="title">Aaa</div>
</div>
<div class="result filtered-out">
<div class="title">Aab</div>
</div>
<div class="result">
<div class="title">Aac</div>
</div>
<div class="result">
<div class="title">Aad</div>
</div>
<div class="result">
<div class="title">Aae</div>
</div>
</div>
and an input field like this
<input type="text" id="search">
And now I try to filter the results with a simple function defined by this
var searchBox = $(this);
searchBox.keyup(function(){
var searchBox = $(this);
var items = $(".results .result:not(.filtered-out)");
items.each(function(){
var title = $(this).find(".title").html();
if(title.toLowerCase().indexOf(searchBox.val().toLowerCase())!== -1)
$(this).show();
else
$(this).hide();
});
});
So the problem is that the list of results is quite long something between 100 and 200 elements and whenever I type something into the search input the code executes very long. Maybe around 2-3 seconds. Is there any other approach to solve this "lag"? Thank you for any advices!
EDIT Maybe something like delayed script execution or asynchronous script execution (like in ajax)?
It's generally not a good idea to use the DOM as a datasource, it's not meant for it and is therefore slow. Personally I would recommend using a small MVVM library or something similar so you don't have to manually manage the DOM yourself.
I've used Vue.js below, but you could just as well use any similar solution. Keeping your data in the code will allow you to operate on it a lot faster since you don't have to re-request it all the time and you avoid doing a lot of work for modifications. All operations below are done on 1000 objects:
var items = [];
for (var i = 0; i < 1000; i++) {
items.push({
title: 'Item #' + i
});
}
var v = new Vue({
el: '#list',
data: {
items: items,
input: ""
},
computed: {
filteredItems: function() {
var value = ("" || this.input).trim().toLowerCase();
if (!value.length) return this.items;
return this.items.filter(function(item) {
return item.title.toLowerCase().indexOf(value) !== -1;
});
}
}
});
ol {
list-style: none;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.16/vue.min.js"></script>
<div id="list">
<input placeholder="Search" v-model="input" />
<ol>
<li v-repeat="filteredItems">{{title}}</li>
</ol>
</div>
When searching the dom through many elements it is recommended to use javascript as opposed to jQuery if speed is what you are after. jQuery has it's purpose but for large amounts of dom searching using javascripts getElementById or querySelector / querySelectorAll is going to be much much faster. If you check this jsPerf example you can see that the jQuery selector operates roughly 94% slower than the comparable getElementById.
You should try using some logging to figure out which part is taking the longest. If you find that it's the items selector (with the psuedo-not), you could try to optimize that, however I don't see anything about the filtered-out class so I'm not sure exactly what that does.
Here's some simple optimizations though:
var searchBox = $(this);
searchBox.keyup(function(){
var $searchBox = $(this);
var searchBoxVal = $searchBox.val().toLowerCase();
var items = $(".results .result:not(.filtered-out)");
items.each(function(){
var $item = $(this);
var title = $item.find(".title").html();
if (title.toLowerCase().indexOf(searchBoxVal) !== -1)
$item.show();
else
$item.hide();
});
});
My guess the lag is because you are performing the search based on the DOM elements, and at the same time manipulating them with hiding/ showing.
I suppose the DOM is populated from some data source? If so it'll be better to perform the search/ filter from that data source, then use the filtered data set to populate the DOM again. (And even if you don't have the data source at first, you can build one by reading the original DOM)

loop the .append() with selector as variable

I am trying to loop the .append() function in order to change the selector each time with different value. But, I don't know the syntax for the selector in order to meet my target. So, how to change it? Thanks so much!
Ka Ho
<script type="text/javascript">
var a=3;
for (var i=0;i<a;i++) {
$i.append(i);
}
</script>
<div class="0"></div> // expected: display 0
<div class="1"></div> // expected: display 1
<div class="2"></div> // expected: display 2
You can also use a function as argument to append, might be cleaner and possibly faster in your case:
$('div').append(function() {
return this.className;
});
http://jsfiddle.net/sSVL8/
<script type="text/javascript">
var a=3;
for (var i=0;i<a;i++) {
$("."+i).append(i); //this is what you need
}
</script>
<div class="0"></div> // expected: display 0
<div class="1"></div> // expected: display 1
<div class="2"></div> // expected: display 2
First of all numeric class and ids are not supported that much as you think it is.
Update your HTML to something like this
<div class="box-0"></div>
<div class="box-1"></div>
<div class="box-2"></div>
Then you can use the script provided by deadlock in his answer.
var a=3;
for (var i=0;i<a;i++) {
$(".box-"+i).append(i); //this is what you need
}

How to implement multiple tinyscrollbars from a class?

I'm trying to implement multiple scrollbars with the plugin Tinyscrollabr.js
http://baijs.nl/tinyscrollbar/
To implement the scrollbars, i use a function scrollify like in this article :
http://www.eccesignum.org/blog/making-tinyscrollbarjs-easier-to-implement
HTML :
<ul id="myList">
<li id="scrollbar1" class="col">
<h2>Title 01</h2>
<div class="scrollBox"><!--Scrollable Content here--></div>
</li>
<li id="scrollbar2 class="col">
<h2>Title 02</h2>
<div class="scrollBox"><!--Scrollable Content here--></div>
</li>
<li id="scrollbar3 class="col">
<h2>Title 03</h2>
<div class="scrollBox"><!--Scrollable Content here--></div>
</li>
</ul>
Javascript :
function scrollify(element,options) { // '#element', {list:of,key:values}
var opt = options || {}
$(element).children().wrapAll('<div class="viewport"><div class="overview"></div></div>');
$(element).prepend('<div class="scrollbar"><div class="track"><div class="thumb"><div class="end"></div></div></div></div>');
$(element).tinyscrollbar(options);}
$scrollbar1 = $('#scrollbar1 .scrollBox') ;
$scrollbar2 = $('#scrollbar2 .scrollBox');
$scrollbar3 = $('#scrollbar3 .scrollBox');
$scrollbar4 = $('#scrollbar4 .scrollBox');
$(function() {
scrollify($scrollbar1);
scrollify($scrollbar2);
scrollify($scrollbar3);
scrollify($scrollbar4);
})
I would to make this more simple.
For example, i would to be able to make this :
$(function() {
scrollify('.scrollBox');
})
But tinyscrollbar need an id. With a class, it's load the first scrollbar and not the others. Firebug return this error message "f.obj[0] is undefined"
Sorry if my question is stupid, but how can I do for applying tinyscrollbar to a list of elements with a class ?
And then, after some actions how to update all this scrollbars with the function $allScrollbars.tinyscrollbar_update();
Thanks for help, I'm just beginning with javascript and i'm trying to learn.
I would count the number of elements with the class:
var scrollCount = $(".scrollbox").size();
Then use an iterating loop to call each of your IDs:
for (i=0; i<5; i++) {
scrollify($('#scrollbar' + i));
}
Also I would recommend using DIVs instead of the list setup you have, use the example from the link you shared as a starting point :)
Thanks KneeSkrap3r for your answer. It's a good solution to make this but i'm trying to do something in the case i' don't know the numbers of element to scroll.
I think I've found with something like this (it's a part from the first jquery plugin i'm trying to do ) where $el is all elemnts with the class"scrollbox".
$el.each(function(index)
{
var $scrolls = $(this);
function scrollify(element,options)
{ // '#element', {list:of,key:values}
var opt = options || {}
$(element).children().wrapAll('<div class="viewport"><div class="overview"></div></div>');
$(element).prepend('<div class="scrollbar"><div class="track"><div class="thumb"><div class="end"></div></div></div></div>');
$(element).tinyscrollbar(options);
}
scrollify($scrolls);
// Update heights
$(window).resize(function()
{ $scrolls.tinyscrollbar_update('relative');
});
})
Like this, it's seems to work but i don't know if i'm using good practice of javascript.
For the Html markup, I told the li elements for div, it's better for the semantic.
Thanks for tips ;-)

jQuery: Loop iterating through numbered classes?

I looked at the post jQuery: Loop iterating through numbered selectors? and it didn't solve my problem, and didn't look like it was truly an answer that works.
I have a list of <h3> tags that are titles to questions, and there are answers below in a <p>. I created classes for each Q & A like so:
<h3 class="sec1">Question:</h3><p class="view1">Answer...</p>
<h3 class="sec2">Question:</h3><p class="view2">Answer...</p>
<h3 class="sec3">Question:</h3><p class="view3">Answer...</p>
I used the following jQuery loop to reduce redundacy for my 21 questions.
$(document).ready(function () {
for (var i = 1; i < 21; i++) {
var link = ".sec" + i;
var content = ".view" + i;
$(link).click(function () {
$(content).toggle("fast");
});
}
});
But it isn't working for all Q & A sets, only the last one. i.e.: It works for the first set if I set the max value to 2 (only looping once). Please advise. Thanks
While I agree with #gaffleck that you should change your approach, I think it is worth while to explain how to fix the current approach.
The problem is that the click function does not get a copy of the content variable but instead has a reference to that same variable. At the end of the loop, the value is .view20. When any element is clicked it read that variable and gets back .view20.
The easiest way to solve this is to move the code into a separate function. The content variable within this function is a new variable for every call of the function.
function doIt(i){
var link = ".sec" + i;
var content = ".view" + i;
$(link).click(function () {
alert(content);
});
}
$(document).ready(function () {
for (var i = 1; i < 21; i++) {
doIt(i);
}
});
http://jsfiddle.net/TcaUg/2/
Notice in the fiddle, if you click on a question the alert has the proper number. Optionally, you could make the function inline, though I find the separate function in most cases to be a bit cleaner.
http://jsfiddle.net/TcaUg/1/
A much easier way to do this, would be this:
$(document).ready(function(){
$("h3").click(function(){
$(this).next("p").toggle("fast");
});
});
This is also safer in that you can add/remove questions and answers in the future and you won't have to update the function.
Wrap your questions in a more logical structure to create a proper scope for your questions-block:
<div id="questions">
<div class="question">
<h3 class="sec1">Question:</h3><p class="view1">Answer...</p>
</div>
<div class="question">
<h3 class="sec2">Question:</h3><p class="view2">Answer...</p>
</div>
<div class="question">
<h3 class="sec3">Question:</h3><p class="view3">Answer...</p>
</div>
</div>
Now iterate through it like this:
$(function() {
$('#questions .question h3').click(function(){
$(this).parent().find('.answer').toggle('fast');
});
});

Categories

Resources