For loop inside object javascript - javascript

I'm using lightGallery and I'm using dynamic creation of galleries, this is the code to generate just one image:
$(this).lightGallery({
dynamic:true,
dynamicEl: [{
'src':'css/images/pictures/gal_'+id+'/1.jpg',
'thumb':'css/images/thumbnails/gal_'+id+'/1.jpg'
}]
});
This id variable is always the same, but I want to loop through a number which I take for example from variable x. So, if x=4 the code generated would look like this:
$(this).lightGallery({
dynamic:true,
dynamicEl: [{
'src':'css/images/pictures/gal_'+id+'/1.jpg', //here's 1
'thumb':'css/images/thumbnails/gal_'+id+'/1.jpg'
},{
'src':'css/images/pictures/gal_'+id+'/2.jpg', //here's 2 and so on
'thumb':'css/images/thumbnails/gal_'+id+'/2.jpg'
},{
'src':'css/images/pictures/gal_'+id+'/3.jpg',
'thumb':'css/images/thumbnails/gal_'+id+'/3.jpg'
},{
'src':'css/images/pictures/gal_'+id+'/4.jpg',
'thumb':'css/images/thumbnails/gal_'+id+'/4.jpg'
}]
});
So I guess the question is how to include a for loop inside an object, if that's even possible, thanks in advance!

No. It's not possible to have control structures(like loops) inside an object definition. You need to create your array of images first, like this:
var dynamicEl = [];
for (var i = 1; i <= 4; i++) {
dynamicEl.push({
'src':'css/images/pictures/gal_' + id + '/'+ i + '.jpg',
'thumb':'css/images/thumbnails/gal_' + id + '/' + i + '.jpg'
});
}
And then to pass it onto the object definition:
$(this).lightGallery({
dynamic:true,
dynamicEl: dynamicEl
});

first create a method to dynamically generate thumbs
function genThumbs(count, id)
{
var arr = [];
for ( var counter = 1; counter <= count; counter++)
{
arr.push( {
'src':'css/images/pictures/gal_'+id+'/' + counter + '.jpg',
'thumb':'css/images/thumbnails/gal_'+id+'/' + counter + '.jpg'
} );
}
return arr;
}
then use the same while calling the gallery
$(this).lightGallery({
dynamic:true,
dynamicEl: genThumbs(5, id)
});

Try this
var genEls = function(id, count)
{
var els = [];
for(i = 1; i <= count; i++)
{
els.push({
'src':'css/images/pictures/gal_'+ id + '/' + i + '.jpg',
'thumb':'css/images/thumbnails/gal_' + id + '/' + i + '.jpg',
});
}
return els;
}
var id = 3;
var count = 4;
$(this).lightGallery({
dynamic:true,
dynamicEl: genEls(id,count);
});
This is as inline as it can get ;)
Hope this helps ...

Related

Trying to prevent duplicate random item in DIV

