Glitch while animating the dynamically added elements - javascript

Glitch is seen when we add step and heading dynamically and try to swap their postion using up and down arrow for moving up and down respectively.
Html:
<div class="makeit_steps"></div>
<div class="row margin-top">
<div class="col-md-12">
<div class="col-md-2">
<span class="glyphicon glyphicon-plus-sign"></span>
<span id="add-step" class="add-new">Add Step</span>
</div>
<div class="col-md-2">
<span class="glyphicon glyphicon-plus-sign"></span>
<span id="add-heading" class="add-new">Add Heading</span>
</div>
</div>
</div>
JavaScript:
Adding step dynamically:
$('#add-step').click(function () {
$('.makeit_steps').append('<div class="row moving"><div class="col-md-12"><span class="steps">Step</span><span><textarea class="form-control" rows="3" cols="105"></textarea></span><span class="glyphicon glyphicon-circle-arrow-up"></span><span class="glyphicon glyphicon-circle-arrow-down"></span><span class="step_remove">X</span></div></div>');
$('.step_remove').click(function () {
$(this).closest('.moving').remove();
});
$(".glyphicon-circle-arrow-up").click(function () {
var $current = $(this).closest('.moving')
var $previous = $current.prev('.moving');
distance = $current.outerHeight();
if ($previous.length !== 0) {
$.when($current.animate({
top: -distance
}, 600),
$previous.animate({
top: distance
}, 600)).done(function () {
$previous.css('top', '0px');
$current.css('top', '0px');
$current.insertBefore($previous);
});
}
return false;
});
$(".glyphicon-circle-arrow-down").click(function () {
var $current = $(this).closest('.moving')
var $next = $current.next('.moving');
distance = $current.outerHeight();
if ($next.length !== 0) {
$.when($current.animate({
top: distance
}, 600),
$next.animate({
top: -distance
}, 600)).done(function () {
$next.css('top', '0');
$current.css('top', '0');
$current.insertAfter($next);
animating = false;
});
}
return false;
});
});
Adding heading dynamically:
$('#add-heading').click(function () {
$('.makeit_steps').append('<div class="row moving"><div class="col-md-12"><span class="step_heading">Heading</span><span><input type="text" ></input></span><span class="glyphicon glyphicon-circle-arrow-up"></span><span class="glyphicon glyphicon-circle-arrow-down"></span><span class="step_remove">X</span></div></div>')
$('.step_remove').click(function () {
$(this).closest('.row').remove();
});
var animating = false;
$(".glyphicon-circle-arrow-up").click(function () {
if (animating) {
return;
}
var $current = $(this).closest('.moving')
var $previous = $current.prev('.moving');
distance = $current.outerHeight(true);
if ($previous.length !== 0) {
animating = true;
$.when($current.animate({
top: -distance
}, 600),
$previous.animate({
top: distance
}, 600)).done(function () {
$previous.css('top', '0px');
$current.css('top', '0px');
$current.insertBefore($previous);
animating = false;
});
}
});
$(".glyphicon-circle-arrow-down").click(function () {
if (animating) {
return;
}
var $current = $(this).closest('.moving')
var $next = $current.next('.moving');
distance = $current.outerHeight();
if ($next.length !== 0) {
animating = true;
$.when($current.animate({
top: distance
}, 600),
$next.animate({
top: -distance
}, 600)).done(function () {
$next.css('top', '0');
$current.css('top', '0');
$current.insertAfter($next);
animating = false;
});
}
});
});
CSS
.margin-top {
margin-top:20px;
}
.glyphicon.glyphicon-circle-arrow-up, .glyphicon.glyphicon-circle-arrow-down {
font-size:30px;
margin-left:25px;
cursor:pointer;
}
.add-new {
color:#007acc;
cursor:pointer;
}
.steps {
font-size:16px;
padding-left:30px;
padding-right:20px;
}
.step_remove {
font-size:16px;
color:#007acc;
margin-left:15px;
cursor:pointer;
}
.step_heading {
padding-left:15px;
font-size:16px;
padding-right:10px;
}
.makeit_steps {
position: relative;
}
.makeit_steps .moving {
position:relative;
}
.moving span {
display:inline-block;
vertical-align: middle;
}
Fiddle:Here

