I have a Javascript function for Marquee animation in my ASP.NET Masterpage that runs fine when the page is first loaded, but then stops when a page button is pressed. Any idea how to fix this?
I got help from here, Javascript Marquee to replace <marquee> tags
Using the second answer
window.addEventListener('load', function () {
function go() {
i = i < width ? i + step : 1;
m.style.marginLeft = -i + 'px';
}
var i = 0,
step = 3,
space = ' ';
var m = document.getElementById('marquee');
var t = m.innerHTML; //text
m.innerHTML = t + space;
m.style.position = 'absolute'; // http://stackoverflow.com/questions/2057682/determine-pixel-length-of-string-in-javascript-jquery/2057789#2057789
var width = (m.clientWidth + 1);
m.style.position = '';
m.innerHTML = t + space + t + space + t + space + t + space + t + space + t + space + t + space;
m.addEventListener('mouseenter', function () {
step = 0;
}, true);
m.addEventListener('mouseleave', function () {
step = 3;
}, true);
var x = setInterval(go, 50);
}, true);
HTML
<div id="marquee">
1 Hello world! 2 Hello world! 3 Hello world!
</div>
CSS
#marquee {
background:#eee;
overflow:hidden;
white-space: nowrap;
}
This problem relates to your button being within an UpdatePanel as you mentioned in the comments above. An UpdatePanel will cause the page to postback without re-triggering the PageLoad event, so any javascript tied to that will be lost.
However, you can use a PageRequestManager. This will allow us to also trigger a function on UpdatePanel postback. This allows us to run the pageload script both on initial load and UpdatePanel postback. The only caveat is that the script block has to come after your ScriptManager. I'd suggest moving it just before your </body> if possible.
Basic example:
//Add a page request manager
var prm = Sys.WebForms.PageRequestManager.getInstance();
//On postback of UpdatePanel
prm.add_endRequest(function () {
alert("UpdatePanel was just triggered!");
});
//On pageload
window.addEventListener('load', function () {
alert("Initial page load!");
}, true);
Your example:
//Because we now have to call our function on both Page Load AND UpdatePanel postback, let's put it in function
function pageInit() {
function go() {
i = i < width ? i + step : 1;
m.style.marginLeft = -i + 'px';
}
var i = 0,
step = 3,
space = ' ';
var m = document.getElementById('marquee');
var t = m.innerHTML; //text
m.innerHTML = t + space;
m.style.position = 'absolute'; // http://stackoverflow.com/questions/2057682/determine-pixel-length-of-string-in-javascript-jquery/2057789#2057789
var width = (m.clientWidth + 1);
m.style.position = '';
m.innerHTML = t + space + t + space + t + space + t + space + t + space + t + space + t + space;
m.addEventListener('mouseenter', function () {
step = 0;
}, true);
m.addEventListener('mouseleave', function () {
step = 3;
}, true);
var x = setInterval(go, 50);
}
//Add a page request manager
var prm = Sys.WebForms.PageRequestManager.getInstance();
//On postback of UpdatePanel
prm.add_endRequest(function () {
pageInit();
});
//On pageload
window.addEventListener('load', function () {
pageInit();
}, true);
If there are certain things you only want to happen on the initial load and not on the UpdatePanel postback, you can take them out of the pageInit() function and put them back in your load event instead.
Related
What I am trying to do is an image gallery in which you can navigate by arrows (left and right). There is x images in the image folder (for example let it be 8). Clicking the left arrow triggers the left() function:
function left() {
number--; // number variable is 1 for default, it's used for changing images which are named slide1 slide2... so I can change it like that: "slide" + number
document.getElementById("js_gallery_image").setAttribute("src", "img/" + "slide" + number + ".jpg"); //changes the number
and the right arrrow triggers the right() function which is the same but with number++ instead of number--.
And this was the code that I made at first but there is one more thing: when you go to the last image (8th one) clicking the right button should show the first image. I did it by adding an invisible img tag named #test, so I changed the right() function to that:
function right() {
number++;
document.getElementById("test").setAttribute("src", "img/" + "slide" + number + ".jpg"); //changes the test image path to next slide.
document.getElementById("test").onload = () => change(); // if number isn't greater than 8 image will load and change() function will change the image in gallery
document.getElementById("test").onerror = () => {
number = 1;
change();
}; // if number is greater than 8 it will throw an error so number will be changed to one and the change() function will be triggered.
};
and that worked, but how to do it with the left function, so when the first image is displayed and you click the left arrow it will show you the last image? I tried to do that:
function left() {
number--;
document.getElementById("test").setAttribute("src", "img/" + "slide" + number + ".jpg");
document.getElementById("test").onload = () => change();
document.getElementById("test").onerror = () => {
let err = false;
do {
number++
document.getElementById("test").setAttribute("src", "img/" + "slide" + number + ".jpg");
document.getElementById("test").onerror = () => err = true;
} while (err == false) //it pluses 1 to number untill test image throws an error which should be thrown when the number is greater than 8
};
And this didn't work, it gives me a result of an infinite loop. I trieed to do that using break statements and others but nothing worked.
From what it looks like, you have an issue with the loop and the fact that it is adding a listener, but is not waiting for the listener to do anything, causing the code to just loop and not wait for anything, and changing it again, not wait...
the fix for that could be to just make another loop inside of a loop and set the number to a variable to reduce having to download the same assets multiple times.
The code would look like this:
let maxImg = 0;
function findMax(){
let currentMax = 1; //initially sets it to one because I presume you will have at least one image in the gallary
let stoploop = false;
let testImg = new Image();
testImg.onload = function () {
currentMax += 1;
stoploop = true;
}
testImg.onerror = function () {
maxImg = currentMax;
stoploop = true;
}
testImg.setAttribute("src", "img/" + "slide" + (currentMax + 1) + ".jpg");
function loop() {
setTimeout(function () {
if (!stoploop) {
loop();
} else {
if (maxImg < 1) {
testImg.setAttribute("src", "img/" + "slide" + (currentMax + 1) + ".jpg");
loop();
}
}
}, 500);//done to not completely bog down the computer, may adjust if needbe
}
loop();
}
so in practice, you would have to have your left function look like this:
function left() {
number--;
document.getElementById("test").setAttribute("src", "img/" + "slide" + number + ".jpg");
document.getElementById("test").onload = () => change();
document.getElementById("test").onerror = () => {
document.getElementById("test").setAttribute("src", "img/" + "slide" + maxImg + ".jpg");
number = maxImg;
};
}
NOTE: With your current solution of testing through the client side you will have to have increased load time because you have to load all of the images, and that includes waiting for the images to be downloaded from the server one by one.
Have a go with this
let number = 0;
let last = 9999999;
const img = document.getElementById("test")
const prev = document.getElementById("prev");
const next = document.getElementById("next");
const changeImg = () => img.setAttribute("src", "img/" + "slide" + number + ".jpg");
img.onerror = () => { // should only trigger once at the end of the list
last = number - 1;
if (number<0) {
console.log("no images found")
return;
}
number = last;
changeImg()
}
nav.addEventListener("click",function(e) {
tgt = e.target;
dir = tgt.id === "prev" ? -1 : 1;
number += dir
if (number < 0 || number >= last) number = 0;
prev.disabled=number===0;
changeImg()
})
<div id="nav">
<button class="btn" id="prev" disabled type="button">Prev</button>
<img id="test" src="img/slide0.jpg">
<button class="btn" id="next" type="button">Next</button>
</div>
See if this helps:
Working example: https://jsfiddle.net/diogocosta/5w042uL1/4/
HTML
<button id="prev-button" disabled onclick="prevImage()">Previous</button>
<button id="next-button" onclick="nextImage()">Next</button>
<img src="https://placeimg.com/300/300/any" id="img-content">
JS
const images = [
'https://placeimg.com/300/300/animals',
'https://placeimg.com/300/300/nature',
'https://placeimg.com/300/300/people',
'https://placeimg.com/300/300/tech',
'https://placeimg.com/300/300/sepia',
]
const TOTAL_IMGS = 5
let currentImg = 1
const imgContent = document.getElementById('img-content')
function nextImage () {
if (currentImg < TOTAL_IMGS) {
currentImg++
imgContent.setAttribute('src', images[currentImg-1])
}
updateButtonState()
}
function prevImage () {
if (currentImg > 1) {
currentImg--
imgContent.setAttribute('src', images[currentImg-1])
}
updateButtonState()
}
// Enables and disables button
function updateButtonState() {
const nextButton = document.getElementById('next-button')
const prevButton = document.getElementById('prev-button')
if (currentImg === 1) {
nextButton.removeAttribute('disabled')
prevButton.setAttribute('disabled', true)
} else if (currentImg === TOTAL_IMGS) {
nextButton.setAttribute('disabled', true)
prevButton.removeAttribute('disabled')
} else {
nextButton.removeAttribute('disabled')
prevButton.removeAttribute('disabled')
}
}
Cheers,
I followed a tutorial and created a simple manual loop slideshow. I'm trying to make it so it changes the slide automatically even if the prev/next buttons aren't clicked. I tried a crude approach by setting a delay between automatic click events on the "next" button but for some reason it clicks it only once and stops. My js knowledge is very limited and can't figure it out, any input is appreciated. This is the script so far:
$(function() {
var ul = $(".slider ul");
var slide_count = ul.children().length;
var slide_width_pc = 100.0 / slide_count;
var slide_index = 0;
var first_slide = ul.find("li:first-child");
var last_slide = ul.find("li:last-child");
last_slide.clone().prependTo(ul);
first_slide.clone().appendTo(ul);
ul.find("li").each(function(indx) {
var left_percent = (slide_width_pc * indx) + "%";
$(this).css({"left":left_percent});
$(this).css({width:(100 / slide_count) + "%"});
});
ul.css("margin-left", "-100%");
$(".slider .prev").click(function() {
console.log("prev button clicked");
slide(slide_index - 1);
});
$(".slider .next").click(function() {
console.log("next button clicked");
slide(slide_index + 1);
});
function slide(new_slide_index) {
var margin_left_pc = (new_slide_index * (-100) - 100) + "%";
ul.animate({"margin-left": margin_left_pc}, 400, function() {
if(new_slide_index < 0) {
ul.css("margin-left", ((slide_count) * (-100)) + "%");
new_slide_index = slide_count - 1;
}
else if(new_slide_index >= slide_count) {
ul.css("margin-left", "-100%");
new_slide_index = 0;
}
slide_index = new_slide_index
});
}
});
Here is an approach to make it sliding automatically...
But if user clicks on prev/next, it holds the automatic feature for a defined "idle" time.
It need two lines added to your click handlers:
var autoEnabled = true; // ADDED
$(".slider .prev").click(function() {
console.log("prev button clicked");
slide(slide_index - 1);
autoEnabled = false; // ADDED
disabledCount = 0; // ADDED
});
$(".slider .next").click(function() {
console.log("next button clicked");
slide(slide_index + 1);
autoEnabled = false; // ADDED
disabledCount = 0; // ADDED
});
And this to cyclically slide or check if it can re-enable itself.
// ----------------- Automatic sliding interval with "idle time" to re-enable on user click
var idleTime = 5000; // Time without manual click to re-enable automatic sliding.
var autoSlideDelay = 1000; // Time between each slide when automatic.
var disabledCount = 0;
var autoSlide = setInterval(function(){
if(autoEnabled || disabledCount >= idleTime/autoSlideDelay ){
disabledCount = 0;
autoEnabled = true;
slide(slide_index + 1);
}else{
disabledCount++;
}
},autoSlideDelay);
var break_auto_slide = false;
function auto_silde()
{
if(break_auto_slide)
{
break_auto_slide = false;
return;
}
slide(slide_index + 1);
setTimeout(auto_silde,1000 /* time in ms*/);
}
setTimeout will call the function in a specified timeout in milliseconds.
Variable break_auto_slide - set it to true to stop the automatic slide. Next time the function is called it will return without setting a new timer and will reset this variable so auto mode can be turned on again.
First of all, I'm not very advanced at code and tend to only do this part time so please excuse all terrible/ugly code! I appreciate there are already some solutions out there but I can't seem to make any of them work with my code so would really appreciate some help!
I'm using isotope grid and trying to setup an infinite scroll. I want to load 10 images at a time when the user scrolls to the bottom by taking these images from an array and appending them to a temp div.
This is working perfectly when scrolling slowly, but as soon as you scroll quickly the function seems to fire multiple times, it gets a little glitchy and loads lots of images at once.
$(window).scroll(function() {
var scrollTop = $(window).scrollTop();
var windowHeight = $(window).height();
var docuHeight = $(document).height();
if(scrollTop + windowHeight == docuHeight){
nextTenImages = imagesData.splice(0,10);
var content = ""
for (var i = 0; i < nextTenImages.length; i++) {
content +=
"<div class='box " + nextTenImages[i]["type"] + "'" + ">" +
"<div class='box-wrapper'>" +
"<img src='" + nextTenImages[i]["src"] + "' />" +
"</div>" +
"</div>"
};
$('body').append('<div id="temp-load"><div id="grid"></div></div>');
$('#temp-load > #grid').append(content)
$('#temp-load > #grid').children().css({
opacity: 0
});
var toAdd = $('#temp-load > #grid').html();
$container.isotope('insert', $(toAdd), function(){
$container.children().css({
opacity: 1
});
$('#temp-load').remove();
});
}
});
Make a single timeout to run the callback. This may avoid the function from executing multiple times.
var timer;
function scrollEvt() {
/* scroll actions */
}
$(window).scroll(function() {
/* clear the old timeout */
clearTimeout(timer);
/* wait until 400 ms for callback */
timer = setTimeout(scrollEvt, 400);
});
Using other ways may result in problems (like comparing (window.performance || Date).now())...
Unbind that specific scroll event till your delayed operation is completed to prevent accumulating more of the event triggers which create the duplication behaviour as in your case.
var winCached = $(window),
docCached = $(document)
var currLeng = 0;
function addContent() {
dettachScrollEvent();
setTimeout(function() { //this timeout simulates the delay from the ajax post
for (var i = currLeng; i < currLeng + 100; i++)
$('div').append(i + '<br />');
currLeng = i;
console.log("called loader!");
attachScrollEvent();
}, 500);
}
function infiNLoader() {
if (winCached.scrollTop() + winCached.height() > docCached.height() - 300) {
addContent();
//alert("near bottom! Adding more dummy content for infinite scrolling");
}
}
function attachScrollEvent() {
winCached.scroll(infiNLoader);
}
function dettachScrollEvent() {
winCached.unbind('scroll', infiNLoader);
}
addContent();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
var fnr = function (a,b) {
// random integer on closed interval
var y = a + Math.floor((b - a + 1) * Math.random());
return y
}
var foo;
var myTimer;
function toRandom() {
var x = fnr(0, PICTURES.length - 1);
var y = SERVER + FOLDER + PICTURES[x] + SUFFIX;
document.getElementById("img").src = y;
document.getElementById("filename").value = PICTURES[x].toUpperCase();
}
function toRandomize() {
if(!foo) {
foo = true;
document.getElementById("random").value = "stop shuffle";
myTimer = setInterval("toRandom()", 600);
} else {
foo = false;
document.getElementById("random").value = "start shuffle";
clearInterval(myTimer);
}
}
window.onload = function () {
document.getElementById("random").onclick = toRandomize;
}
// button in the body of the HTML portion of my code
<input id="random" type="button" value="start shuffle">
I have a button to randomize photos, but it won't work the second time. Do you guys have any insight in reading the code? I know fnr stands for first-non-repeating, but I'm not too familiar with how to "reset it," or if it requires a reset to get it to work again. I have the same setup for other functions and they work fine.
It's cut so it will only show the parts relevant to the question. I apologize if it's confusing.
please I need some help in previewing a form in popup. I have a form, quite big, so I added the option of preview to show as popup. The lightbox form popup works well, but the problem I now have is function passform() passing the inputs(textfield, select, checkbox, radio) into the popup page for preview on Click().
Below are my javascript and html codes. I left the css and some html out, because I think they're not necessary. I will appreciate your help. Thank you
The Javascript
function gradient(id, level)
{
var box = document.getElementById(id);
box.style.opacity = level;
box.style.MozOpacity = level;
box.style.KhtmlOpacity = level;
box.style.filter = "alpha(opacity=" + level * 100 + ")";
box.style.display="block";
return;
}
function fadein(id)
{
var level = 0;
while(level <= 1)
{
setTimeout( "gradient('" + id + "'," + level + ")", (level* 1000) + 10);
level += 0.01;
}
}
// Open the lightbox
function openbox(formtitle, fadin)
{
var box = document.getElementById('box');
document.getElementById('shadowing').style.display='block';
var btitle = document.getElementById('boxtitle');
btitle.innerHTML = formtitle;
if(fadin)
{
gradient("box", 0);
fadein("box");
}
else
{
box.style.display='block';
}
}
// Close the lightbox
function closebox()
{
document.getElementById('box').style.display='none';
document.getElementById('shadowing').style.display='none';
}
//pass form fields into variables
var divexugsotherugsexams1 = document.getElementById('divexugsotherugsexams1');
var exugsotherugsexams1 = document.form4.exugsotherugsexams1.value;
function passform()
{
divexugsotherugsexams1.innerHTML = document.form4.exugsotherugsexams1.value;
}
The HTML(with just one text field try):
<p><input name="submit4" type="submit" class="button2" id="submit4" value="Preview Note" onClick="openbox('Preview Note', 1)"/>
</p>
<div id="shadowing"></div>
<div id="box">
<span id="boxtitle"></span>
<div id="divexugsotherugsexams1"></div>
<script>document.write('<PARAM name="SRC" VALUE="'+exugsotherugsexams1+'">')</script>
Close
</div>