Can anyone help me with this? All I need to do is prevent a duplicate from showing. I am populating an array and randomly generating the recipes. When you refresh the page, sometimes the same item appears twice. I need to prevent this from happening. I included a Fiddle at the bottom thanks.
Below is my code:
var recipe_data = [
{
"id":"11",
"recipeName":"Hummus",
"recipeCategory":"4",
"recipeImageCategoryURL":"http://www.slurrpy.com/wp-content/uploads/2012/08/roasted-eggplant-hummus-800x500.jpg"
},
{
"id":"12",
"recipeName":"Antipasto",
"recipeCategory":"4",
"recipeImageCategoryURL":"http://static.menutabapp.com/img/cache/800x500/2012/10/23/7857b394d50293d29443dc09eac76b3d.jpeg"
},
{
"id":"10",
"recipeName":"Zucchini",
"recipeCategory":"4",
"recipeImageCategoryURL":"https://paleofood.io/wp-content/uploads/2016/05/garlic-shrimp-zucchini-noodle-main-800x500.jpg"
}
]
var categoryItems = [];
$.each(recipe_data, function(i, item){
if (item.recipeCategory == "4") { categoryItems.push(item); }
});
var similarRecipe = '';
var randomRecipe = {};
for(var i = 0; i < categoryItems.length; i ++) {
randomRecipe = categoryItems[Math.floor(Math.random()*categoryItems.length)];
categoryItems.length = 2;
similarRecipe = [ '<div class="col-md-6 col-sm-6 img-margin">' + ' <div class="addthis_inline_share_toolbox" data-url="' + randomRecipe.recipePageURL +'" data-title="' + randomRecipe.recipeName + '"></div>'
+ '' + '<img class="img-responsive" src="' + randomRecipe.recipeImageCategoryURL + '">' + ''
+ '' + '<h3 class="recipeSubCategoryImgCaption">' + randomRecipe.recipeName + '</h3>' + '' + '</div>' ];
$('#recipeSimilar').append(similarRecipe);
}
Here is a fiddle: https://jsfiddle.net/wn4fmm5r/
After picking a random item, just remove it from the array so it's not picked again:
var randomIndex = Math.floor(Math.random()*categoryItems.length);
randomRecipe = categoryItems[randomIndex];
categoryItems.splice(randomIndex, 1);
Updated fiddle: https://jsfiddle.net/bLpqvs4f
May store the last recipe id in local storage, to prevent of showing it again (i suppose refreshing means reloading the page?)?
var showed=localStorage.getItem("stored")||[];//get the recipes already showed
var id;
while(!id||showed.find(el=>el===id)){//retry until generated a new one
id=Math.floor(Math.random()*categoryItems.length);//generate new one
}
showed.push(id);
localStorage.setItem("stored",showed);//store again
randomRecipe = categoryItems[id];//your new & random recipe
Unlike the other answers, this also work with browser refreshes...
I suppose in this case you want to take n different items from recipe_data?
In this case you should write a specified function to get the items you want
function getRandomItems(noOfItems, source){
var samples = source.slice();
var results = [];
for(var i=0; i < noOfItems;i++){
results = results.concat(samples.splice(Math.floor(Math.random() * samples.length), 1));
}
return results;
}
Some things to note here is to use .slice() to shallow copy an array, instead of running a for loop to add items, and when you want to pull items from an array .splice() is the function to choose.
See demo: https://jsfiddle.net/wn4fmm5r/3/

Get the image filename by first characters using javascript

I have a folder with images that have long filenames, but they all have unique product ID numbers at the beginning
e.g. 1023-Very-Long-Image-Name.jpg.
What I'm trying to do is to get full image filename into my javascript, by just using this unique ID number.
e.g. I need to find an image with ID 1023, which is this one - 1023-Very-Long-Image-Name.jpg
All unique IDs stored in JSON database. So below is an example of my code:
$('.choose-range-cta').click(function () {
var rowID = $(this).attr("id");
var stylesTable = JSON.parse(stylesDB);
var styleHTML = "";
for (var i = 0; i < stylesTable.length; i++) {
if (stylesTable[i].collectionID == rowID) {
var blockTitle = stylesTable[i].styleName;
var blockPrice = stylesTable[i].fromPrice;
var blockSize = stylesTable[i].size;
var blockImageID = stylesTable[i].frontImageID;
styleHTML += "<div class=\"col-lg-4 style-block\"><span class=\"style-name\">" + blockTitle + "</span><span class=\"from-price\">from £" + blockPrice + "</span><span class=\"cta\">Select</span><div class=\"img-box\"><img src=\"" + ImagePath + blockImageID +"\"></div><span class=\"copy\">" + blockSize + "</span></div>";
}
}
$('#style-list').html(styleHTML);
});
Assuming your list is an array, use filter:
var imageArray = [
'1021-Don-Long-Image-Name.jpg',
'1022-Very-Long-Image-Name.jpg',
'1023-Dan-Long-Image-Name.jpg',
'1024-BobLong-Image-Name.jpg'
];
function getName(data, id) {
return data.filter(function (el) {
return el.substring(0, 4) === id;
})[0];
}
var name = getName(imageArray, '1023'); // 1023-Dan-Long-Image-Name.jpg
DEMO

Set interval in a nested loop

