Dynamically generated lightslder and lightgallery - javascript

I have a news feed page where different posts show their images in a combination of lightslider and lightgallery. So far I have made it work for hardcoded posts, but failing to do the same for posts that are
dynamically generated.
Here is the code I'm using for combining lightgallery and lightslider
$('.lightSlider').each(function (index) {
$(this).lightSlider({
gallery: true,
item: 1,
loop: true,
slideMargin: 0,
thumbItem: 9,
onBeforeSlide: function (el) {
$('#counter' + index).text(el.getCurrentSlideCount());
},
onSliderLoad: function(el) {
el.lightGallery({
selector: '.lightgallery .lslide'
});
}
});
});
Here is the code I am playing with for combining lightslider and lightgallery in dynamically generated posts
HTML:
<button type="button" id="appendnewcontainer">Click me To create new slider</button>
<div id="fotoappendarea">
JavaScript:
$(document).ready(function(){
var imagesarray = [
"http://www.planwallpaper.com/static/images/Winter-Tiger-Wild-Cat-Images.jpg",
"http://www.gettyimages.ca/gi-resources/images/Homepage/Category-Creative/UK/UK_Creative_462809583.jpg",
"http://blog.jimdo.com/wp-content/uploads/2014/01/tree-247122.jpg",
"http://i765.photobucket.com/albums/xx291/just-meller/national%20geografic/Birds-national-geographic-6873734-1600-1200.jpg",
"http://www.gettyimages.com/gi-resources/images/CreativeImages/Hero-527920799.jpg"
];
var hiddenimages = "",
albumcover;
$("#appendnewcontainer").click(function() {
$("<span />", {
class : "container",
appendTo : $("#fotoappendarea"),
append : $("<span />", {
class : "imagecontiner",
html : "<a class='dfed' href=" + imagesarray[1] + "><img src='" + imagesarray[1] + "' class='_34'/></a>"
}).lightGallery()
});
});
});

Solved! Here is how I did it
HTML:
<button type="button" class="btn btn-danger" id="appendnewcontainer">Click me To create new slider</button>
<div id="fotoappendarea">
JavaScript:
$(document).ready(function(){
getPost(0);
var imagesarray = [
"https://www.elastic.co/assets/bltada7771f270d08f6/enhanced-buzz-1492-1379411828-15.jpg",
"https://images.pexels.com/photos/236047/pexels-photo-236047.jpeg?auto=compress&cs=tinysrgb&h=350"
];
var hiddenimages = "",
albumcover;
$("#appendnewcontainer").click(function() {
$("#fotoappendarea").append("<div class='lightgallery my-5'><ul class= 'lightSlider'><li data-thumb=" + imagesarray[0] + " data-src=" + imagesarray[0] + "><img src='" + imagesarray[0] + "' class='_34'/></li><li data-thumb=" + imagesarray[1] + " data-src=" + imagesarray[1] + "><img src='" + imagesarray[1] + "' class='_34'/></li></ul></div>");
$('.lightSlider:last').lightSlider({
gallery: true,
item: 1,
loop: true,
slideMargin: 0,
thumbItem: 9,
onBeforeSlide: function (el) {
$('#counter' + index).text(el.getCurrentSlideCount());
},
onSliderLoad: function(el) {
el.lightGallery({
selector: '.lightgallery .lslide'
});
}
});
});
})
Will add the jsfiddle later

Related

jQuery fresh ALL rows from PHP loop

