animate jquery working only once - javascript

I am trying to use a simple animation feature of jquery. In my application, I have two button " Slide Right" and "Slide Left". When we click on these buttons, these move the box to left or right respectively. My move right button is working perfectly but my move right button is working only once. What's wrong with my code? Here's my code:
$(document).ready(function() {
$("#slideRightButton").click(function() {
$("#boxToBeMoved").animate({
left: '+=10%'
});
});
$("#slideLeftButton").click(function() {
$("#boxToBeMoved").animate({
right: '+=10%'
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<button id="slideRightButton">Slide Right</button>
<button id="slideLeftButton">Slide Left</button>
<p>By default, all HTML elements have a static position, and cannot be moved. To manipulate the position, remember to first set the CSS position property of the element to relative, fixed, or absolute!</p>
<div id="boxToBeMoved" style="background:#98bf21;height:100px;width:100px;position:absolute;"></div>
The above code is just an extension of the jquery tutorial by W3Schools which can be found here

You are changing the left and right property of the box, It looks like the right property is taking precedence and preventing the left from doing anything.
If you make both use the same property, one adding to it and the other subtracting, it should work.
$("#slideRightButton").click(function(){
$("div").animate({left: '+=10%'});
});
$("#slideLeftButton").click(function(){
$("#boxToBeMoved").animate({left: '-=10%'});
});

Updated to include author's request to not exceed the maximum width.
To accomplish this, I included a wrapper div with a fixed width.
When sliding to the right, it checks if the value will be bigger than parent's width and, if positive, returns.
Same when sliding to the left, but it returns if the value is negative, preventing the box to slide outside the limits of the parent div.
$(document).ready(function() {
const slideVal = 30; // slide value (in pixels)
$("#slideRightButton").click(function() {
var box = $("#boxToBeMoved");
if (parseInt(box.css("left")) + slideVal > parseInt(box.parent().width())) return;
box.animate({
left: '+=' + slideVal
});
});
$("#slideLeftButton").click(function() {
var box = $("#boxToBeMoved");
if (parseInt(box.css("left")) - slideVal < 0) return;
box.animate({
left: '-=' + slideVal
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<button id="slideRightButton">Slide Right</button>
<button id="slideLeftButton">Slide Left</button>
<p>By default, all HTML elements have a static position, and cannot be moved. To manipulate the position, remember to first set the CSS position property of the element to relative, fixed, or absolute!</p>
<div id="wrapper" style="width: 200px">
<div id="boxToBeMoved" style="background:#98bf21;height:100px;width:100px;position:absolute;"></div>
</div>

Related

Dynamically set scroll coordinates & change DOM element with 200px scroll tolerance from these coordinates

I've got a single page site with two div modules that expand when clicked.
The first is at the top, in the Hero section and with the current code works as desired. The second is much further down the page in another section. Currently this second module closes as soon as the scroll takes place.
What I need to do is get the documents scroll coordinates when the div is clicked. Then once the user scrolls 200px up or down the div closes back up. Regardless of where it (the div) is on the site.
All the questions I found here and elsewhere only refer to setting the scroll tolerance relative to the window position on page load. But for me that's no goon. This site is responsive, and as it changes the initial positions of the div's will / can be unknown. I need someway of dynamically storing the viewports scroll position when the div's are clicked and assigning the 200px tolerance then.
I hope that makes sense. I've been at this for like 12+hrs now. SOS :)
Here's the Fiddle
If you don't want to go over to Fiddle, Here's the requisite code
HTML:
<body>
<section id="hero">
<div>
<div class="module-cta hero-cta">
<a class="module-cta__button"><!-- Fallback location -->
<span class="module-cta__text">PRESS ME</span>
</a>
<div class="module-cta__open">
<div class="module-cta__open-inner">
<div class="hero-cta__contact-points">
<div class="phone">
<div class="hero-cta_contact_logo">
<span><!-- phone.svg" --></span>
</div><!-- .service-logo -->
<div class="contact_trigger">
<a>Scroll down to 200px to see</a>
</div><!-- .contact_trigger -->
</div><!-- .phone -->
<div class="email">
<div class="hero-cta_contact_logo">
<span><!-- email.svg --></span>
</div><!-- .service-logo -->
<div class="contact_trigger">
<a>this div fold back up</a>
</div><!-- .contact_trigger -->
</div><!-- .email -->
</div><!-- .hero-cta__contact-points -->
<button class="module-cta__close module-cta__cancel"><i class="icon"><span></span></i></button>
</div><!-- .hero-cta__open-inner -->
</div><!-- .hero-cta__open -->
</div><!-- .hero-cta -->
</div>
</section>
<section class="spacer"></section>
<section id="service_area">
<div class="area_input">
<div class="module-cta area-cta wow fadeInUp" id="form_module">
<a class="module-cta__button area-cta__button">
<span class="module-cta__text area-cta__text">NOW PRESS ME</span>
</a>
<div class="module-cta__open area-cta__open">
<div class="module-cta__open-inner area-cta__open-inner">
<div class="area-cta__search">
<form class="postcode_form" id="postcode_form" name="postcode_form" action="#">
<input type="number" id="your_postcode" class="your_postcode" name="postcode" placeholder="3???">
<button type="button" class="area-btn"><span></span></button>
<a class="call-now">##########</a>
</form>
</div><!-- .area-cta__search -->
<button class="module-cta__close module-cta__cancel"><i class="icon"><span></span></i></button>
</div><!-- .area-cta__open-inner -->
</div><!-- .area-cta__open -->
</div><!-- .area-cta -->
</div><!-- .area_input -->
</section>
<section class="spacer"></section>
</body>
Script:
I'm sure a lot of this can be cleaned up and shrunk, but for now I'm just trying to get it all going.
// opens & closes modules by clicking module name
$('.module-cta__button').on('click', function(){
if($(this).parent().hasClass('hero-cta')){
$(this).parent().toggleClass('module-cta--active');
} else {
if($(this).parent().hasClass('area-cta')){
$(this).parent().toggleClass('module-cta--active');
}
}
});
// closes modules with .module-cta__close btn
$('.module-cta__close').on('click', function(){
if($(this).closest('div .module-cta').hasClass('module-cta--active')){
$(this).closest('div .module-cta').removeClass('module-cta--active');
}
});
// closes modules on scroll.
// * works but doesn't apply scroll tolerance of 200px for #area
$(window).scroll(function(){
var currentPos = $(window).scrollTop();
var module = $('div .module-cta');
if(module.hasClass('module-cta--active') && module.position().top <= currentPos+200){
$('div .module-cta--active').removeClass('module-cta--active');
}
});
// closes modules when escape key is pressed
$(window).keydown(function(escape){
var key = escape.which;
if(key == 27){
$('div .module-cta--active').removeClass('module-cta--active');
}
});
see Fiddle for css
Thanks for any help or useful suggestions in advanced.
I've put together a much smaller and simpler demonstration, just to show you what variables you need to accomplish this. Essentially, when a div is clicked, capture the current document scroll position using $(document).scrollTop(). Also store a refference to the current div that has been clicked.
When scrolling, check the difference between the current scroll and the new scroll, and using your clicked div reference, shrink the div when the difference is 200 or greater. JS fiddle below;
https://jsfiddle.net/jLqu4pas/
Code from Fiddle;
var currentScroll;
var lastClickedDiv;
$('section').click(function(){
$(this).css({'height' : '400'})
currentScroll = $(document).scrollTop();
lastClickedDiv = $(this);
console.log(currentScroll);
})
$(window).scroll(function(){
if($(document).scrollTop() > currentScroll + 200){
lastClickedDiv.css({'height' : 0})
}
})
So I've put together a script that will potentially help you.
I've done some basic testing on it, but if you come across any problems make a comment.
// Generate offsets and return them as an object
function generateOffsets($element, tolerance)
{
var offsets = $element.offset(),
offsetTop = offsets.top;
return {
scrollPos: offsetTop,
toleranceTop: offsetTop - tolerance,
toleranceBottom: offsetTop + tolerance
};
}
// Run a callback when the user leaves the scroll tolerance of a set of elements
function closeOnScroll($elements, tolerance, callback)
{
$elements.each(function() {
var $element = $(this),
offsets = generateOffsets($element, tolerance),
resizeEvent;
// On resize, regenerate the offsets so they stay up to date
$(window).on('resize', function(e) {
resizeEvent = e;
offsets = generateOffsets($element, tolerance);
});
// On scroll check if we've left the tolerance area, if so run the event and unbind
$(window).on('scroll', function(e) {
var windowPos = $(this).scrollTop();
if (windowPos < offsets.toleranceTop || windowPos > offsets.toleranceBottom) {
callback($element);
$(this).unbind(e);
$(this).unbind(resizeEvent);
}
});
});
}
// Example: Apply the event to a set of elements
$('.btn').click(function() {
closeOnScroll($('div .module-cta'), 200, function($element) {
$element.removeClass('module-cta--active');
});
});
The thing to remember with thie script is that it needs to be applied EVERY time the user clicks your button. You may say, WHY WOULD YOU DO THAT - but it actually has some serious performance implications.
The events rely on both scroll and resize, both of which are very slow, especially if not debounced like in this script. However, what I do in the script is unbind the events once it has occured. Otherwise, the resize and scroll would keep happening for each and every one of your buttons until the end of time. By 'unbinding' the event, you ensure long running performance of your page.
Wouldn't want to ruin those pretty animations would we?

How to use jQuery .hover() in combination with Overflow

Well, i am stucked and can't find the answer myself. Hopefully someone can give me a hint.
I try to fullfill the following requirements:
There should be a Newsblock within a HTML Page with a fixed width and
height.
In this Newsblock only the title of the news are visible.
Those news are "collapsed" by default and should "expand" if the Mouse is over it.
Due the fact that the 'Newsblock' is limited by its height, there should be a Scrollbar visible. But only if the currently expanded news makes it necessary, so the user can Scroll down.
Newstitle and Newstext should never leave the Newsblock.
so far so good, i was able to fullfill all those demands except the one with the Scrollbar. If i try to reach the Scrollbar out of the currently expanded news it collapses again and the Scrollbar disappears. I understand that my .hover is configured that it always SlideUp if i leave the newsentry and the Scrollbar isn't a part of the newsentry div. But i have no idea what to change to still have an overall Scrollbar for the Newsblock, but won't disappear if i try to 'reach' it.
P.s.: A Scrollbar only per Newsentry looks weird. Thats why i want 'bind' the scrollbar to the parent container :S
HTML
<div id="newsblock">
<div> // some auto generated div's i have to life with, so the news entries are not 'direct' children of the newsblock.
<div class="newsentry">
<div class="newstitle">...</div>
<div class="newstext">...</div>
</div>
... another 9 'newsentry' divs.
</div>
</div>
JS
$(".newsentry").hover(
function() {
$(this).children(".newstext").stop(true,true).slideDown();
},
function() {
$(this).children(".newstext").stop(true,true).slideUp();
}
);
CSS
.newsblock {
height: 200px;
overflow-y: auto;
}
Instead of closing a .newsentry when the cursor goes out of it, a solution can be to close it only when it enters another .newsentry or when it leaves #newsblock.
The scrollbar being part of #newsblock, the entry isn't closed anymore when you go on it.
EDIT: Following our discussion about the scroll issue, I added a step callback to the closing animation to make sure that the top of the .newsentry getting opened remains visible when the other entries are getting closed.
Here is a working example:
var $newsblock = $("#newsblock");
function closeAllNews(slideUpArgs){
return $(".newstext").stop(true).slideUp(slideUpArgs);
}
function openNews(news, slideDownArgs){
$(news).find(".newstext").stop(true).slideDown(slideDownArgs);
}
function ensureNewsTopVisible(news){
// Check if the top of the newsentry is visible...
var top = $(news).position().top;
if(top < 0){
// ...and if not, scroll newsblock accordingly.
$newsblock.scrollTop($newsblock.scrollTop() + top);
}
}
$(".newsentry").each(function(){
var $this = $(this);
// When the mouse enter a news entry...
$this.on("mouseenter", function(){
// ...close all opened entries (normally there is at most one)...
closeAllNews({
// (while making sure that the top of this entry remains visible
// at each step)
step: ensureNewsTopVisible.bind(null, $this)
});
// ...open this newsentry.
openNews($this);
});
});
// When the mouse get out of the newsblock, close all news.
$newsblock.on("mouseleave", closeAllNews);
.newstitle {
font-size: 2em;
}
.newstext {
display: none;
}
#newsblock {
max-height: 150px;
overflow: scroll;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="newsblock">
<div>
<div class="newsentry">
<div class="newstitle">News 1</div>
<div class="newstext"></div>
</div>
<div class="newsentry">
<div class="newstitle">News 2</div>
<div class="newstext"></div>
</div>
<div class="newsentry">
<div class="newstitle">News 3</div>
<div class="newstext"></div>
</div>
<!-- Etc. -->
</div>
</div>
<!-- Ignore the script below. It is just filling in the news' text. -->
<script>
$(".newstext").each(function(i, newstext){
$.get("http://baconipsum.com/api/?type=meat-and-filler&format=html&paras=5&num=" + i)
.then(function(ipsumHtml){
$(newstext).html(ipsumHtml);
});
});
</script>
Try this:
$(".newsentry, .newsblock").hover( // <-- changed
function() {
$(this).children(".newstext").stop(true,true).slideDown();
},
function() {
$(this).children(".newstext").stop(true,true).slideUp();
}
);
This makes sure the block stays open when you hover either over the header or the block itself.
Is that what you mean?
There would be a joke , if i am wrong .. what i thing just change your css as
/* not .newsblock **/
#newsblock {
height: 200px;
overflow-y: scroll;/* not auto*/
}
It will be a lot better if you use click operation instead of hover to slide down news text block because the user can accidentally hover over any of the news entry in order to reach for the scroll bar. I think you need a accordion like functionality. You can use the below code if you are fine with click instead of hover.
$(".newsentry").click(
function() {
$(".newstext").stop(true,true).slideUp();
$(this).children(".newstext").stop(true,true).slideDown();
}
);
Or use the below one to go with hover.
$(".newsentry").hover(
function() {
$(".newstext").stop(true,true).slideUp();
$(this).children(".newstext").stop(true,true).slideDown();
},
function(){}
);
This will not close the news text block until you accidentally hover over another news entry.

Set parent div height to content that is not overflowing

I have a slider that's in place on my website.
The basic way that it works is depicted in this jsfiddle -
http://jsfiddle.net/6h7q9/15/
I've written code to set the parent's height to the height of the content div. This worked fine, until I introduced some content that did not have a fixed height and whose height might increase while it was being shown on the page. Is there a way, I can dynamically change the height of this parent div whenever content inside it increases or decreases it's height.
HTML -
<div id="slider_container">
<div id="slider">
<div id="slide1">
Has content that might increase the height of the div....
</div>
<div id="slide2">
Has content that might increase the height of the div....
</div>
<div id="slide3">
Has content that might increase the height of the div....
</div>
</div>
</div>
<input type="button" value="Next" id="btnNext">
<input type="button" value="Previous" id="btnPrev">
<input type="button" value="Add text" id="btnAddText">
<div class="footer">
I appear after the largest container, irrespective of which one is present....
</div>
JavaScript -
var currSlider = 1;
$('#btnNext').click(function(){
debugger;
var margin = $('#slider').css('margin-left');
if(parseInt(margin) <= -400) {
return;
}
currSlider++;
// Moving the slider
$('#slider').css('margin-left', parseInt(margin) - 200 + 'px');
// Resetting the height...
$('#slider').height($('#slide' + currSlider).height());
});
$('#btnPrev').click(function(){
debugger;
var margin = $('#slider').css('margin-left');
if(parseInt(margin) >= 0) {
return;
}
currSlider--;
// Moving to the previous slider
$('#slider').css('margin-left', parseInt(margin) + 200 + 'px');
// Resetting the height...
$('#slider').height($('#slide' + currSlider).height());
});
$('#btnAddText').click(function() {
$('#slide' + currSlider).text('Hello World'.repeat(100));
});
String.prototype.repeat = function(times) {
return (new Array(times + 1)).join(this);
};
I hope this "answer" gets you going in the right direction. Since i don't have the time to fully look this up right now, i hope to send you in the right direction. if you do find out how to do this properly, please shoot me a message, since i would really like to know ^_^
http://www.w3.org/TR/DOM-Level-3-Events/#legacy-event-types
An example on how to use: (DOMSubtreeModified didn't work in IE from what i read. Therefor the propertchange event)
$('#slide1').on('DOMSubtreeModified propertychange', function() {
console.log('test',this);
});
Another option is by using the MutationObserver:
http://updates.html5rocks.com/2012/02/Detect-DOM-changes-with-Mutation-Observers
https://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#mutation-observers
Updated 6-8-2014 15:00 CET
Since i totally misread the original post, this answer was useless to say the best. But since the problem is actually really easy to solve (or... at least i hope i understand the problem this time), i thought i'd post an answer that worked for the situation: a slider with content of different heights.
What was the problem with the original slider? You moved the content out of the container, which made it hidden. However, the container would still pick up the height of it, since it only had a fixed width. The fixed height on the '#slider' did not prevent the container of picking up the height from the '#slide-*'. Had you set the height for the container... all would be fine :-)
Here's the outline of the hidden slide, moved 'off canvas': http://i.gyazo.com/f2404e85263a7209907fdbc8f9d8e34e.png
I did not fix your fiddle by completing your code. I just rewrote it to provide you with an easier to maintain slider. Here's a fiddle with a working slider where you can add and remove stuff in the slides: http://jsfiddle.net/3JL2x/3/
Just remove the height properties in the .slide1, 2 and 3 and add min-height instead.
Like that :
#slider > div {
min-height:200px;
float:left;
width : 200px;
}
#slide1 {
background-color : red;
}
#slide2 {
background-color: green;
}
#slide3 {
background-color: blue;
}
Live example
http://jsfiddle.net/6h7q9/27/

Jquery clickable resize animation. Maximizing div over others

I can't come up with solution to my problem.
So I've got cool idea to make fancy looking user panel but can't figure out how to
make jquery work right ;). Here's the thing:
html:
<div id="content">
<div id="containerleft">
<div id="box1" class="box"></div>
<div id="box2" class="box"></div>
<div id="box3" class="box"></div>
<div id="box4" class="box"></div>
<div id="box5" class="box"></div>
<div id="box6" class="box"></div>
</div>
</div>
JS:
$(".box").click(function(){
$(this).css({'position' : 'absolute'}).animate({
width: '100%',
height : '100%'},300);
});
Here is how it work with css:
http://jsfiddle.net/85mJN/1/
What I'm trying to achieve is resize div from his position, to size of parent div, growing effect I would call.
As you can see, after .click div is moving to the left top corner, and then its fiting to parent, also its ruing whole thing by moving other guys. I've tried to mess around with .css('z-index': '999') for animated div, but that was a miss. Main goal is to expand div from his original position, above other div's, without moving them.
~ sandman
$(".box").click(function(){
var clone = $(this).clone().addClass('active');
var parent = $(this).parent();
var pos = $(this).position();
$(this).append(clone);
clone.css({'position' : 'absolute', left: pos.left + 'px', top: pos.top + 'px'}).animate({
width: '100%',
height : '100%',
top: 0,
left: 0
},300);
});
http://jsfiddle.net/85mJN/3/
Note that your box element should have static position so the appended box absolute position will be wrapped from the container.
UPDATE:
Added close on click while a box is active.
http://jsfiddle.net/85mJN/4/
ALSO i still think the best way to use CSS3 transition with toggleClass. It requires less code, it's much failsafe and it's smoother when your using complex divs as it's hardware accelerated. I would not worry about older browser, they won't animate but show the big box...
The movement shown in your example is a product of removing the clicked on div from the flow and then the other divs readjusting since they are floated.
A simple solution is to make the #containerleft{ overflow:hidden; ... }
However if that doesn't satisfy your needs making a clone works as well:
$('#containerleft').on("click", ".box", function(){
var $this = $(this);
console.log($this.css('position'));
if($this.css('position') === 'absolute'){
$this.animate({width:'0px',height:'0px'},300);
//$this.remove();
}
else {
$this.clone().appendTo($this.parent()).css({'position' : 'absolute'}).animate({
width: '100%',
height : '100%'},300);
}
});
http://jsfiddle.net/e4NG5/2/

Trying to write a script to push a box using mouse pointer in JavaScript

I'm in the beginning of learning JavaScript, and trying to write a script that allows the user to push a box left and right using mouse pointer.
I managed to work it out when the pointer touches the left side of the box, but I'm facing two problems here:
When the pointer gets inside the box, the box jumps to the new coordinate. I want the box to stay in it's position when the pointer gets inside the box.
I really can't figure it out when the mouse touches the right side of the box. I want the box to get pushed left. I've made a box.offsetRight property to help me out but just can't use it efficiently.
Here's a picture to demonstrate what I mean:
The "X" mark is where the pointer is. And heading toward the right side of the box. How to push the box to the left ?
Here's what i've tried to do (it didn't work of course) :
index.html
<html>
<head>
<title>Chase the box</title>
<style>
body {
}
.css-box{
position: absolute ;
top:20px;
width : 100px;
height : 100px;
background-color : blue;
}
.css-textbox{
margin-top: 500px;
}
</style>
</head>
<body>
<div id="box" class="css-box"></div>
<div class="css-textbox">
<p>All : <input id="allTextbox" type="text"></input></p>
<p>Left : <input id="leftTextbox" type="text"></input></p>
<p>Right : <input id="rightTextbox" type="text"></input></p>
<p>e.pageX(Left) : <input id="pageXTextbox" type="text"></input></p>
<p>e.pageX(Right) : <input id="pageXRightTextbox" type="text"></input></p>
</div>
<script type="text/javascript" src="helper.js"></script>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
script.js
var box = document.getElementById("box");
var allTextbox = document.getElementById("allTextbox");
var leftTextbox = document.getElementById("leftTextbox");
var rightTextbox = document.getElementById("rightTextbox");
var pageXTextbox = document.getElementById("pageXTextbox");
var PageXRightTextbox = document.getElementById("pageXRightTextbox");
Object.prototype.offsetRight = window.innerWidth - (box.offsetWidth + box.offsetLeft);
var pushBox = function(e){
var pageXRight = window.innerWidth - e.pageX;
box.offsetRight = window.innerWidth - (box.offsetWidth + box.offsetLeft);
if (e.pageX >= box.offsetLeft){
box.style.left = e.pageX + "px";
} else if(pageXRight >= box.offsetRight){
box.style.right = pageXRight + "px";
}
allTextbox.value = window.innerWidth;
leftTextbox.value = box.offsetLeft;
rightTextbox.value = box.offsetRight;
pageXTextbox.value = e.pageX;
pageXRightTextbox.value = pageXRight;
};
box.addEventListener("mousemove" , pushBox);
I hope to find an answer using JavaScript not jQuery.
Possible idea for you. Sounds like some carousels I've coded up in AS3.
When mouse over the div container for the box you start checking mouse position on a timer (fairly fast).
using mouse X, div width, box width you can calculate if the mouse is on the left or the right of the box. You probably want ranged hit area on both sides of the box so that it moves when mouse hits that to new position. (I assume your box is position relative css inside its container which will allow css:left and css:right to be animated via document.getElementById("xxx").style
Careful when box gets to left and right side limits as you still want a hit area.
I would suggest creating a few text boxes for number outputs so you can see how numbers change when your timer function is checking mouse positions etc and then you should be able to make the calculations.
Hope this helps.

Categories

Resources