Javascript doesn't work on dynamic content - javascript

I'm trying to learn javascript and jquery lately so I'm not so good yet.
The page I'm currently struggling with is a news page. Basically news are article tags and are contained in two different main category divs.
<body>
<div class="a">
<article> ... </article>
<article> ... </article>
<article> ... </article>
...
</div>
<div class="b">
<article> ... </article>
<article> ... </article>
<article> ... </article>
...
</div>
</body>
In each article there's a slideshow with pictures and this is the code in JS:
//dots functionality
dots = document.getElementsByClassName('dot');
for (i = 0; i < dots.length; i++) {
dots[i].onclick = function() {
slides = this.parentNode.parentNode.getElementsByClassName("mySlides");
for (j = 0; j < this.parentNode.children.length; j++) {
this.parentNode.children[j].classList.remove('active');
slides[j].classList.remove('active-slide');
if (this.parentNode.children[j] == this) {
index = j;
}
}
this.classList.add('active');
slides[index].classList.add('active-slide');
}
}
//prev/next functionality
links = document.querySelectorAll('.slideshow-container a');
for (i = 0; i < links.length; i++) {
links[i].onclick = function() {
current = this.parentNode;
var slides = current.getElementsByClassName("mySlides");
var dots = current.getElementsByClassName("dot");
curr_slide = current.getElementsByClassName('active-slide')[0];
curr_dot = current.getElementsByClassName('active')[0];
curr_slide.classList.remove('active-slide');
curr_dot.classList.remove('active');
if (this.className == 'next') {
if (curr_slide.nextElementSibling.classList.contains('mySlides')) {
curr_slide.nextElementSibling.classList.add('active-slide');
curr_dot.nextElementSibling.classList.add('active');
} else {
slides[0].classList.add('active-slide');
dots[0].classList.add('active');
}
}
if (this.className == 'prev') {
if (curr_slide.previousElementSibling) {
curr_slide.previousElementSibling.classList.add('active-slide');
curr_dot.previousElementSibling.classList.add('active');
} else {
slides[slides.length - 1].classList.add('active-slide');
dots[slides.length - 1].classList.add('active');
}
}
}
}
It worked fine until I made the news data load on scroll with ajax. The JS code doesn't work anymore and I don't know how to fix it.
Here is the ajax code:
$(document).ready(function() {
function getDataFor(category) {
var flag = 0;
function getData() {
$.ajax({
type: 'GET',
url: 'get_data.php',
data: {
'offset': flag,
'limit': 3,
'cat': category
},
success: function(data) {
$('.' + category).append(data);
flag += 3;
}
});
}
getData();
var $window = $(window);
var $document = $(document);
$window.on('scroll', function() {
if ($window.scrollTop() >= $document.height() - $window.height()) {
getData();
}
});
}
getDataFor('a');
getDataFor('b');
});

Related

Issue with Load More button

