Slider animation handle with JQuery, hover element issue using promises - javascript

I have problem with a slider. It works correctly without one, strange for me, situation. When I mouseover fast from one dot to another, it will not wait until previous animation ends and two texts overlap. Can somebody older and wiser help me?
HTML structure of project:
<section class="product-section">
<div class="vertical-text vertical-text-custom-5">
Pluginy
</div>
<div class="carrousel-image-container-1 product-release-management">
<i class="image-carrousel-1"></i>
</div>
<div class="carrousel-image-container-2 product-SLA">
<i class="image-carrousel-2"></i>
</div>
<div class="carrousel-image-container-3 product-test-management">
<i class="image-carrousel-3"></i>
</div>
<div class="col-custom-5">
<div class="col-custom-7 text-size-xl">
<div class="text-container-17">
<div class="product product-release-management">
<span class="text-color-6 text-weight-thin">Rivet</span> <br>
<span class="text-color-5 text-weight-bold">Release Management</span> <br>
<span class="text-color-3 text-weight-bold">plugin</span>
</div>
<div class="product product-SLA">
<span class="text-color-6 text-weight-thin">Rivet</span> <br>
<span class="text-color-5 text-weight-bold">SLA</span> <br>
<span class="text-color-3 text-weight-bold">plugin</span>
</div>
<div class="product product-test-management">
<span class="text-color-6 text-weight-thin">Rivet</span> <br>
<span class="text-color-5 text-weight-bold">Test Management</span> <br>
<span class="text-color-3 text-weight-bold">plugin</span>
</div>
</div>
<div id="carrousel-dots-contener" class="carrousel-dots text-color-5">
<div class="dot-container" data-carrousel-dot='dot-1'>
<div class="dot-border">
<div class="dot dot-custom-2">●</div>
</div>
</div>
<!--
-->
<div class="dot-container" data-carrousel-dot='dot-2'>
<div class="dot-border">
<div class="dot dot-custom-2">●</div>
</div>
</div>
<!--
-->
<div class="dot-container" data-carrousel-dot='dot-3'>
<div class="dot-border">
<div class="dot dot-custom-2">●</div>
</div>
</div>
</div>
</div>
</div>
REST OF CODE HERE

These are the main issues:
The promise() call works fine when you are sure you don't need to interrupt the animation, but as soon as you have mouse events that need immediate action (like hideAll), this promise will become a problem: it will still resolve, but at an inconvenient moment. In fact, as soon as you do another animation like hideAll, you want to cancel the execution of the code that follows the resolved promise. So... add a condition before proceeding with fadeIn() to see that the product selection is still relevant.
runInterval calls cyclicChange immediately, which is great when the page loads, but which is a bit annoying when moving the mouse over one dot to the next: as the mouse may exit the area, runInterval gets called and makes the selection jump to potentially another dot, which makes it kinda jumpy. It is better to remove this immediate call to cyclicChange and then to add some code to show the first product when start runs.
To avoid unwanted queuing of animations, you could call stop(true) before doing fadeOut().
I applied these changes to your JavaScript code, where I also made some other improvements, unrelated to the problem:
var carrousel = (function() {
var interval = null,
products,
current = -1;
products = [
'.product-release-management',
'.product-SLA',
'.product-test-management'
];
function showProduct(id) {
// Avoid unnecessary work
if (id == current) return; // nothing to do;
// In other cases: hide first
hideAll();
current = id;
$('.product').promise().done(function() {
// Make sure selection is still like at the start of showProduct execution
if (current === id) $(products[current]).fadeIn(500);
});
$("div[data-carrousel-dot='dot-" + (current + 1) + "']").addClass('dot-active');
}
function hideAll() {
// 1. easier selector for selecting all product classes
// 2. stop any ongoing animation
$(products.join(",")).stop(true, true).fadeOut(500);
$("div[data-carrousel-dot").removeClass('dot-active');
}
function cyclicChange() {
if ( isNaN(interval) ) return; // timer is not active
showProduct((current + 1) % products.length); // easier way to roundtrip
}
function runInterval(){
interval = setInterval(cyclicChange, 3000);
}
function mouseOverDotHandler() {
$('.dot-container').hover(
function() {
// Easier way to get number
showProduct($(this).index());
}
);
$('#carrousel-dots-contener').hover(
function(){
clearInterval(interval);
interval = null; // use variable for indicating the pause
},
runInterval
);
}
return {
start: function() {
showProduct(0);
runInterval();
mouseOverDotHandler();
}
}
})();
$(document).ready(function(){
carrousel.start();
});
See it run on jsbin.com.

