Html page jumps when clicking link - javascript

Building a frontend and getting a bit baffled since I´m unable to stop the browser to jump when triggering a click event on an img.
I thought that either event.preventDefault() or return false would do it but I am obviously missing something and is completely at a loss about what to try next!
Here is the code
$("#imgViewer-thumbs").find("img").click(function (event) {
event.preventDefault();
var $imgViewPane = $("#imgViewPane"),
$selectedImage = $imgViewPane.find(".selected-image"),
$clickedImage = $(this),
$clickedImageIndex = $clickedImage.prevAll().length + 1,
$maxIndex = $clickedImageIndex + $clickedImage.nextAll().length,
$targetImage = $imgViewPane.find(":nth-child(" + $clickedImageIndex + ")");
if (!$targetImage.hasClass("selected-image")) {
$selectedImage.fadeOut(100, function () {
$targetImage.addClass("selected-image");
$selectedImage.removeClass("selected-image");
$targetImage.fadeIn(100);
});
}
console.log('Returning false');
return false;
}
);
EDIT:
Setup the imageviewer in jsfiddle here http://jsfiddle.net/tEXaa/

The problem is that image container "#imgViewPane" doen't hold the height. So then the prev image fades out "#imgViewPane" loses height and as a result the page loses scroll position.
I updated your fiddle: http://jsfiddle.net/tEXaa/1/

I had the same problem but with clicking anchor tags, and the problem wasn't with any jquery code but with negative margins.
Instead of using something like this
<div width="600px">
<div id="top-left" style="height:200px;"> some content </div>
<div id="top-right" style="margin-top:-200px;> content"</div>
</div>
use
<div width="600px">
<div id="top-left" style="float:left;"> some content </div>
<div id="top-right" style="float:right;> content"</div>
</div>

Related

lazy loading images on scroll and "come into view"