I am having some issues with a custom slider on a WordPress website.
The slider works properly for some of the products, however, the same slider does not work on products which are loaded after a "Load More" button.
This is how the content is generated.
<div class="new_full_image-slider">
<div class="full_image-slider">
<div class="slider">
<div class="item_new_slide">
<?php the_post_thumbnail('medium_large') ?>
</div>
<?php foreach ( $attachment_ids as $attachment_id ) { ?>
<div class="item_new_slide" style="display:none;">
<img src="<?php echo wp_get_attachment_url( $attachment_id ); ?>" class="attachment-medium_large size-medium_large wp-post-image" alt="">
</div>
<?php } ?>
</div>
<div class="slider-dots">
<a class="prev">❮</a>
<span class="slider-dots_item"></span>
<?php foreach ( $attachment_ids as $attachment_id ) { ?>
<span class="slider-dots_item"></span>
<?php } ?>
<a class="next">❯</a>
</div>
</div>
</div>
The JavaScript which updates the classes and styles:
function custom_js_slider(slider) {
var slideIndex = 1;
var slides = slider.querySelectorAll('.item_new_slide');
var dots = slider.querySelectorAll('.slider-dots_item');
dots = Array.prototype.slice.call(dots);
var prev = slider.querySelector('.prev');
var next = slider.querySelector('.next');
var track = slider.querySelector('.slider');
function showSlides(n) {
slideIndex = n;
if (n > slides.length) {
slideIndex = 1
}
if (n < 1) {
slideIndex = slides.length
}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex - 1].style.display = "block";
dots[slideIndex - 1].className += " active";
}
showSlides(slideIndex);
prev.addEventListener('click', function(event) {
showSlides(slideIndex - 1);
});
next.addEventListener('click', function(event) {
showSlides(slideIndex + 1);
});
for(var i = 0; i<dots.length; i++) {
var this_i = dots.indexOf(dots[i]);
dots[i].addEventListener('click', function(event) {
var newIndex = dots.indexOf(event.target);
newIndex++;
showSlides(newIndex);
});
}
var threshold = 50;
var startX;
var swipedir;
track.addEventListener('touchstart', function(e){
var touchobj = e.changedTouches[0];
swipedir = 'none';
startX = touchobj.pageX;
//e.preventDefault();
}, false);
track.addEventListener('touchmove', function(e){
//e.preventDefault();
}, false);
track.addEventListener('touchend', function(e){
var touchobj = e.changedTouches[0];
distX = touchobj.pageX - startX;
if (Math.abs(distX) >= threshold){
swipedir = (distX < 0)? 'left' : 'right';
}
if (swipedir=='right') {
showSlides(slideIndex-1);
} else if (swipedir=='left') {
showSlides(slideIndex+1);
}
//e.preventDefault();
}, false);
}
var sliders = document.getElementsByClassName("full_image-slider");
Array.prototype.forEach.call(sliders, function(slider) {
custom_js_slider(slider);
});
And the "Load More" function:
jQuery(function ($) {
if ($('.post-listing').length > 0) {
//$('.post-listing').append('<span class="load-more"></span>');
var button = $('.post-listing .load-more');
var loading = false;
var count = $('.post-listing').data('count');
var full_count = $('.post-listing').data('full_count');
var cat_id = $('.post-listing').data('cat_id');
var cat_name = $('.post-listing').data('cat_name');
var term_link = $('.post-listing').data('term_link');
var type = $('.post-listing').data('type');
var ajax_append = $('.post-listing .ajax_append');
var scrollHandling = {
allow: true,
reallow: function () {
scrollHandling.allow = true;
},
delay: 400 //(milliseconds) adjust to the highest acceptable value
};
$('.load-more').click(function () {
loading = true;
var data = {
action: 'be_ajax_load_more',
count: count,
cat_id: cat_id,
cat_name: cat_name,
term_link: term_link,
type: type,
};
$.post(beloadmore.url, data, function (res) {
if (res.success) {
$('.ajax_append').append(res.data.objects);
loading = false;
button.removeClass('load_style');
count = count + res.data.count;
$('.post-listing').data('count', count);
if (count >= full_count) {
button.remove();
loading = true;
}
} else {
// console.log(res);
}
}).fail(function (xhr, textStatus, e) {
// console.log(xhr.responseText);
});
});
}
Could you have a look and point me to the right direction, please.
Thanks in advance.

jQuery lazy-loading image and video not working

I'm trying to lazy-load an image & video file with jQuery, following the example from the URL below:
https://varvy.com/pagespeed/defer-videos.html
https://varvy.com/pagespeed/defer-images.html
The problem is that my paginated data loaded onScroll by jQuery, but all of my image and video wasn't loaded. How can I solve this?
[ Pagination ]
$(window).on('scroll', function () {
if ($(window).scrollTop() + $(window).height() == $(document).height()) {
page += 1;
if (page <= maxPages) {
$.ajax({
beforeSend: function () {
$('.loader').html('Loading....');
},
type: 'GET',
url: 'blog/postloader?page=' + page,
data: { 'page': page },
cache: false,
success: function (data) {
$('.loader').html('Load More...');
$('.blogItems').append(data);
}
});
}
else { $('.loader').html('No More Post Available'); }
}
[ Lazy Loader function ]
function delayImg() {
var imgDefer = document.getElementsByTagName('img');
for (var i = 0; i < imgDefer.length; i++) {
if (imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src', imgDefer[i].getAttribute('data-src'));
}
}
}
//window.onload = delayImg;
// Lazy Load Video
function delayVid() {
var vidDefer = document.getElementsByTagName('iframe');
for (var i = 0; i < vidDefer.length; i++) {
if (vidDefer[i].getAttribute('data-src')) {
vidDefer[i].setAttribute('src', vidDefer[i].getAttribute('data-src'));
}
}
}
//window.onload = delayVid;
function start() {
delayImg();
delayVid();
}
window.onload = start;
you can combine the function with jQuery
function delayMedia() {
$('img, iframe').each(function() {
if (!$(this).attr('src')) { // set only if src is empty
var dataSrc = $(this).data('src');
if (dataSrc)
this.src = dataSrc;
}
});
}
call it on page load and after Ajax
$('.blogItems').append(data);
delayMedia();
And your function are not "really" lazy load, usually it appear after element position reached not on page load
function isVisible(el) {
var rect = el.getBoundingClientRect(),
elemTop = rect.top,
elemBottom = rect.bottom;
return (elemTop >= 0) && (elemBottom <= window.innerHeight);
}
function delayMedia() {
$('img, iframe').each(function() {
if (!$(this).attr('src')) { // set only if src is empty
var dataSrc = $(this).data('src');
if (dataSrc && isVisible(this)){
console.log(dataSrc)
this.src = dataSrc;
}
}
});
}
$(window).on('scroll', function() {
delayMedia();
});
.dh {
height: 300px;
display: block
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p class="dh">scroll</p>
<img src="" data-src="https://www.planwallpaper.com/static/images/1712173free-wallpaper.jpg" />
<p class="dh">scroll</p>
<img src="" data-src="https://www.planwallpaper.com/static/images/3d_falling_leaves.jpg" />
<p class="dh">scroll</p>
<img src="" data-src="https://www.planwallpaper.com/static/images/free-wallpapers-640x400.jpg" />

Jquery tab is not working

I have one problem with click function. I have created this demo from jsfiddle.net.
In this demo you can see there are smile buttons. When you click those buttons then a tab will be opening on that time. If you click the red button from tab area then the tab is not working there are something went wrong.
Anyone can help me here what is the problem and what is the solution?
The tab is normalize like this working demo
var response = '<div class="icon_b">
<div class="clickficon"></div>
<div class="emicon-menu MaterialTabs">
<ul>
<li class="tab active"> TAB1</li>
<li class="tab"> TAB2</li>
<li class="tab"> TAB3<span></span></li>
</ul>
<div class="panels">
<div id="starks-panel1" class="panel pactive"> a </div>
<div id="lannisters-panel1" class="panel"> b </div>
<div id="targaryens-panel1" class="panel"> c </div>
</div>
</div>
</div>';
$(document).ready(function () {
function showProfileTooltip(e, id) {
//send id & get info from get_profile.php
$.ajax({
url: '/echo/html/',
data: {
html: response,
delay: 0
},
method: 'post',
success: function (returnHtml) {
e.find('.user-container').html(returnHtml).promise().done(function () {
$('.emoticon').addClass('eactive');
});
}
});
}
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
$(this).on( "click", function() {
$(this).find('.user-container').html("");
});
var componentHandler = function() {
'use strict';
var registeredComponents_ = [];
var createdComponents_ = [];
function findRegisteredClass_(name, opt_replace) {
for (var i = 0; i < registeredComponents_.length; i++) {
if (registeredComponents_[i].className === name) {
if (opt_replace !== undefined) {
registeredComponents_[i] = opt_replace;
}
return registeredComponents_[i];
}
}
return false;
}
function upgradeDomInternal(jsClass, cssClass) {
if (cssClass === undefined) {
var registeredClass = findRegisteredClass_(jsClass);
if (registeredClass) {
cssClass = registeredClass.cssClass;
}
}
var elements = document.querySelectorAll('.' + cssClass);
for (var n = 0; n < elements.length; n++) {
upgradeElementInternal(elements[n], jsClass);
}
}
function upgradeElementInternal(element, jsClass) {
if (element.getAttribute('data-upgraded') === null) {
element.setAttribute('data-upgraded', '');
var registeredClass = findRegisteredClass_(jsClass);
if (registeredClass) {
createdComponents_.push(new registeredClass.classConstructor(element));
} else {
createdComponents_.push(new window[jsClass](element));
}
}
}
function registerInternal(config) {
var newConfig = {
'classConstructor': config.constructor,
'className': config.classAsString,
'cssClass': config.cssClass
};
var found = findRegisteredClass_(config.classAsString, newConfig);
if (!found) {
registeredComponents_.push(newConfig);
}
upgradeDomInternal(config.classAsString);
}
return {
upgradeDom: upgradeDomInternal,
upgradeElement: upgradeElementInternal,
register: registerInternal
};
}();
function MaterialTabs(element) {
'use strict';
this.element_ = element;
this.init();
}
MaterialTabs.prototype.Constant_ = {
MEANING_OF_LIFE: '42',
SPECIAL_WORD: 'HTML5',
ACTIVE_CLASS: 'pactive'
};
MaterialTabs.prototype.CssClasses_ = {
SHOW: 'materialShow',
HIDE: 'materialHidden'
};
MaterialTabs.prototype.initTabs_ = function(e) {
'use strict';
this.tabs_ = this.element_.querySelectorAll('.tab');
this.panels_ = this.element_.querySelectorAll('.panel');
for (var i=0; i < this.tabs_.length; i++) {
new MaterialTab(this.tabs_[i], this);
}
};
MaterialTabs.prototype.resetTabState_ = function() {
for (var k=0; k < this.tabs_.length; k++) {
this.tabs_[k].classList.remove('pactive');
}
};
MaterialTabs.prototype.resetPanelState_ = function() {
for (var j=0; j < this.panels_.length; j++) {
this.panels_[j].classList.remove('pactive');
}
};
function MaterialTab (tab, ctx) {
if (tab) {
var link = tab.querySelector('a');
link.addEventListener('click', function(e){
e.preventDefault();
var href = link.href.split('#')[1];
var panel = document.querySelector('#' + href);
ctx.resetTabState_();
ctx.resetPanelState_();
tab.classList.add('pactive');
panel.classList.add('pactive');
});
}
};
MaterialTabs.prototype.init = function() {
if (this.element_) {
this.initTabs_();
}
}
window.addEventListener('load', function() {
componentHandler.register({
constructor: MaterialTabs,
classAsString: 'MaterialTabs',
cssClass: 'MaterialTabs'
});
});
});
There is updated and working version.
What we have to do, is to move the target on the same level as the icon is (almost like tab and content). Instead of this:
<div class="emoticon">
<div class="emoticon_click" data-id="1">
<img src="http://megaicons.net/static/img/icons_sizes/8/178/512/emoticons-wink-icon.png" width="30px" height="30px">
<div class="user-container" data-upgraded></div>
</div>
</div>
We need this
<div class="emoticon">
<div class="emoticon_click" data-id="1">
<img src="http://megaicons.net/static/img/icons_sizes/8/178/512/emoticons-wink-icon.png" width="30px" height="30px">
// not a child
<!--<div class="user-container" data-upgraded></div>-->
</div>
// but sibling
<div class="user-container" data-upgraded></div>
</div>
And if this is new HTML configuration, we can change the handlers
to target click on div "emoticon_click"
change the content of the sibling (not child) div "user-container"
The old code to be replaced
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
$(this).on( "click", function() {
$(this).find('.user-container').html("");
});
will now be replaced with this:
//$('body').on('click', '.emoticon', function(e) {
$('body').on('click', '.emoticon_click', function(e) {
// clear all user container at the begining of this click event
$('body').find('.user-container').html("");
// find id
var id = $(this).attr('data-id');
// find the parent, which also contains sibling
// user-container
var parent = $(this).parent()
// let the target be initiated
showProfileTooltip($(parent), id);
});
$(this).on( "click", function() {
//$(this).find('.user-container').html("");
});
Check it in action here
NOTE: the really interesting note was in this Answer by pinturic
If we want to extend the first and complete answer with a feature:
close all tabs if clicked outside of the area of tabs or icons
we just have to
add some event e.g. to body
and do check if the click was not on ".emoticon" class elements
There is a working example, containing this hook:
$('body').on( "click", function(e) {
// if clicked in the EMOTICON world...
var isParentEmotion = $(e.toElement).parents(".emoticon").length > 0 ;
if(isParentEmotion){
return; // get out
}
// else hide them
$('body').find('.user-container').html("");
});
I have been debugging your code and this is the result:
you are adding the "tab" under ; any time you click within that div this code is intercepting it:
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
and thus the "tab" are built again from scratch.

How to make expand all/collapse all button in this certain script?

i would like to ask for help in a simple task i really need to do at my work (I am a javascript newbie). I made a simple collapsible list with script provided by this guy http://code.stephenmorley.org/javascript/collapsible-lists/ but what i need right now are two simple buttons as stated in the title: expand all and collapse whole list. Do you guys know if something like that can be implemented in this certain script? Please help :)
var CollapsibleLists = new function () {
this.apply = function (_1) {
var _2 = document.getElementsByTagName("ul");
for (var _3 = 0; _3 < _2.length; _3++) {
if (_2[_3].className.match(/(^| )collapsibleList( |$)/)) {
this.applyTo(_2[_3], true);
if (!_1) {
var _4 = _2[_3].getElementsByTagName("ul");
for (var _5 = 0; _5 < _4.length; _5++) {
_4[_5].className += " collapsibleList";
}
}
}
}
};
this.applyTo = function (_6, _7) {
var _8 = _6.getElementsByTagName("li");
for (var _9 = 0; _9 < _8.length; _9++) {
if (!_7 || _6 == _8[_9].parentNode) {
if (_8[_9].addEventListener) {
_8[_9].addEventListener("mousedown", function (e) {
e.preventDefault();
}, false);
} else {
_8[_9].attachEvent("onselectstart", function () {
event.returnValue = false;
});
}
if (_8[_9].addEventListener) {
_8[_9].addEventListener("click", _a(_8[_9]), false);
} else {
_8[_9].attachEvent("onclick", _a(_8[_9]));
}
_b(_8[_9]);
}
}
};
function _a(_c) {
return function (e) {
if (!e) {
e = window.event;
}
var _d = (e.target ? e.target : e.srcElement);
while (_d.nodeName != "LI") {
_d = _d.parentNode;
}
if (_d == _c) {
_b(_c);
}
};
};
function _b(_e) {
var _f = _e.className.match(/(^| )collapsibleListClosed( |$)/);
var uls = _e.getElementsByTagName("ul");
for (var _10 = 0; _10 < uls.length; _10++) {
var li = uls[_10];
while (li.nodeName != "LI") {
li = li.parentNode;
}
if (li == _e) {
uls[_10].style.display = (_f ? "block" : "none");
}
}
_e.className = _e.className.replace(/(^| )collapsibleList(Open|Closed)( |$)/, "");
if (uls.length > 0) {
_e.className += " collapsibleList" + (_f ? "Open" : "Closed");
}
};
}();
It is important to understand why a post-order traversal is used. If you were to just iterate through from the first collapsible list li, it's 'children' may (will) change when expanded/collapsed, causing them to be undefined when you go to click() them.
In your .html
<head>
...
<script>
function listExpansion() {
var element = document.getElementById('listHeader');
if (element.innerText == 'Expand All') {
element.innerHTML = 'Collapse All';
CollapsibleLists.collapse(false);
} else {
element.innerHTML = 'Expand All';
CollapsibleLists.collapse(true);
}
}
</script>
...
</head>
<body>
<div class="header" id="listHeader" onClick="listExpansion()">Expand All</div>
<div class="content">
<ul class="collapsibleList" id="hubList"></ul>
</div>
</body>
In your collapsibleLists.js
var CollapsibleLists =
new function(){
...
// Post-order traversal of the collapsible list(s)
// if collapse is true, then all list items implode, else they explode.
this.collapse = function(collapse){
// find all elements with class collapsibleList(Open|Closed) and click them
var elements = document.getElementsByClassName('collapsibleList' + (collapse ? 'Open' : 'Closed'));
for (var i = elements.length; i--;) {
elements[i].click();
}
};
...
}();

Js and Divs, (even <div> is difference)

I Have find a javascript code that works perfectly for showing a DIV.
but this code works only for showing one div for each page.
i want to include many DIVS for hiding and showing in the same page.
I was try to replace the div id and show/hide span id with a rundom php number for each include, but still is not working.
so how i have to do it?
the JS code:
var done = true,
fading_div = document.getElementById('fading_div'),
fade_in_button = document.getElementById('fade_in'),
fade_out_button = document.getElementById('fade_out');
function function_opacity(opacity_value) {
fading_div.style.opacity = opacity_value / 100;
fading_div.style.filter = 'alpha(opacity=' + opacity_value + ')';
}
function function_fade_out(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'none';
done = true;
}
}
function function_fade_in(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'block';
}
if (opacity_value == 100) {
done = true;
}
}
// fade in button
fade_in_button.onclick = function () {
if (done && fading_div.style.opacity !== '1') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_in(x)
};
})(i), i * 10);
}
}
};
// fade out button
fade_out_button.onclick = function () {
if (done && fading_div.style.opacity !== '0') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_out(x)
};
})(100 - i), i * 10);
}
}
};
Check out the Fiddle, you can edit code based on your needs ;)
$(function() {
$('.sub-nav li a').each(function() {
$(this).click(function() {
var category = $(this).data('cat');
$('.'+category).addClass('active').siblings('div').removeClass('active');
});
});
});
finaly i found my self:
<a class="showhide">AAA</a>
<div>show me / hide me</div>
<a class="showhide">BBB</a>
<div>show me / hide me</div>
js
$('.showhide').click(function(e) {
$(this).next().slideToggle();
e.preventDefault(); // Stop navigation
});
$('div').hide();
Am just posting this in case someone was trying to answer.

Categories