Related

After adding querySelector inside function page crash

With this function, every div element that has children needs to wrap the children in a wrap div. Everything works fine if
<button id="run" onclick="wrapChildren(document.querySelector('#element1'))">Run</button>
but at the moment when I insert in the function:
var element = document.querySelector('#element1');
the page is crashing "devtools was disconnected from the page". Why is this happening and how to fix?
function wrapChildren() {
var element = document.querySelector('#element1');
const childElements = Array.from(element.children);
if (childElements.length === 0) {
return;
}
const wrapDiv = document.createElement('div');
wrapDiv.id = element.id+"wrap";
childElements.forEach((childElement) => {
wrapDiv.appendChild(childElement);
});
element.appendChild(wrapDiv);
childElements.forEach((childElement) => {
wrapChildren(childElement);
});
}
<div id="element1">
<div id="child1">
<div id="grandchild1"></div>
<div id="grandchild2">
<div id="granddrandchild1"></div>
<div id="granddrandchild2"></div>
<div id="granddrandchild3">
<div id="granddrandgrandchild1"></div>
</div>
</div>
</div>
<div id="child2"></div>
</div>
<button id="run" onclick="wrapChildren()">Run</button>
The way you have written it, your wrapChildren function doesn't actually take any arguments:
function wrapChildren()
so it was always running exactly the same code, even when you attempt to call it recursively with a different argument (in the forEach at the end of your function). As a result, your code leads to infinite recursion and hence a page crash.
To fix this, just give it an element as the argument, and use this element in the function body rather than hardcoding element to be the one with id element1.
I have made this change below and there is no crash any more. The function doesn't actually appear to do anything very much, but I'll leave that to you to sort out, or perhaps ask a new question about. (I don't actually know what this is trying to do.)
function wrapChildren(element) {
const childElements = Array.from(element.children);
if (childElements.length === 0) {
return;
}
const wrapDiv = document.createElement('div');
wrapDiv.id = element.id+"wrap";
childElements.forEach((childElement) => {
wrapDiv.appendChild(childElement);
});
element.appendChild(wrapDiv);
childElements.forEach((childElement) => {
wrapChildren(childElement);
});
}
<div id="element1">
<div id="child1">
<div id="grandchild1"></div>
<div id="grandchild2">
<div id="granddrandchild1"></div>
<div id="granddrandchild2"></div>
<div id="granddrandchild3">
<div id="granddrandgrandchild1"></div>
</div>
</div>
</div>
<div id="child2"></div>
</div>
<button id="run" onclick="wrapChildren(document.querySelector('#element1'))">Run</button>

Text not fully redrawing when I toggle between templates

On my AngularJS app I have a view that allows me to toggle between type of insurance cover and it works fine. However on iPhone in particular (Chrome & Safari), the text kind of scrambles when I toggle between the prices. To be very clear about it, it's only the top few pixels and those pixels generally belong to the price toggled away from, so it's like the page isn't properly redrawing it. This issue then goes away if I do anything in the Dev tools. Any help is appreciated here.
EDIT: This appears to only happen when I select an option that updates the value displayed, not when it switched to a different piece of template.
Here's a screenshot
And a slightly stripped down version of the template in question:
<div class="row quote-tab-container">
<div class="col">
<div class="quote__tab">
<button ng-click="selectedCoverType = 'Comp'; setCoverDetails()" class="quote__tab__button">
Comprehensive
<div class="active-selection" ng-show="selectedCoverType === 'Comp'"></div>
</button>
<button ng-click="selectedCoverType = 'Tpft'; setCoverDetails()" class="quote__tab__button">
Third Party,<br />Fire & Theft
<div class="active-selection-tpft" ng-show="selectedCoverType === 'Tpft'"></div>
</button>
</div>
</div>
</div>
<div class="quote-details row">
<div class="col">
<div class="answer--radio">
<input ng-click="paymentType = 'CC'" type="radio" ng-checked="paymentType == 'CC'" id="singlePayment" name="payment-type">
<label for="singlePayment">Single Payment</label>
</div>
<div class="answer--radio answer--radio--right">
<input ng-click="paymentType = 'DD'" type="radio" ng-checked="paymentType == 'DD'" id="monthlyPayments" name="payment-type">
<label for="monthlyPayments">Monthly Payments</label>
</div>
<section class="selected-product answer--checkbox" ng-show="paymentType == 'CC'">
<div class="your-online-price">
Your online price is
</div>
<div class="selected-product__price">
{{totalPremium | signedCurrencyFilter}}
</div>
<div class="selected-product__includes">
Price includes online discount of {{onlineDiscount | signedCurrencyFilter}}
</div>
</section>
<section class="selected-product answer--checkbox" ng-show="paymentType == 'DD'">
<div class="your-online-price">
Your online price is
</div>
<div class="selected-product__price">
{{instalmentAmount | signedCurrencyFilter}}
</div>
<div class="selected-product__includes">
Price includes online discount of {{onlineDiscount | signedCurrencyFilter}}
</div>
</section>
</div>
</div>
So because the browser would correct this glitch whenever the screen resized or had to redraw I had to force a redraw any time these options were selected. The best way to do this seemed to be to clone the element and replace the original with the clone in order to force a redraw, this was enclosed in a timeout in order to send this to the end of the execution queue.
This answer helped with this: https://stackoverflow.com/a/8840703/1999035
var n = document.createTextNode(' ');
var opacity = element.style.opacity;
element.appendChild(n);
element.style.opacity = '0.5';
setTimeout(function(){
element.style.display = opacity;
n.parentNode.removeChild(n);
}, 20);
My edit of the proposed solution is to use the opacity property rather than display, because the display change causes a jitter/glitch/flash that looks really bad.Opacity just causes a slight fade.

why jquery hover over one element, highlights all elements

When i hover over one element, all of them are highlighted
here is my html and jquery code
$('.hover-text').hide();
$('.movie-content').hover(
function () {
$('.movies_post_text').hide();
$('.hover-text').show();
},
function () {
$('.movies_post_text').show();
$('.hover-text').hide();
}
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="movie-content movie-big" style="background-image: url('Images/incidentbyabank-900x498.jpg');">
<a href="http://www.cricbuzz.com">
<div class="movies_post_text">
<h3>INCIDENT BY A BANK</h3>
<p>Sweden/12 MIN</p>
<p>Award Winning, Drama, Thriller</p>
<p>DIR.Ruben Ostlund</p>
</div>
<div class="hover-text">
<div class="row movie-info">
<div class="col-md-4">
<div class="reactions pull-left">
<div class="view">429<i class="fa fa-eye"></i></div>
<div class="like">252<i class="fa fa-thumbs-up"></i></div>
</div>
</div>
<div class="col-md-8">
<h3 class="grid-title">INCIDENT BY A BANK</h3>
<div class="movie-desc">
<p>Shot using a single camera, 90 people meticulously recreate a failed bank robbery that took place in Stockholm in June 2006. A superb single shot.The short went on to win the Golden Bear at </p>
</div>
</div>
</div>
</div>
</a>
</div>
Please suggest me any solutions to this with jquery or any html classes to use.Help me to get rid of it i know that if i use this it get resolved but how to use that this to get it working
The problem is that in your event callbacks you're not restricting your selectors to the operate only within the hovered parent.
$('.hover-text').hide();
$('.movie-content').hover(
function () {
$('.movies_post_text').hide(); //<-- all matching elements, not just the
// one inside the hovered div
$('.hover-text').show(); //<-- same here
},
function () {
$('.movies_post_text').show(); //<-- " "
$('.hover-text').hide(); //<-- " "
}
);
Should be
$('.hover-text').hide();
$('.movie-content').hover(
function () {
$(this).find('.movies_post_text').hide();
$(this).find('.hover-text').show();
},
function () {
$(this).find('.movies_post_text').show();
$(this).find('.hover-text').hide();
}
);

How to show element only if other element contains something using jQuery?

My guess is what I want to achieve should be easy, but due to my lack of knowledge of front-end development, I cannot manage to solve issue. Have a page that works with AJAX-filters that users can select. Filters that are currently applied show up within <div> with id=current-filters.
HTML looks like this:
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<!-- here every single applied filter is displayed -->
</div>
</div>
</div>
Need to hide the the entire DIV current-filters-box in case no filter is applied.
The page uses a Javascript file, bundle.js which is massive, but contains the following line:
s=document.getElementById("current-filters")
Therefore tried the following if-statement to hide the DIV:
if(s.length<1)$('#current-filters-box').hide()
and
if(s=0)$('#current-filters-box').hide()
But this does not seem to have any effect. Can someone tell, what I did wrong?
Demo of page can be found here
EDIT: this is what the HTML looks like when filters are applied:
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<div class="badge-search-public">
<strong>Humanities & Languages</strong> <span class="x" data-property="disciplines" data-value="4" onclick="filter.removeFilter(this)">×</span>
</div>
<div class="badge-search-public">
<strong>January</strong> <span class="x" data-property="months" data-value="1" onclick="filter.removeFilter(this)">×</span>
</div>
</div>
</div>
Both of your conditions are incorrect or I would say they are not doing what you think they do.
s.length will always prints undefined so instead of s.length<1 you could use s.children.length
and the second one is not a condition rather it is an assignment
s==0 // condition
s=0 //assignment
the correct condition for your requirement would be
if(s.children.length<1){
I have assigned snippets for illustration.
Without filters
s = document.getElementById("current-filters")
console.log(s.children.length);
if (s.children.length < 1) {
$('#current-filters-box').hide(1000)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="current-filters-box">
filter box
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<!-- here every single applied filter is displayed -->
</div>
</div>
</div>
Without filters
s = document.getElementById("current-filters")
console.log(s.children.length);
if (s.children.length < 1) {
$('#current-filters-box').hide(1000)
}
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<div class="badge-search-public">
<strong>Humanities & Languages</strong> <span class="x" data-property="disciplines" data-value="4" onclick="filter.removeFilter(this)">×</span>
</div>
<div class="badge-search-public">
<strong>January</strong> <span class="x" data-property="months" data-value="1" onclick="filter.removeFilter(this)">×</span>
</div>
</div>
</div>
Try this .
if( $('#current-filters').is(':empty') ) {
$('#current-filters-box').hide()// or $('#current-filters-box').css("display","none")
}
You are performing an assignment, try..
if (s.children.length)
Using vanilla JavaScript, you can check if the current-filters div is empty or not and toggle the parent div current-filters-box like this:
s= document.getElementById("current-filters");
t= document.getElementById("current-filters-box");
if(s.children.length<1) {
t.style.display = 'none';
// t.style.visibility= 'hidden'; <<-- use this if you want the div to be hidden but maintain space
}
else {
t.style.display = 'block';
// t.style.visibility= 'visible'; <<-- use this if you used visibility in the if statement above
}
You can achieve this by adding your own variable which counts or maintains your applied filters, e.g.
var applied_filter_count = 0;
at every time filter is applied
applied_filter_count++;
if(applied_filter_count) {
$('#current-filters-box').show()
}
and at every time filter is removed
applied_filter_count--;
if(!applied_filter_count) {
$('#current-filters-box').hide()
}
and by default current-filters-box should be display:none

Take div and insertAfter when div loads

Building a site that gives play by play info for a game and want to insert a div after a specific div appears.
<div id="pbp-no-drive-0-0" class="no-drive">
<span></span>
</div>
<div id="pbp-no-drive-0-1" class="no-drive">
<span></span>
</div>
<div id="pbp-0-0" class="all-plays">
<div class="drivesum></div>
<div id="pbp-in-drive-0-3" class="play-in-drive">
</div>
<div id="pbp-no-drive-0-25" class="no-drive">
<span></span>
</div>
<div id="pbp-0-1" class="all-plays">
<div class="drivesum"></div>
</div>
The "no-drive" divs will appear first, the "all-plays" div appears after a drive has started. I'm attempting to insert the "no-drive" divs after "drivesum" divs if they are already not there. There are multiple "all-plays" and "no-drives". It is for american football and the "no-drives" represent special teams kicking off.
What would be the best way to handle this?
You can write up a conditional statement. If you are not sure when this would be appended, then you can have a timer in place.
var timer;
timer = setInterval(function() {
if( !$('.all-plays').find('.no-drive').length) {
$('.no-drive').insertAfter('.drivesum');
clearInterval(timer);
}
}, 100);

Categories

Resources