Im not sure what is happening here, but I can not update this DIV per every row using this code. This code loads a initial user list, and loads the rest (after first 3) to a DIV dropdown triggered by click event.
<? foreach ($res as $row) { ?>
<script>
function fetchIndexUsers() {
$(function () {});
$.ajax({
url: '/ajax/ajax_live_index_users.php',
method: 'GET',
cache: false,
dataType: 'JSON',
data: {
item_id: <?=intval($row["item_id"])?>
},
success: function (data) {
var html_to_append = '';
array = [];
results = [];
$.each(data, function (i, item) {
results[i] = data[i];
array[0] = item.total;
array[1] = item.calc;
let icon = item.user.match(/(^|\W)yes($|\W)/i) ? 'arrow_upward' : 'arrow_downward';
html_to_append += '<div style="display:inline;float:left"><span class="material-icons" style="vertical-align:top;width:16px;padding-right:30px;color:#c0c0c0">' + icon + '</span></div><div style="display:inline;float:left;padding-bottom:1px"><a class="tooltip-newusers" title="' + item.username + '" href="/user/?id=' + item.user_id + '"><img style="box-shadow:2px 2px 10px #D3D3D3;height:35px;width:35px;border-radius:50%;margin-bottom:6px;margin-right:-20px;margin-top:-5px;vertical-align:middle;position:relative;z-index:10005;border:2px solid #FFF" src="/' + item.avatar + '" /></a></div><div style="clear:both"></div>';
return i <= 3;
});
if (array[0] >= 3) {
$("#live-peers-more-<?=intval($row["item_id"])?>").html('<div id="slidedown-<?=intval($row["item_id"])?>" style="user-select:none;margin-top:-14px;position:absolute;right:-20px;font-size:13px;background:purple;padding:0 6px;text-align:center;border-radius:3px;color:#FFF;font-weight:500;text-decoration:none;text-shadow:0 1px 1px rgba(0,0,0,.3);box-shadow:2px 2px 10px #D3D3D3"><a style="color:#fff;cursor:pointer">+ ' + (array.length - array[1]) + (array[1] >= 2 ? ' peers' : ' peer') + '</a></div>')
if (array[1] === 0) {
$("#live-users-more-<?=intval($row["item_id"])?>").hide();
}
}
$("#live-users-<?=intval($row["item_id"])?>").html(html_to_append);
$('.tooltip-newusers').tooltipster({
animation: 'grow',
delay: 200,
interactive: true,
theme: 'tooltipster-punk'
});
$("#live-peers-<?=intval($row["item_id"])?>").css('background', 'none');
$("#slidedown-<?=intval($row["item_id"])?>").html('<span><a style="color:#fff;cursor:pointer">+ ' + array[0] + (array[0] >= 2 ? ' peers' : ' peer') + '</a></span>');
}
});
$("#live-users-more-<?=intval($row["item_id"])?>").click(function () {
$("#slidedown-<?=intval($row["item_id"])?>").css('z-index', '9999999');
$.ajax({
url: '/ajax/ajax_live_index_users.php',
method: 'GET',
cache: false,
dataType: 'JSON',
data: {
item_id: <?=intval($row["item_id"])?>,
more: 1
},
success: function (data) {
var html_to_append = '';
$.each(results, function (i, item) {
html_to_append += '<div id="more_users" style="padding:6px;text-shadow:0 1px 1px rgba(0,0,0,.3)"><div id="peer-username">' + truncateString(item.username, 6) + '</div><a class="tooltip-newusers" title="' + item.username + '" href="/user/?id=' + item.user_id + '"><img style="height:35px;width:35px;border-radius:50%;border:2px solid #FFF" src="/' + item.avatar + '" /></a><div style="font-size:11px;font-weight:normal">' + formatBytesSpeed(item.totalspeed) + '</div></div>';
$("#slidedown-<?=intval($row["item_id"])?>").css('height', 'auto');
});
$("#slidedown-<?=intval($row["item_id"])?>").html(html_to_append);
$('.tooltip-newusers').tooltipster({
animation: 'grow',
delay: 200,
interactive: true,
theme: 'tooltipster-punk'
});
}
});
});
}
fetchIndexUsers();
setInterval(function () {
fetchIndexUsers()
}, 5000);
</script>
<div id="live-users-<?=intval($row["item_id"])?>" style="padding:10px;background:url(/images/loading-ellipsis.svg) no-repeat left">
<span style="padding-right:89px"></span>
</div>
<div id="live-users-more-<?=intval($row["item_id"])?>"></div>
<? } ?>
But any action coming back only updates the last row in from the array (PHP foreach array, with the JS emedded in the loop picking up on the ID from the iteration).
How come it only interacts with the last row? How can I update all rows since I am using a unique ID?
Thank you
You need to move the script out from the loop completely. Have ONE version of the script that delegates like this
$("#container").on("click", ".live-users-more",function () {
const item_id = $(this).prev().attr("id"); ....
and then change
<div id="live-users-more-<?=intval($row["item_id"])?>"></div>
to
<div class="live-users-more"></div>
where you have a
<div id="container"></div>
that wraps all the live user divs

Unable to access value i inside function onSelect of autoComplete. [Dynamically generate jquery]

Cannot get the value of i inside onSelect. Im calling the below jQuery function in a loop. I need the value of i to populate data in onSelect.
Is there a better way to generate jquery? Please help me on this.
for (i = count; i > 1; i--) {
jQuery(function ($) {
$(`input[name="company${i}"]`).autoComplete({
minChars: 1,
source: function (term, response) {
$.getJSON('https://autocomplete.clearbit.com/v1/companies/suggest', {
query: term
}, function (data) {
response(data);
});
},
renderItem: function (item, search) {
default_logo = 'https://s3.amazonaws.com/clearbit-blog/images/company_autocomplete_api/unknown.gif'
if (item.logo == null) {
logo = default_logo
} else {
logo = item.logo + '?size=25'
}
container = '<div class="autocomplete-suggestion" data-name="' + item.name + '" data-val="' + search + '">'
container += '<span class="icon"><img align="center" src="' + logo + '" onerror="this.src=\'' + default_logo + '\'"></span> '
container += item.name + '<span class="domain">' + item.domain + '</span></div>';
return container
},
onSelect: function (e, term, item) {
$(`input[name="company${i}"]`).val(item.data('name'))
},
});
});
}
You have several problems in this code:
jQuery(function ($) { will execute when all resources have been loaded, by that time the for loop has ended (because it's outside the ready function) and i will have its last value so it won't bind to all your elements. This function is acting as a closure, this is why you can't get the expected value in onSelect. Also, the loop will never get to 1, since the condition is i > 1 and it should be i > 0.
You can move the for inside the ready function and scope the element of the current iteration, but I'm choosing a jQuery approach here using .each.
jQuery(function($) {
$(`input[name^="company"]`).each(function() {
// This is what makes this work.
// If you use the 'for' you can set it to `input[name="company${i}"]`
let $input = $(this);
$input.autoComplete({
minChars: 1,
source: function(term, response) {
response([{
"name": "Amazon",
"domain": "amazon.com",
"logo": "https://logo.clearbit.com/amazon.com"
}, {
"name": "Amanda",
"domain": "iambaker.net",
"logo": "https://logo.clearbit.com/iambaker.net"
}]);
},
renderItem: function(item, search) {
default_logo = 'https://s3.amazonaws.com/clearbit-blog/images/company_autocomplete_api/unknown.gif'
if (item.logo == null) {
logo = default_logo
} else {
logo = item.logo + '?size=25'
}
container = '<div class="autocomplete-suggestion" data-name="' + item.name + '" data-val="' + search + '">'
container += '<span class="icon"><img align="center" src="' + logo + '" onerror="this.src=\'' + default_logo + '\'"></span> '
container += item.name + '<span class="domain">' + item.domain + '</span></div>';
return container
},
onSelect: function(e, term, item) {
// Reference the current input element
$input.val(item.data('name'))
},
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-autocomplete/1.0.7/jquery.auto-complete.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-autocomplete/1.0.7/jquery.auto-complete.min.css" />
<input name="company1" />
<input name="company2" />
You should use let keyword with 'i' because as you are not using any keyword 'i' would remain in the global scope and when this onSelect event would fire, it would pick the latest value of 'i' at the moment of event fire which in your case would be 1. So your code should be
for (let i = count; i > 1; i--){ // rest of the code reamins same }
Please read about
let, var and const
hosting

How to display charts in different modal windows after multiple ajax calls?

I do multiple ajax calls and I want to show a chart inside the modal window after clicking on symbol name. Right now I can see the chart only for the last symbol. For the first symbol the modal window is empty. I understand that with each ajax call the new chart function overrides the previous result and display new chart in last modal window. But how can I still show all previous charts and display new one in the lsat window?
var stocks = [];
window.onload = function() {
var symbols = ['AAPL', 'MSFT', 'FB'];
symbols.forEach( symbol => makeAjaxCall(symbol));
}
function makeAjaxCall(param){
$.ajax({
type: "GET",
url: "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=" + param + "&interval=1min&apikey=T6UEJETEQRVGDJS9",
success: function(result){
stocks = result;
getPrices();
}
});
}
function getPrices() {
var metaData = stocks["Meta Data"],
timeSeries = stocks["Time Series (1min)"],
sym = metaData["2. Symbol"];
var mdl1 = '<div id="chartModal" class="modal fade" role="dialog">' +
'<div class="modal-dialog modal-lg" role="content">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h4>',
mdl2 = '</h4>' +
'<button type="button1" class="close" data-dismiss="modal">×</button>' +
'</div>' +
'<div class="modal-body" id="modalBody">' +
'<div class = "container-canvas">' +
'<canvas class = "line-chart" width = "400" height = "250"></canvas>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>',
mdl3 = mdl1 + sym + mdl2;
document.getElementById("loadedStocks").innerHTML += '<div class="eachStock"><span><a onclick="showChart()">' + sym + '</a></span></div><div></div>' + mdl3;
var datasetsValues = Object.values(timeSeries),
datasetsValuesReverse = datasetsValues.reverse();
highPrice = Object.values(datasetsValuesReverse).map(o => o["4. close"]),
dateKeys = Object.keys(timeSeries),
datesReverse = dateKeys.reverse();
var ctx = document.getElementById('loadedStocks').querySelectorAll('.line-chart');
var last = ctx[ctx.length - 1];
new Chart(last, {
type: 'line',
data: {
labels: datesReverse,
datasets: [{
data: highPrice,
borderColor: "#FF4500",
label: "Close",
fillset: "#FFDAB9"
}],
pointStyle: "cross",
},
options: {
title: {
display: true,
text: "Stock's close price changes"
}
}
});
}
function showChart() {
$('#chartModal').modal();
}
My html:
<div id='loadedStocks'></div>
Thanks!
The main issue is that you gave the same ID to all your modals.
Below is a revision.
// better to use document.ready() than window.load()
// good idea to wrap jQuery-related code within document.ready()
$(function() {
// good idea to cache elements that you will re-use
var loadedStocks = $("#loadedStocks");
var API = 'https://www.alphavantage.co/query';
function makeAjaxCall(param) {
// simplified
$.getJSON(API, {
'function': 'TIME_SERIES_INTRADAY',
'symbol': param,
'interval': '1min',
'apikey': 'T6UEJETEQRVGDJS9',
}, getPrices);
}
function getPrices(stocks) {
var metaData = stocks["Meta Data"],
timeSeries = stocks["Time Series (1min)"],
symbol = metaData["2. Symbol"];
// give a unique id to each modal e.g. chartModal-AAPL
// in rare cases, use inline style to hide your HTML
var modal =
'<div id="chartModal-' + symbol + '" class="modal fade" role="dialog" style="display:none">' +
'<div class="modal-dialog modal-lg" role="content">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h4>' + symbol + '</h4>' +
'<button type="button1" class="close" data-dismiss="modal">×</button>' +
'</div>' +
'<div class="modal-body" id="modalBody">' +
'<div class="container-canvas">' +
'<canvas class="line-chart" width="400" height="250"></canvas>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
// use HTML5-data attribute to store the stock value (*)
loadedStocks.append('<div class="eachStock">' + symbol + '</div>' + modal);
var datasetsValues = Object.values(timeSeries),
datasetsValuesReverse = datasetsValues.reverse(),
highPrice = Object.values(datasetsValuesReverse).map(o => o["4. close"]),
dateKeys = Object.keys(timeSeries),
datesReverse = dateKeys.reverse();
var last = loadedStocks.find('.line-chart').last()[0]; // simplified
new Chart(last, {
type: 'line',
data: {
labels: datesReverse,
datasets: [{
data: highPrice,
borderColor: "#FF4500",
label: "Close",
fillset: "#FFDAB9"
}],
pointStyle: "cross",
},
options: {
title: {
display: true,
text: "Stock's close price changes"
}
}
});
}
// attach a click handler on the dynamically-created link
$(document).on('click', '.eachStock a[data-stock]', function showChart(e) {
e.preventDefault();
// find modal based on this link's stock value (*)
$('#chartModal-' + this.dataset.stock).modal('show');
});
// start!
['AAPL', 'MSFT', 'FB'].forEach(symbol => makeAjaxCall(symbol));
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
<div id="loadedStocks"></div>
(Give the demo a few seconds to load everything. You should probably change your API key afterwards.)
window.onload vs document.ready
jQuery shorthand methods
Event propogation
Data attributes

How to call multiple different AJAX calls to the same div in HTML

so I am reading data from a JSON file. Then I am successfully able to use AJAX calls to update the div in the HTML code. For example:
$("#carSize").append(carInfo[0].carSize);
The div carSize will get the data from the JSON file. However there is going to be 10 different cars with many different properties such as carSize. Since the carInfo array is big and full of several different properties, is there a way to simpler way of my achieving this without having to create a different div to append to for each car's property.
HTML:
<html>
<link href="json.css" rel="stylesheet" type="text/css">
<body>
<div class = "whiteBar">
<div id = "box1">
<div id = "carPrice"></div>
<div id = "carRate"></div>
SELECT
<div id = "total"></div>
</div>
<div id = "box2">
<div id = "carSize"></div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="my_script.js"></script>
</body>
</html>
JS
$(document).ready(function()
{
$.getScript("vehicle_data.json", function()
{
$("#carPrice").append(carInfo[0].carPrice + ".00");
$("#carRate").append(carInfo[0].carRate);
$("#total").append("Total: " + carInfo[0].carPrice * 7 + ".00 USD");
$("#carSize").append(carInfo[0].carSize);
});
});
JSON (sample)
var carInfo = [
{
carId: 1,
carPrice : 35.00,
carRate : 'USD/DAY',
carSize : 'Extra Small Car',
type : 'Economy',
},
{
carId: 2,
carPrice : 37.00,
carRate : 'USD/DAY',
carSize : 'Small Car',
type : 'Compact',
}
];
Note how the JS code is just for 1 car and I need it done for 9 other cars. Any ideas?
Could you do something like:
$(document).ready(function(){
$.getScript("vehicle_data.json", function() {
for(i=0; i<carInfo.length; i++){
var $carContainer = $('<div class="carContainer-'+i+'"></div>');
$carContainer.append('<div id="carPrice-'+i+'">'+carInfo[i].carPrice + ".00"+'</div>')
.append('<div id="carRate-'+i+'">'+carInfo[i].carRate+'</div>')
.append('<div id="total-'+i+'">'+"Total: " + carInfo[i].carPrice * 7 + ".00 USD"+'</div>')
.append('<div id="carSize-'+i+'">'+carInfo[i].carSize+'</div>');
$('body').append($carContainer);
}
});
});
Create a new div rather then appending it to existing html
Now that you've stored it in a variable, you can append anything you want to it
$.each(carInfo,function(i,car){
//create a new div to store car info
var myNewDiv = $('<div class="car-info"></div>');
// append car properties to the info div
myNewDiv.append(car.carSive);
myNewDiv.append(car.carId); //etc
// append the new div to existing html
$('.whiteBar').append(myNewDiv);
});
I am not quite sure if this fits what you need but I have had good luck with jsRender http://www.jsviews.com/ for situations like that.
Here is a generic solution if you get all of your cars in one go:
var carInfo = [
{
carId: 1,
carPrice : 35.00,
carRate : 'USD/DAY',
carSize : 'Extra Small Car',
type : 'Economy',
},
{
carId: 2,
carPrice : 37.00,
carRate : 'USD/DAY',
carSize : 'Small Car',
type : 'Compact',
}
];
function getCarHTML (car){
var carHtml = '<div class = "box1" class="car-' + car.carId + '" data-id="' + car.carId + '">' +
'<div id = "carPrice">' + car.carPrice + '</div>' +
'<div id = "carRate">' + car.carRate + '</div>' +
'SELECT' +
'<div id = "total">' + car.carPrice + '</div>' +
'</div>' +
'<div class = "box2">' +
'<div class = "carSize">' + car.carSize + '</div>' +
'</div>';
return carHtml;
};
//this is your ajax on success function
var showCars = function (cars) {
var $carContainer = $('#car-info-container');
cars.forEach(function(car) {
var carHTML = getCarHTML(car);
var $carIfPreset = $carContainer.find('.car-' + car.carId);
if ($carIfPreset.length) {
$carIfPreset.replaceWith(carHTML);
} else {
$carContainer.append(carHTML);
}
});
};
//calling function here, you should make this call inside your ajax
//Assuming ajax to return an array of cars
showCars(carInfo);
Here is a working jsfiddle: https://jsfiddle.net/fjh3mjtm/
Expected json here is {cars: [{carId: 1, carPrice: 35.00, ...}, {carId: 2, carPrice: 37.00, ...}, ...]}

Aftershow in fancybox jQuery

I had the same problem this person: ShareThis plugin not working in FancyBox title But now I have gotten it work, except the
afterShow: function(){
stButtons.locateElements();
}
Where in this code should I put it? I've tried many places, but it just says error. It say's I am placing it wrong. Where should I place it in the script below?
<script type="text/javascript">
$(document).ready(function(){
$(".fancybox").fancybox({
beforeShow: function() {
var caption = $(this.element).data("caption") ? $(this.element).data("caption") : "";
this.title = this.title ? this.title + buildShareThis(this.href) + caption : buildShareThis(this.href) + caption;
if (this.title) { ''
// New line
this.title += '<br />';
}
},
nextEffect : 'fade',
prevEffect : 'fade',
padding : 0,
margin : [15, 15, 50, 15],
afterLoad : addLinks,
beforeClose : removeLinks
});
function buildShareThis(url){
var customShareThis = "<div class='share'>"; // class for styling maybe
customShareThis += "<span class='st_facebook_hcount' displayText='Facebook' st_url='"+url+"'></span> ";
customShareThis += "<span class='st_twitter_hcount' displayText='Tweet' st_url='"+url+"'></span>";
customShareThis += "<span class='st_pinterest_hcount' displayText='Pinterest' st_url='"+url+"' st_img='"+url+"' ></span>";
customShareThis += "<span class='st_tumblr_hcount' displayText='Tumblr' st_url='"+url+"'></span>";
customShareThis += "</div>";
return customShareThis;
}
function addLinks() {
var list = $("#links");
if (!list.length) {
list = $('<ul id="links">');
for (var i = 0; i < this.group.length; i++) {
$('<li data-index="' + i + '"><label></label></li>').click(function() { $.fancybox.jumpto( $(this).data('index'));}).appendTo( list );
}
list.appendTo( 'body' );
}
list.find('li').removeClass('active').eq( this.index ).addClass('active');
}
function removeLinks() {
$("#links").remove();
}
});
</script>
You can set all fancybox API options, including fancybox callbacks (afterLoad, afterShow, beforeClose, etc.) like :
$(".fancybox").fancybox({
nextEffect: 'fade',
prevEffect: 'fade',
padding: 0,
margin: [15, 15, 50, 15],
afterLoad: addLinks,
afterShow: function () {
stButtons.locateElements();
},
beforeClose: removeLinks
});
Assuming you have properly defined your addLinks and removeLinks functions somewhere else in your script.

Categories