The problem with your code currently is that it is binding the click event multiple times on the up and down arrows (existing ones) whenever you create dynamically a new one.
In order to attach the click event only on the newly appended element you should make an object of the new element to be added and then you can use it further
var el = $('<div class="row moving"><div class="col-md-12"><span class="steps">Step</span><span><textarea class="form-control" rows="3" cols="105"></textarea></span><span class="glyphicon glyphicon-circle-arrow-up"></span><span class="glyphicon glyphicon-circle-arrow-down"></span><span class="step_remove">X</span></div></div>');
$('.makeit_steps').append(el);
After appending the new element the need is to assign the click event on up and down arrows for that , you should do this way
For Up arrow
$('.glyphicon glyphicon-circle-arrow-up',el).on('click',function(){
For down arrow
$('.glyphicon-circle-arrow-down',el).on('click',function(){
you can see the e1 object used when applying the click event.
The above lines will search for the up and down arrows only within the new element appended and will assign the event.
The working demo is here - http://jsfiddle.net/m86p420h/7/

Related

Switch classes on click next or back

I'm trying to setup multiple-step form in which the first step is visible by default and rest of the steps are hidden with class "hide". I'd like to switch the class with Next and Back button so only one step is visible at a time. Could you please help with this (Already spent an hour on this)
<div class="steps">
<div class="step1">step1</div>
<div class="step2 hide">step2</div>
<div class="step3 hide">step3</div>
<div class="step4 hide">step4</div>
</div>
<div class="back">Back</div>
<div class="next">Next</div>
$('.next').click(function(){
$('div:not(.hide)').next().removeClass('hide');
$('.hide').prev().removeClass('hide')
})
Try combining the 2 actions into one, like so:
$('.next').click(function(){
$('.steps div:not(.hide)').addClass('hide').next().removeClass('hide');
})
That way, you add the .hide class on your current div and then remove it on the next one.
You can use something similar for the Back button, by replacing .next() with .previous()
$('.next').click(function() {
// find the div that is not hidden
var $current = $('.steps div:not(.hide)');
// only perform logic if there is a proceeding div
if ($current.next().length) {
// show the next div
$current.next().removeClass('hide');
// hide the old current div
$current.addClass('hide')
}
});
$('.back').click(function() {
// find the div that is not hidden
var $current = $('.steps div:not(.hide)');
// only perform logic if there is a preceeding div
if ($current.prev().length) {
// show the previous div
$current.prev().removeClass('hide');
// hide the old current div
$current.addClass('hide')
}
});
.hide { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="steps">
<div class="step1">step1</div>
<div class="step2 hide">step2</div>
<div class="step3 hide">step3</div>
<div class="step4 hide">step4</div>
</div>
<div class="back">Back</div>
<div class="next">Next</div>
You can add a current step variable to track the currently displayed step and two css for styling and showing your content.
jQuery(function($) {
let currentstep = 1;
let maxsteps = 4;
function showstep(step) {
let step_c = '.step' + step;
for (i = 1; i <= maxsteps; i++) {
var step_selector = '.step' + i;
$(step_selector).removeClass('show');
$(step_selector).addClass('hide');
}
$(step_c).removeClass('hide');
$(step_c).addClass('show');
};
$('.next').click(function() {
currentstep = currentstep + 1;
currentstep = (currentstep % (maxsteps + 1));
if (currentstep == 0) currentstep = 1;
showstep(currentstep);
});
$('.back').click(function() {
currentstep = currentstep - 1;
currentstep = (currentstep % (maxsteps + 1));
if (currentstep == 0) currentstep = 4;
showstep(currentstep);
});
});
.hide {
display: none;
}
.show {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="steps">
<div class="step1 show">step1</div>
<div class="step2 hide">step2</div>
<div class="step3 hide">step3</div>
<div class="step4 hide">step4</div>
</div>
<div class="back">Back</div>
<div class="next">Next</div>
I converted Taplar's answer to a jQuery plugin.
You are essentially navigating left or right by one, using the previous and next functions. These functions navigate through the sibling elements.
(function() {
$.fn.moveRight = function(className) {
var $curr = this.find('div:not(.' + className + ')');
if ($curr.next().length) $curr.next().removeClass(className);
else this.find('div:first-child').removeClass(className);
$curr.addClass(className);
return this;
};
$.fn.moveLeft = function(className) {
var $curr = this.find('div:not(.' + className + ')');
if ($curr.prev().length) $curr.prev().removeClass(className);
else this.find('div:last-child').removeClass(className);
$curr.addClass(className);
return this;
};
})(jQuery);
$('.next').on('click', (e) => $('.steps').moveRight('hide'));
$('.back').on('click', (e) => $('.steps').moveLeft('hide'));
.hide {
display: none;
}
.nav {
width: 260px;
text-align: center;
}
.nav .nav-btn::selection { background: transparent; }
.nav .nav-btn::-moz-selection { background: transparent; }
.nav .nav-btn {
display: inline-block;
cursor: pointer;
}
.steps {
width: 260px;
height: 165px;
border: thin solid black;
text-align: center;
line-height: 165px;
font-size: 3em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="steps">
<div class="step1">step1</div>
<div class="step2 hide">step2</div>
<div class="step3 hide">step3</div>
<div class="step4 hide">step4</div>
</div>
<div class="nav">
<div class="nav-btn back">[ << Back ]</div>
<div class="nav-btn next">[ Next >> ]</div>
</div>

Javascript, JQuery Previous button

I need some help with this code. I want to create an event click button for previous. How can I do this using a little code? some thing similar to my Next button click event.
Here is my full code.
$(document).ready(function() {
var nextSlide = $("#slides img:first-child");
var nextCaption;
var nextSlideSource;
var counter = 0;
// the function for running the slide show
var runSlideShow = function() {
$("#caption").fadeOut(1000);
$("#slide").fadeOut(1000,
function () {
if (nextSlide.next().length === 0) {
nextSlide = $("#slides img:first-child");
}
else {
nextSlide = nextSlide.next();
}
nextSlideSource = nextSlide.attr("src");
nextCaption = nextSlide.attr("alt");
$("#slide").attr("src", nextSlideSource).fadeIn(1000);
$("#caption").text(nextCaption).fadeIn(1000);
}
);
};
// start the slide show
var timer = setInterval(runSlideShow, 3000);
$("#play").on("click", function() {
if($(this).val() === "Pause") {
clearInterval(timer);
$(this).val("Play");
$("#prev").prop("disabled", false);
$("#next").prop("disabled", false);
}
else if ($(this).val() === "Play") {
timer = setInterval(runSlideShow, 3000);
$(this).val("Pause");
$("#prev").prop("disabled", true);
$("#next").prop("disabled", true);
}
});
var imag = $("#slides img").index();
var imageSize = $("#slides img").length - 1;
$("#next").on("click", function (e) {
e.preventDefault();
if (imag === imageSize) {
$("#next").prop("disabled", true);
}
else {
++imag;
runSlideShow(1);
}
});
});
body {
font-family: Arial, Helvetica, sans-serif;
width: 380px;
height: 350px;
margin: 0 auto;
padding: 20px;
border: 3px solid blue;
}
h1, h2, ul, p {
margin: 0;
padding: 0;
}
h1 {
padding-bottom: .25em;
color: blue;
}
h2 {
font-size: 120%;
padding: .5em 0;
}
img {
height: 250px;
}
#slides img {
display: none;
}
#buttons {
margin-top: .5em;
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Slide Show</title>
<link rel="stylesheet" href="main.css">
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="slide_show.js"></script>
</head>
<body>
<section>
<h1>Fishing Slide Show</h1>
<h2 id="caption">Casting on the Upper Kings</h2>
<img id="slide" src="images/casting1.jpg" alt="">
<div id="slides">
<img src="images/casting1.jpg" alt="Casting on the Upper Kings">
<img src="images/casting2.jpg" alt="Casting on the Lower Kings">
<img src="images/catchrelease.jpg" alt="Catch and Release on the Big Horn">
<img src="images/fish.jpg" alt="Catching on the South Fork">
<img src="images/lures.jpg" alt="The Lures for Catching">
</div>
<div id="buttons">
<input type="button" id="prev" value="Previous" disabled>
<input type="button" id="play" value="Pause">
<input type="button" id="next" value="Next" disabled>
</div>
</section>
</body>
</html>
I thought of during it this way, but that is not working.
$("#prev").on("click", function () {
if (imag === imageSize) {
$("#prev").prop("disabled", true);
}
else {
++imag;
runSlideShow(-1);
}
});
Something similar to this Next button click event.
$("#next").on("click", function (e) {
e.preventDefault();
if (imag === imageSize) {
$("#next").prop("disabled", true);
}
else {
++imag;
runSlideShow(1);
}
});
Any help please.
test my idea =)
var mySlide = function(){
var index = 0;
var timer = false;
var self = this;
self.data = [];
self.start = function(){
timer = setInterval(self.next, 3000);
return self;
};
self.stop = function(){
clearInterval(timer);
timer = false;
return self;
};
self.pause = function(){
if(timer == false){
self.start();
} else {
self.stop();
}
};
self.next = function(){
if(self.data.length > 0){
self.stop().start(); // reset the timer
index++;
self.update();
}
};
self.prev = function(){
if(self.data.length > 0 && index > 0){
self.stop().start(); // reset the timer
index--;
self.update();
}
};
self.update = function(){
var item = self.data[index % self.data.length]; // calculating the value of INDEX
$('.print').fadeOut(1000,function(){
$(this).html(item).fadeIn(1000);
});
};
}
// RUN CODE!
var test = new mySlide();
test.data = [ // LOAD ITEM!
'food',
'bar',
$('<img/>').attr('src','https://www.google.it/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png')
];
test.start().update(); // START!
$('.prev').click(test.prev); // add event!
$('.pause').click(test.pause);
$('.next').click(test.next);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="print"></div>
<input type="button" value="prev" class="prev">
<input type="button" value="pause" class="pause">
<input type="button" value="next" class="next">

jQuery bind / unbind not working

I'm trying to create a simple slider. Here is a example but slider next and prev button not working properly.
// next
var next = $('.next').click(function() {
var storepos = $(".storepos").val();
$('.prev').bind('click');
$('.storepos').val($('.storepos').val() / 1 + 110);
$('.container').animate({
scrollLeft: $('.storepos').val()
}, 200);
});
//prev
$('.prev').click(function() {
var storepos = $(".storepos").val();
$('.next').bind('click');
$('.storepos').val($('.storepos').val() / 1 - 110);
$('.container').animate({
scrollLeft: $('.storepos').val()
}, 200);
});
//after scrollend right event
$('.container').bind('scroll', function() {
if ($('.container').scrollLeft() + $(this).innerWidth() >= $(this)[0].scrollWidth) {
$('.next').unbind('click');
}
});
//after scrollend left event
$('.container').bind('scroll', function() {
if ($('.container').scrollLeft() < 1) {
$('.prev').unbind('click');
}
});
.container {
overflow: hidden !important
}
.container::-webkit-scrollbar {
width: 0;
height: 0
}
.content {
width: 1600px
}
.items {
background: black;
color: white;
margin-left: 10px;
width: 100px;
height: 100px;
float: left;
text-align: center
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="content">
<div class="items">1</div>
<div class="items">2</div>
<div class="items">3</div>
<div class="items">4</div>
<div class="items">5</div>
<div class="items">6</div>
<div class="items">7</div>
<div class="items">8</div>
<div class="items">9</div>
<div class="items">10</div>
</div>
</div>
Prev / Next
<input class="storeposx" value="" />
<input class="storepos" value="" />
fiddle
I see two errors. First, the previous button is active from the begging, enabling scrolling to negative values. Second, you do unbind the events when reaching the end both sides, but you're not bind them back after that.
I used two variables where I keep the buttons status. When I reach the start or end position I don't unbind them, instead I just return false on click.
// next
var next = $('.next').click(function() {
if (!nextIsActive || $('.container').is(':animated')) return false;
var storepos = $(".storepos").val();
$('.prev').bind('click');
$('.storepos').val($('.storepos').val() / 1 + 110);
$('.container').animate({
scrollLeft: $('.storepos').val()
}, 200);
});
//prev
$('.prev').click(function() {
if (!prevIsActive || $('.container').is(':animated')) return false;
var storepos = $(".storepos").val();
$('.next').bind('click');
$('.storepos').val($('.storepos').val() / 1 - 110);
$('.container').animate({
scrollLeft: $('.storepos').val()
}, 200);
});
var nextIsActive=true;
var prevIsActive=false;
//after scrollend right event
$('.container').bind('scroll', function() {
if ($('.container').scrollLeft() + $(this).innerWidth() >= $(this)[0].scrollWidth) {
nextIsActive=false;
}else{
nextIsActive=true;
}
});
//after scrollend left event
$('.container').bind('scroll', function() {
if ($('.container').scrollLeft() < 1) {
prevIsActive=false;
}else{
prevIsActive=true;
}
});
.container{overflow:hidden !important}
.container::-webkit-scrollbar {
width:0;
height:0
}
.content {width:1600px}
.items { background:black;
color:white;
margin-left:10px;
width:100px;
height:100px;
float:left;
text-align:center
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="content">
<div class="items">1</div>
<div class="items">2</div>
<div class="items">3</div>
<div class="items">4</div>
<div class="items">5</div>
<div class="items">6</div>
<div class="items">7</div>
<div class="items">8</div>
<div class="items">9</div>
<div class="items">10</div>
</div>
</div>
Prev / Next
<input class="storeposx" value="" />
<input class="storepos" value="" />

Show/hide a div 500 px from top and 500 px before bottom

I have a page where I want an image to appear after scrolling say 500px and I used the "If you want to show a div after scrolling a number of pixels, WITHOUT jquery" code snippet from apaul34208 (show div after 800px scroll). My adapted code is like this:
<!DOCTYPE html>
<html>
<body>
<div id="myID" class="pointer hide">
<img src="image.png">
</div>
<script>
myID = document.getElementById("myID");
var myScrollFunc = function () {
var y = window.scrollY;
if (y >= 400) {
myID.className = "pointer show"
} else {
myID.className = "pointer hide"
}
};
window.addEventListener("scroll", myScrollFunc);
</script>
</body>
</html>
and CSS:
.hide {
display: none;
}
.show {
display: block;
margin-top: -80px;
}
Only problem is that I would also like it to DISAPPEAR again lets say 400 px from the bottom of the page. the page-height differs from page to page so I cant just set a range like underneath from say 400-1000 px.
<script>
myID = document.getElementById("myID");
var myScrollFunc = function () {
var y = window.scrollY;
if (y >= 400 & y <= 1000 ) {
myID.className = "pointer show"
} else {
myID.className = "pointer hide"
}
};
window.addEventListener("scroll", myScrollFunc);
</script>
</body>
</html>
Anyone have any idea how I can make this happen?
Thanks guys!
$(document).ready(function() {
$(window).scroll(function() {
console.log('scrolling ', $(window).scrollTop(), $(document).height());
if ($(window).scrollTop() >= 400 && $(window).scrollTop() <= ($(document).height() - 600)) {
$('#myID').removeClass('hide');
}
else {
$('#myID').addClass('hide');
}
});
});
.hide {
display: none;
}
.body {
height: 2000px;
}
#myID {
background-color: lightgray;
position: fixed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="body">
<div id="myID" class="pointer hide">
STUFF HERE
</div>
</div>
use document.height to get the height of the document and rest the desired value:
myID = document.getElementById("myID");
var myScrollFunc = function () {
var y = window.scrollY;
if (y >= 400 & y <= document.height - 400) {
myID.className = "pointer show";
} else {
myID.className = "pointer hide";
}
};
window.addEventListener("scroll", myScrollFunc);

How to convert jQuery function into angular js?

I am very new to AngularJs, I have written a slider function in jQuery. Now I want to convert thih function into Angular. Here is my code below::
<div class="slide-container">
<div class="slide-scroller" style="left: 0px;">
<div class="slideContent" style="background-color: #f00;">one</div>
<div class="slideContent" style="background-color: #0f0;">two</div>
<div class="slideContent" style="background-color: #00f;">three</div>
</div>
</div>
<input type="button" id="left">
<input type="button" id="right">
.slide-container {height: 100px; overflow: hidden; position: relative;}
.slide-scroller { height: 100px; overflow:hidden; position: absolute; top: 0px;}
.slide-scroller .slideContent { height: 100px; overflow: hidden; float: left;}
function slider() {
var slideWidth, speed, sc, slideScroller, scSlide, totalSlide, scrollerWidth, maxLeft;
slideWidth = $(window).width(); // [ get the device width ]
speed = 0.6; // [ control speed 1 = 1s]
sc = $(".slide-container"); // [ getting the container ]
slideScroller = $('.slide-scroller'); // [ getting slider scroller ]
scSlide = $('.slideContent'); // [ getting slide contetnts ]
totalSlide = $(scSlide).length; // [ total slide contents ]
scrollerWidth = totalSlide * slideWidth; // [ slide scroller width ]
maxLeft = -parseInt(scrollerWidth) + parseInt(slideWidth); // [maxmimum left slide value]
// adding some initial attributes
$(sc && scSlide).css({width: slideWidth});
$(slideScroller).css({width: scrollerWidth});
$(slideScroller).css('transition', 'all ease '+speed+'s');
// left click function
$("#left").click(function () {
var xvalue = $(slideScroller).css('left'); //console.log('left :: ', xvalue);
var newvalue = parseInt(xvalue) - parseInt(slideWidth); // console.log('newValue :: ', newvalue);
if (newvalue >= maxLeft) {//console.info('no more left left');
$(slideScroller).css('left', newvalue);
}
else {
return false;
}
});
// right click function
$("#right").click(function () {
var xvaluetwo = $(slideScroller).css('left'); console.log('lefttwo :: ', xvaluetwo);
var newvaluetwo = parseInt(xvaluetwo) + parseInt(slideWidth); console.log('newValuetwo :: ', newvaluetwo);
if (newvaluetwo <= 0) {//console.info('no more right left');
$(slideScroller).css('left', newvaluetwo);
}
else {
return false;
}
});
}
$(document).ready(function () {
slider();
});
I have linked jQuery.min library and called the function in document.ready
Please help me how to make in AngularJS
in HTML:
<div class="slide-container" ng-init="initSlider()">
<div class="slide-scroller" ng-repeat="item in sliderList" style="left: 0px;">
<div class="slideContent" style="background-color: {{item.bgColor}}">{item.content}</div>
</div>
</div>
<input type="button" id="left">
<input type="button" id="right">
in Controller:
$scope.initSlider = function(){
slider()
}

Categories