I am using Lazy as a lazy image loading plugin. I have a div where I load divs like this:
<div class="nano-content" id="lScroll">
/*... MORE LIKE THIS ... */
<div class="card">
<div class="city-selected city-medium clickChampion pointer"
data-champ-id="1">
<article>
<div class="info">
<div class="city">
CHAMPNAME
</div>
</div>
</article>
<figure class="cFigure lazy" data-src="images/champions/CHAMPNAME_0.png"></figure>
</div>
</div>
/*... MORE LIKE THIS ... */
</div>
So I initiate the plugin and it works for the first ones visible and when I scroll:
var $lazy = $('#lScroll .lazy');
if ($lazy.length) {
$lazy.Lazy({
appendScroll: $('#lScroll')
});
}
But now I have a function that "filters" the divs by their attributes when I enter sth in my search input and it fails to load the image when the according div is shown:
$(document).on("keyup", "#searchVod", function () {
var $search = $(this);
var $sVal = $search.val().toLowerCase();
if ($sVal !== "") {
$(".vodCard").hide();
$('[data-champ*="' + $sVal + '"]').show();
$('[data-role*="' + $sVal + '"]').show();
} else {
$(".vodCard").show();
}
});
I tried bind: "event" /w and w/out delay: 0 (loading the plugin in the search function) but when I searched it would load ALL images immediately in the background.
Any hint highly appreciated
UPDATE: I just noticed in Chrome DevTab after entering one letter in my searchbox it loads ALL the images and eventually the one I am searching for (if its the last it takes some time (30MB sth)
There is an excellent library called Lozad.js which can help you to make it easier to load your images like lazy load do but in easier way.
You can download it here from Github.
Demo page here.
Explanation:
This library will load your images one by one on scrolling to each image anchor by class name.
Example
HTML:
At the header ->
<script src="https://cdn.jsdelivr.net/npm/lozad"></script>
Image element should looks like this:
<img class="lozad" data-src="image.png">
Javascript
// Initialize library
lozad('.lozad', {
load: function(el) {
el.src = el.dataset.src;
el.onload = function() {
el.classList.add('fade')
}
}
}).observe()
Hope it will help you.
Best,
Ido.

Find the class after a clicked class in a HTML document

I Have the following in my HTML:
<div class="item" id="item_1">
Content
</div>
<div class="item" id="item_2">
Content
</div>
<div class="item" id="item_3">
Content
</div>
<!--CONTENT BLOCK 1-->
<div class="item w100" id="content_1">
Story
</div>
<!--/CONTENT BLOCK 1-->
<div class="item" id="item_4">
Content
</div>
<div class="item" id="item_5">
Content
</div>
<!--CONTENT BLOCK 2-->
<div class="item w100" id="content_2">
Story
</div>
<!--/CONTENT BLOCK 2-->
<div class="item" id="item_6">
Content
</div>
<!--CONTENT BLOCK 3-->
<div class="item w100" id="content_3">
Story
</div>
<!--/CONTENT BLOCK 3-->
The content blocks are hidden, only visible when an item is clicked.
I had this working fine as an unresponsive layout but now I've made the website responsive and the javascript needs to function slightly differently as each item width is different (it's a boxed grid layout).
This is the javascript:
// Open Link in Content Block
jQuery(document).ready(function($){
$('.contentLink').click(function(event){
var itemID=$(event.target).closest(".storyLink").attr("id");
showBlock(itemID);
document.location.hash = itemID;
return false;
});
});
function showBlock(targetID){ //load content and open dialog
var $url = "ss_storyboard/"+targetID+".html";
if (targetID == 'Sarah')
{
loadStory("#content_1", 500, targetID);
}
else if ((targetID == 'item_1') || (targetID == 'item_2') || (targetID == 'item_3'))
{
loadStory("#content_2", 1700, targetID);
}
else if (targetID == 'item_4' || targetID == 'item_5')
{
loadStory("#content_3", 2200, targetID);
}
else if (targetID == 'item_6' || targetID == 'item_7')
{
loadStory("#content_4", 2750, targetID);
}
else{
return false;
}
I was thinking I could do something like this:
jQuery(document).ready(function($){
$('.contentLink').click(function(event){
var itemID=$(event.target).closest(".storyLink").attr("id");
var contentID= $(event.target).next(".w100").attr("id");
showBlock(itemID, contentID);
document.location.hash = itemID;
return false;
});
});
But jquery's .next() only works within the content set. Is there a way to find find the next class the comes after a clicked class in a document??
Another way I though I could do this is to detect where the line break of the items ends (ie. when the items wrap to a new line), and append the content block in dynamically after this....I'm just not sure how to go about calculating where the break would be. All the item widths use percentages that differ for a number of media queries matching the different screen widths.
Final answer
Measure available area
function measureWidths(){
var container = document.getElementById("container"),
containerRectObject = container.getBoundingClientRect(),
containerRight = 0;
containerRight = containerRectObject.right;
return containerRight;
}
Go trought each storyLink and certain data-attribute if it's last of row.
This uses containerRight -value from previous function.
$(".storylink").each(function(key, value) {
$(this).append("<h2>Storylink no: " + key + "</h2>");
$(this).attr("data-open", "false");
$(this).attr("data-target", "content-" + key).append("<em>My data-target is 'content-" + key + "'</em>");
storyLinkRectObject = this.getBoundingClientRect();
storyLinkRight = storyLinkRectObject.right;
if(storyLinkRight == containerRight){
$(this).attr("data-row",dataRow);
$(this).attr("data-endOfRow",dataRow);
dataRow++;
}else{
$(this).attr("data-row",dataRow);
}
});
On click, dynamically move contentBlock after last storylink on the row.
//Destroy previous content of dynamicContentBlock
$(".dynamicContentBlock").html("");
$(".dynamicContentBlock").append(storyContent);
console.log(currentRow);
$(".dynamicContentBlock").insertAfter($("*[data-endOfRow='"+currentRow+"']"));
$(".dynamicContentBlock").show("slow");
Check the whole code HERE
I improved my answer based on your comment. Now the code checks if window width is small or not and if it's small (mobile), it does the following.
toggle clicked .storyLink larger (optional)
get wanted .storyBlock, based on assigned data-attributes (new)
use insertAfter() -jQuery method to move selected .storyBlock-node
after clicked .storyLink (new)
show wanted content(your code)
Notice:
I added some custom data-attributes on .storyLinks, .storyblocks
and to .story-elements. (only to first set of links)
I added .story for each .storyLink just to make things more clear to myself. Stories are now shown based on class "open".
CodePen
You can find code here
OLD ANSWER
If I understood you right, then this might help you.
Assigining data-targets (or similar), you can easily detect what content block to show on click.
I used .toggle() -jQuery method, but if you don't want to hide content block on second click, then you can just use .show() instead.
Hope this helps!
CodePen

Show/Hide Content without reloading the page

I have three content boxes that i want to show and hide using controls.
The HTML is as follows:
<div id="leermat1">
Content here
<a class="pag-next">Next</a>
<a class="pag-prev">Previous</a>
</div>
<div id="leermat2">
Content here
<a class="pag-next">Next</a>
<a class="pag-prev">Previous</a>
</div>
<div id="leermat3">
Content here
<a class="pag-next">Next</a>
<a class="pag-prev">Previous</a>
</div>
I have the two anchors pag-next and pag-prev that will control which of the content divs should be visible at any given point:
I want to write jquery such as, when #leermat1 'pag-next' is clicked, it hides #leermat1 and shows #leermat2. Then when #leermat1 is hidden and #leermat2 shows, when '.pag-next' is clicked, it hides #leermat2, and shows #leermat3.
Also the 'pag-prev' should work the same way.
I started with the following but dont know where to go from here.
$(document).ready(function() {
$('.pag-next').on('click',function() {
$('#leermat1').addClass('hide');
$('#leermat2').addClass('show');
});
});
One more thing is that the '.pag-next' should stop functioning after it has shown #leermat3.
You need this
$('[class^=pag-]').click(function() {
var elem = $('[id^=leermat]').filter(":visible"); // take the visible element
var num = Number(elem[0].id.match(/\d+$/)[0]); // take the number from it
var step = $(this).is('.pag-next') ? 1 : -1; // ternary operator
$('#leermat'+ (num + step)).show(); // show next or back
elem.hide(); // hide the visible element
});
Looks like in your anchor tag you have not given it a class.
Next
You then go on in your JQuery code to add a click function to a class which does not exist.
$('.pag-next').on('click',function()
Try adding class="pag-next" to your anchor tag.
This is what worked for me through a little trial and error. Although I am not sure if this is the most efficient solution.
$('#leermat1 .pag-next').on('click',function(){
$('#leermat1').addClass('hide');
$('#leermat1').removeClass('show');
$('#leermat3').addClass('hide');
$('#leermat3').remove('show');
$('#leermat2').addClass('show');
});
$('#leermat2 .pag-next').on('click',function(){
$('#leermat1').removeClass('show');
$('#leermat2').addClass('hide');
$('#leermat2').removeClass('show');
$('#leermat3').addClass('show');
});
$('#leermat2 .pag-prev').on('click',function(){
$('#leermat2').addClass('hide');
$('#leermat2').removeClass('show');
$('#leermat1').addClass('show');
$('#leermat3').removeClass('show');
});
$('#leermat3 .pag-prev').on('click',function(){
$('#leermat3').addClass('hide');
$('#leermat2').addClass('show');
$('#leermat1').addClass('hide');
$('#leermat3').removeClass('show');
$('#leermat1').removeClass('show');
});

Copying element's style width attribute to another element

I have a progress bar that is outputted from a webapp program like this:
<div id="diskUsageProgressBar">
<div class="green-bar" style=" width: 1%;">
</div>
</div>
And I have added to the page a much nicer bar like this:
<div class="progress xs">
<div class="progress-bar progress-bar-red diskusgbar" style="width: 1%;"></div>
</div>
How could I use javascript (or JQuery) to copy the width value from the first one and paste it into the second one on page load?
Thanks for the help!
jQuery javascript:
$('.progress.xss .diskusgbar').css('width',
$('#diskUsageProgressBar .green-bar').css('width')
);
Like this:
$(function(){
$('.progress-bar-red').attr('style',$('.green-bar').attr('style'));
})
If you want to only copy the width then you can use native .width() method of jquery to get/set value:
$('.progress-bar').width($('.green-bar').width());
use this
$('.progress-bar').width($('.green-bar').width());
First, as said in Is it possible to listen to a "style change" event?
(function() {
var ev = new $.Event('style'),
orig = $.fn.css;
$.fn.css = function() {
orig.apply(this, arguments);
$(this).trigger(ev);
}
})();
And then bind it:
$('#diskUsageProgressBar > .green-bar').bind('style', function(e) {
$('.progress.xs > .diskusgbar').css('width',
$('#diskUsageProgressBar > .green-bar').css('width')
);
});
Hope it works. Maybe tricky and not so symple if the first bar is in another iframe.

How to detect mouseleave() on two elements at once?

Answer can be in vanilla js or jQuery. I want to hide a div with the id "myDiv" if the user is no longer hovering over a link with the id "myLink" or a span with the id "mySpan". If the user has his mouse over either element "myDiv" will still show, but the second the user is not hover over either of the two (doesn't matter which element the user's mouse leaves first) "myDiv" will disappear from the face of existence.
In other words this is how I detect mouse leave on one element:
$('#someElement').mouseleave(function() {
// do something
});
but how to say (in a way that will actually work):
$('#someElement').mouseleave() || $('#someOtherElement').mouseleave()) {
// do something
});
How to detect this?
Something like this should work:
var count = 0;
$('#myLink, #mySpan').mouseenter(function(){
count++;
$('#myDiv').show();
}).mouseleave(function(){
count--;
if (!count) {
$('#myDiv').hide();
}
});
jsfiddle
You could use a multiple selector:
$("#someElement, #someOtherElement").mouseleave(function() {
// Do something.
});
You can beautifully use setTimeout() to give the mouseleave() function some "tolerance", that means if you leave the divs but re-enter one of them within a given period of time, it does not trigger the hide() function.
Here is the code (added to lonesomeday's answer):
var count = 0;
var tolerance = 500;
$('#d1, #d2').mouseenter(function(){
count++;
$('#d3').show();
}).mouseleave(function(){
count--;
setTimeout(function () {
if (!count) {
$('#d3').hide();
}
}, tolerance);
});
http://jsfiddle.net/pFTfm/195/
I think, it's your solution!!!
$(document).ready(function() {
var someOtherElement = "";
$("#someElement").hover(function(){
var someOtherElement = $(this).attr("href");
$(someOtherElement).show();
});
$("#someElement").mouseleave(function(){
var someOtherElement= $(this).attr("href");
$(someOtherElement).mouseenter(function(){
$(someOtherElement).show();
});
$(someOtherElement).mouseleave(function(){
$(someOtherElement).hide();
});
});
});
----
html
----
<div id="someElement">
<ul>
<li>element1</li>
<li>element2</li>
</ul>
</div>
<div id="tab1" style="display: none"> TAB1 </div>
<div id="tab2" style="display: none"> TAB1 </div>
While the answer from lonesomeday is perfectly valid I changed my html to have both elements in one container. I originally wanted to avoid this hence I had to do more refactoring for my clients in other html templates, but I think it will pay out on the long term.
<div id="my-container">
<div class="elem1">Foo</div>
<div class="elem2">Bar</div>
</div>
$('#my-container').mouseleave(function() { console.log("left"); });

Categories

Resources