I have a nested loop in a function which takes a while to load on IE8 and results in an unresponsive page.
I have a loading bar which 'freezes' when the script is running.
How can I use setInterval() to stop processing JS after each iteration to make it appear the loading bar is still moving and make it appear that the page is responsive?
The function is:
function createDropDown() {
var target = $('#mainList');
for (var i = 0; i < info.books.length; i++) {
var gnrval = info.books[i].genre
var catval = info.books[i].category
for (var j = 0; j < info.books[i].publishers.length; j++) {
var pubval = info.books[i].publishers[j].publisher
if (typeof app.cache.pub[pubval] == 'undefined') {
app.cache.pub[pubval] = {
'ul': $('<li class="publisher" data-value="' + pubval + '">' + pubval + '<ul class="sub-menu" data-title="Publishers"></ul></li>').appendTo(target).children('ul'),
'aut': {}
};
}
var ulauthors = app.cache.pub[pubval].ul;
for (var k = 0; k < info.books[i].publishers[j].authors.length; k++) {
var autval = info.books[i].publishers[j].authors[k].name + ' (' + gnrval + ')'
var aut_val = info.books[i].publishers[j].authors[k].name
if (typeof app.cache.pub[pubval].aut[autval] == 'undefined') {
app.cache.pub[pubval].aut[autval] = $('<li class="author" data-value="' + autval + '">' + autval + '<ul class="sub-menu" data-title="Authors"></ul></li>').appendTo(ulauthors).children('ul')
}
var ulyears = app.cache.pub[pubval].aut[autval]
console.log(ulyears)
var gItems = []
for (var m = 0; m < info.books[i].publishers[j].authors[k].yearsPublished.length; m++) {
var yearval = info.books[i].publishers[j].authors[k].yearsPublished[m]
var year = ulyears.find('.year[data-value="' + yearval + '"]')
if (year.size() == 0) {
var id = ++count
gItems.push('<li class="year" data-value="' + yearval + '"><a id="selyear' + id + '" class="addone" data-id="' + id + '" data-year="' + yearval + '" data-pub="' + pubval + '" data-aut="' + aut_val + '" data-cat="' + catval + '" data-gnr="' + gnrval + '">' + yearval + '</a></li>')
}
}
ulyears.append(gItems.join(''))
};
};
};
I tried adding:
setTimeout(function () {
//last nested loop code here
timeout();
}, 1000);
But obviously it didn't work.
You should start by breaking this gigantic function down. Simple tip: Principle of single responsibility.
Nesting loops squares the number of operations done. I suggest simplifying your data so that it can be done in one loop or a series of loops, and not nested loops. This would mean unnesting the data or structuring it in a way that you can simply do one pass.
A caveat is that the data will multiply in size, so it's a tradeoff between payload size and processing performance. Here's an example, where a case of locating the "geo" book would take several searches on the first data structure, but would only be a simple filter on the second data structure.
// So you loop through the properties of books, then another loop through math
// then another loop through science, then you get your "geo". Loops: 3
{
books : {
math : ['algebra','trigo','solids'],
science : ['bio','geo','psycho']
}
}
// Here, var geoBook = array.filter(function(book){return book.topic === 'geo'})[0];
// Loops: 1 (filter is essentially a loop)
[
{
type : 'book',
subject : 'math',
topic : 'algebra'
},{
type : 'book',
subject : 'math',
topic : 'trigo'
},{
type : 'book',
subject : 'math',
topic : 'solids'
},{
type : 'book',
subject : 'science',
topic : 'bio'
},{
type : 'book',
subject : 'science',
topic : 'geo'
},{
type : 'book',
subject : 'science',
topic : 'psycho'
},
]
To avoid freezing the browser, you need to "defer" operations using timers. You can use setInterval with a counter instead of loops. Here's a simple example:
function each(array,iterator){
var i = 0, length = array.length;
var timer = setInterval(function(){
iterator.call(array,array[i]);
if(++i >= length) clearInterval(timer);
},1000);
}
each([1,2,3,...10000],function(n){
console.log(n);
})

Passing id of element but getting the element itself

Here is a sample of my problem and below is the same code
HTML
<button id='preview_btn'>Add</button>
<table id="point_tbl">
</table>
JavaScript
var pointList = [];
function deletePoint(id) {
console.log(id); // should be string but turns out to be the tr element
for (var i = 0; i < pointList.length; i++) {
if (pointList[i].id == id) {
pointList.splice(i, 1);
document.getElementById(id).remove();
document.getElementById(id + "item").remove();
}
}
}
function getTemplate(obj) {
var id = obj.id + "item";
var aa = obj.id;
var row = "<tr id = '" + id + "'><td>" + obj.sn + "</td><td>" + obj.x + "</td><td>" + obj.y + "</td><td>" + obj.tx + "</td><td>" + obj.ty + "</td><td>" + obj.lbl + "</td><td><button class='del_point' onclick = 'deletePoint("+id+");'>Delete</button></td></tr>";
return row;
}
document.getElementById("preview_btn").onclick = function(event) {
var id = getUniqueId();
var obj = {sn: pointList.length, x: 10, y: 10, tx: "0.5", ty: "0.5", lbl: "", id: id};
$('#point_tbl').append(getTemplate(obj));
pointList.push(obj);
}
function getUniqueId() {
if (!getUniqueId.idList) {
getUniqueId.idList = [];
}
var id = "uniqueID" + Math.round(Math.random() * 1000 + 1);
if (getUniqueId.idList.indexOf(id) != -1) {
return getUniqueId();
} else {
getUniqueId.idList.push(id);
}
return id;
}
When the Add button is clicked a new row is added with a button.
On this newly added button the deletePoint function is bind using the getTemplate function. The deletePoint function accepts the id of the row (tr) created by getTemplate function.
I am logging the the passed parameter in the deletePoint function. I was expecting this to be the id(basically a string) of the row but it turns out to be the whole tr element.
Not able to rectify the problem, please help.
What happens is that the generated code in the event handler is
deletePoint(someId)
instead of being
deletePoint("someId")
As most browsers create a variable in global scope for all elements having an id (the name of the variable being the id), you pass the element, not the string (in some browsers you would pass undefined).
Immediate fix : Change
onclick = 'deletePoint("+id+");'
to
onclick = 'deletePoint(\""+id+"\");'
Better : don't inline JS code in HTML to avoid those problems. For example give an id and data-attribute to your cell and later bind as you do with other elements.
You can change your delete function to fix problem
function deletePoint(id) {
id.remove();
}

concatenating strings in .each loop

This may be a dumb question but I can't seem to get it or find it anywhere.
I have a .each function that returns the id's of a bunch of divs on a page and then assigns them a number. I need them to be outputted in a specific format all as one string so I can pass them to a database and use them as "sort_order" values. (I split them through a sproc in my database).
Here is my code:
jQuery('#updateAllContentButton').click(function() {
var count = 1;
jQuery('.CommentaryItem').each(function() {
var id = GetID(jQuery(this));
var data_str = (id + ':' + count + '~');
console.log(data_str);
count++;
});
});
So that returns each data_str on a separate line but I need it to return it like this:
144:2~145:3~146:4~147:4~148:5 (so on)
Any help would be appreciated, thanks!
Use map and join :
jQuery('#updateAllContentButton').click(function() {
console.log(jQuery('.CommentaryItem').map(function(i) {
return GetID(jQuery(this)) + ':' + (i+1);
}).get().join('~'));
});
Note that you don't have to count yourself : Most jQuery iteration functions do it for you.
You can use an array for that. Like this...
jQuery('#updateAllContentButton').click(function() {
var count = 1;
var arr = [];
jQuery('.CommentaryItem').each(function() {
var id = GetID(jQuery(this));
var data_str = (id + ':' + count + '~');
arr.push(data_str);
//console.log(data_str);
count++;
});
console.log(arr.join());
});
try this:
jQuery('#updateAllContentButton').click(function() {
var count = 1;
var data_str = "";
jQuery('.CommentaryItem').each(function() {
var id = GetID(jQuery(this));
data_str += (id + ':' + count + '~');
console.log(data_str);
count++;
});
});
change
var data_str = (id + ':' + count + '~');
to
data_str+ = (id + ':' + count + '~');
full code
jQuery('#updateAllContentButton').click(function() {
var count = 1,
data_str;
jQuery('.CommentaryItem').each(function() {
var id = GetID(jQuery(this));
data_str += (id + ':' + count + '~');
console.log(data_str);
count++;
});
});

Categories

Resources