jQuery: animate element to give room for another one appearing - javascript

So I have a function which is called when input's value changes.
It checks if new value is not '' and then it's supposed to slide an input field a little to the left to make room for "clear" button to appear, but I just don't know how to do it.
Here's what I have.
<div class="searchbox">
<input type="text" ng-model="search" ng-change="filterHeaders()"
ng-focus="changeSearchValue()" ng-blur="changeSearchValue()" />
<button id="clearSearch">x</button>
</div>
Please ignore the ng-stuff, but I left it here, so there are no questions how the function is called. It's called from angular.
$('#clearSearch').hide();
searchButton = function() {
if($('.searchbox input').val() !== '') {
if($('#clearSearch:hidden')) {
$('.searchbox input').stop().animate(
{marginRight: 20},
{queue: false, duration: 500}
);
$('#clearSearch').stop().fadeIn(500);
}
}
};
But, of course, it doesn't work as I want it to. It first jumps to the left, giving room for the button to appear, as it would without any animation, and only after begins to slide 20px more to the left.
I understand, that marginRight is not the way to achieve this, but I have no other idea. What do you think?
tldr: I want to slide input to the left to make room for a button to fade in. Simultaneously.
Here is a fiddle of the problem.

All you need to do is make the clear button absolutly positioned so it doesn't disturb the other elements: (Working jsFiddle)
.searchbox {
float: right;
position:relative;
}
.searchbox button{
position: absolute;
top:0; right:0;
}
Also, I would add an "animating" class or something to tell if the input is currently animating.. What currently happens is that when typing fast the .stop() function is called every time which causes a short "break" on each keypress. Another jsFiddle to illustrate this.

If I understand correctly, what you want to do is run your second animation like so:
http://jsfiddle.net/rktpw89p/3/
$('#clearSearch').hide();
$('.searchbox input').keyup(function() {
if($('.searchbox input').val() !== '') {
if($('#clearSearch:hidden')) {
$('.searchbox input').stop().animate({
marginRight: 20
}, 500, function() {
alert('first animation complete!');
$('#clearSearch').stop().fadeIn(500);
});
}
}
});
it's waiting for the first one to complete.

use absolute positining like so :
.searchbox {
right:0;
position: absolute;
}
#clearSearch {
right:0;
top:0;
position: absolute;
}
That way, the search box does not jump to the left when the button gets rendered because absolute positioning does not affect the positioning of other DOM elements like described here
here is a working jsfiddle:
http://jsfiddle.net/rktpw89p/5/

You don't want to change the position of the input, just decrease its width, so animate the width property instead of any margins.
Here's a running example where the animation starts after two seconds.
$(function() {
$('#clearSearch').hide();
setTimeout(function() {
animate();
}, 2000);
});
function animate() {
var input = $('.searchbox input');
var newWidth = input.width() - 20;
input.stop().animate({
width: newWidth
}, {
queue: false,
duration: 500
});
$('#clearSearch').stop().fadeIn(500);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="searchbox">
<input type="text" />
<button id="clearSearch">x</button>
</div>

Related

jQuery carousel next element not sliding in

See this fiddle: http://jsfiddle.net/r0mvyLmx/
I have to write a simple jQuery horizontal carousel from scratch, but I've stumbled into the following issue: when the next button is pressed the current element slides out of view just fine, but the next element does not slide in. It shows up only after the previous element is completely out of view. If you've not understood me, this is the effect I'm after: http://jsfiddle.net/yvD5S/ (next and previous slides sliding at the same time).
Here's my code:
$('#carousel-outer button:last').on('click', function () {
var slide = $('#carousel-inner .item.active');
slide.animate({'margin-left':'-480px'},2000,function() {
slide.css({ 'margin-left': 0 });
slide.parent().find('div:last').after(slide);
slide.removeClass('active');
slide.parent().find('div:first').addClass('active');
});
});
Whoops, the issue turned out to be pretty simple. It was not the jQuery, but actually the CSS, that is faulty. On the inner wrapper of the carousel, I had given it the same width of the outer wrapper and the slides weren't displaying inline, but rather block, so they weren't able to flow after one another. I've updated the fiddle for anyone who is interested in the issue: http://jsfiddle.net/r0mvyLmx/1/. There was also a minor change in the JS, in order to keep the inactive elements with display:none.
CSS:
#carousel-outer {
width: 480px;
margin: 0 auto;
overflow: hidden;
}
#carousel-inner {
width: 1600px;
height: 200px;
overflow: hidden;
}
jQuery change:
$('#carousel-outer button:last').on('click', function () {
var slide = $('#carousel-inner .item.active');
slide.next().addClass('active');
slide.animate({'margin-left':'-480px'},2000,function() {
slide.css({ 'margin-left': 0 });
slide.parent().find('div:last').after(slide);
slide.removeClass('active');
});

Cursor in wrong position in IE11 after CSS transform w/ transition

jsfiddle here
This is a bug specific to IE and I'm looking for a work around.
When I apply a CSS transform: translate to a text input, that has the focus, with transition set to something valid, the cursor stays in the old location while the element moves.
Once you start typing it moves to the correct location, but before that the cursor stubbornly blinks at the old location.
This code illustrates the problem... again, it's an IE specific bug.
var toggleTop = function(){
$('.input-container').toggleClass('top');
$('#the-input').focus();
}
$('#the-button').click(toggleTop);
.input-container {
top: 100px;
left: 100px;
position: fixed;
transition: all 1s;
}
.input-container.top {
transform: translateY(-100px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='input-container'>
<input type='text' id='the-input'></input>
</div>
<button id='the-button'>Click Me!</button>
One year passed, and I've encountered this issue as well. Here is angular.js directive that I used to fixed it, based on the accepted answer's code and explanation.
angular.module('my.directive')
  .directive('custom-auto-focus', function ($timeout) {
    return {
      link: function (scope, elm) {
        $timeout(function() {
          elm[0].focus();
        }, 350);
      }
    };
  });
Is there any reason why you can't wait for the transition to end before focusing on the element? Considering you're using CSS transitions you should have access to transitionend event.
This fixes the issue:
var toggleTop = function () {
var inputContainer = $('.input-container'),
input = inputContainer.find('#the-input');
inputContainer.toggleClass('top');
inputContainer.one('transitionend', function () {
input.focus();
});
};
$('#the-button').click(toggleTop);
Updated JSFiddle

How to initialize an Angularjs css3 animation using Javascript

I am currently trying to do a CSS3 animation in Angular.js.
Before animating I try to set the initial css properties using Javascript.
So, is there a way to initialize an animation using Javascript and then continue the animation using CSS3?
My situation:
When the user clicks on a div, a dialog should appear.
The dialog should start out exactly over the original div (same size, same position), and then grow to a larger size.
I am able to animate the dialog from a predefined position and size:
CSS:
.dialog {
position: absolute;
z-index: 10;
width:600px;
height:400px;
margin-left: -300px;
left:50%;
margin-top: 50px;
}
.dialogHolder.ng-enter .dialog {
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1s;
width:0;
height:0;
margin-left: 0px;
}
.dialogHolder.ng-enter-active .dialog {
width:600px;
height:400px;
margin-left: -300px;
}
I would like to animate the dialog starting at the size of the clicked div.
So far my code (not working yet) looks like this:
HTML:
<div ng-repeat="course in data.courses" ng-click="showDialog($event)">
{{ course.cursus }}
</div>
<!-- Placeholder for blokDialogs -->
<div class="dialogHolder" ng-include="dialogTemplate.url">
DIALOG WILL BE LOADED HERE
</div>
Javascript:
app.controller('blockController', function($scope) {
$scope.showDialog = function(evt) {
// get position and size of the course block
$scope.dialogTemplate.clientRect = evt.target.getBoundingClientRect();
// load the html to show the dialog
$scope.dialogTemplate.url = 'partials/blokDialog.html';
// SHOULD I DO SOMETHING HERE?
};
});
// OR SHOULD I DO SOMETHING LIKE THIS?
app.animation('.dialogHolder', function(){
return {
// SOMEHOW SET THE WIDTH, HEIGHT, TOP, LEFT OF .dialog
};
});
I'd prefer to do this without jQuery to keep the page weight low.
Regards,
Hendrik Jan
You want to use ng-animate http://docs.angularjs.org/api/ngAnimate
If you are using ng-repeat, you can animate when elements enter, leave and move around your repeater. The magic is that you don't even have to put an extra directive in your html, just define your CSS animations accordingly.
So in your case something like this
.repeater.ng-enter, .repeater.ng-leave, .repeater.ng-move {
-webkit-transition:0.5s linear all;
transition:0.5s linear all;
}
.repeater.ng-enter { }
.repeater.ng-enter-active { }
.repeater.ng-leave { }
.repeater.ng-leave-active { }
.repeater.ng-move { }
.repeater.ng-move-active { }
and your HTML
<div ng-repeat="..." class="repeater"/>
In the end, I found the following solution:
HTML:
Create an onClick handler and a placeholder where the dialog is loaded.
<!-- Element on which the user clicks to initialize the dialog -->
<div ng-repeat="course in data.courses"
ng-click="showDialog($event, course)">
{{ course.name }}
</div>
<!-- Placeholder for blokDialogs -->
<div class="dialogHolder"
ng-include="dialogTemplate.url"
onload="showDialogLoaded()">
</div>
HTML Template:
partials/blokDialog.html sets it's style using ng-style.
<div ng-style="dialogTemplate.initialStyle">
...
</div>
Javascript:
The onClick handler sets the initial CSS before the animation starts.
$scope.showDialog = function(evt, course) {
// Load the dialog template
$scope.dialogTemplate.url = 'partials/blokDialog.html';
// set the css before the animation starts
// get position and size of the course block
var clientRect = evt.target.getBoundingClientRect();
$scope.dialogTemplate.initialStyle = {
left: clientRect.left + 'px',
top: clientRect.top + 'px',
width: clientRect.width + 'px',
height: clientRect.height + 'px',
backgroundColor: getComputedStyle(evt.target).backgroundColor
};
};
The style needs to be removed before the animation ends but after the animation started.
The animation starts at the end of the onLoad handler. If we remove the style in the onLoad handler (i.e. in showDialogLoaded), then we are to early.
We use setTimeout to make sure that the removal of the style is done after the animation was started.
$scope.showDialogLoaded = function() {
// remove the style that we set in showDialog
setTimeout(function(){
$scope.dialogTemplate.initialStyle = {};
// we need to $apply because this function is executed
// outside normal Angular handling, so Angular does not know
// that it needs to do a dirty check
$scope.$apply();
}, 0);
};
I hope this can be helpful for others.
Regards,
HJ

Trying to fade and slide text out of initials on mouse over with jQuery

I'm trying to create an effect with jQuery where on mouse over of my initials on the page in the header, the div they are in expands (using jQuery animate) and the text of my full name fades in from each initial.
I have tried a variety of things but am not sure what is the best way to do this. I'm a bit stuck. I'm currently trying to get it going by having the initials of my name "OW" in two separate divs and then the remainder of my name to make up "wen" and "illiams" in between those initals. Like so:
<div class="initialF inlinediv">O</div>
<div class="fullF inlinediv">wen</div>
<div class="initialL inlinediv">W</div>
<div class="fullL inlinediv">illiams</div>
I thought it would work to use jQuery slideLeft and .fadeIn to get the text to slide in from the left as well as fading to look like the text is emerging from the initials but the animations was jumpy and would go onto a second line while the div was still expanding. I am using the below jQuery to detect the mouseIn/Out events:
<script>
$(".brand").mouseenter(function() {
$('.brand').animate({width: '160px'});
$('.fullF').fadeIn("slow");
});
$(".brand").mouseout(function() {
$('.brand').animate({width: '36px'});
$('.fullF').fadeOut("slow");
});
</script>
The alternatives I have tried were using jquery.lettering.js to help with it but there seemed to be some issues with that. Any suggestions to push me in the right direction would be useful and my site with a partially working example is here:
http://192.241.203.146/
Here's one using css transitions rather than jquery animate: http://jsfiddle.net/S58Se/2/
<div class='branding'>
<span class='initial'>O</span><span class='hidden nameFull wen'>wen</span>
<span class='initial'>W</span><span class='hidden nameFull illiams'>illiams</span>
</div>
span {
display: inline-block;
overflow: hidden;
transition: all 1s;
-moz-transition: all 1s;
-webkit-transition: all 1s;
}
.wen { width: 36px; }
.illiams { width: 160px; }
span.hidden {
width: 0px;
opacity: 0;
}
$('.branding').hover(
function() { $('.nameFull').removeClass('hidden'); },
function() { $('.nameFull').addClass('hidden'); }
);
Or you can do away with the javascript altogether with this: http://jsfiddle.net/S58Se/3/
remove the js and add these css statements:
.branding:hover .wen {
width: 36px;
opacity: 1;
}
.branding:hover .illiams {
width: 160px;
opacity: 1;
}
... just because I think it's neat.
A good way to go about this is to just expand the use of your call to the animation method by adding another property to the object you are passing in. So instead of calling an extra method (fadeIn) you just handle it all in one fell swoop:
$('.brand').on({
'mouseenter' : function () {
$('.nameFull').stop().animate({
'width' : '200px',
'opacity' : '1'
}, 500);
},
'mouseleave' : function () {
$('.nameFull').stop().animate({
'width' : '0',
'opacity' : '0'
}, 500);
}
});
You'll notice I'm also using 'on' instead of the 'hover' or 'mouseenter' and 'mouseleave' methods. In most recent versions of jQuery those methods just reference 'on', so it's better to just cut out the middle man and do it all in one place.
I'm not sure if this exactly fits your design, but I made a Codepen to demonstrate the code in action: http://codepen.io/Tristan-zimmerman/pen/lnDGh
Style the hidden divs position:absolute, and when show them:
'show' them first, to set them visible
then position them (next to your 'launching' div), using jQuery.position();
set the animation going.
Essentially you want them 'absolute' to avoid them thunking in/out & changing your existing flow. position() must be called after making the element visible, and then you should have appropriate starting conditions to kick off your animation.
Or you could try using <span>' for the incoming text and/or displaying as inline-block, which may help avoid the "incoming" kicking things down a line. HTH.
I think what you are looking for is something like this: JSFiddle
html:
<div class="brand">
<div>O<span class="full">wen </span>W<span class="full">illiams</span></div>
</div>
jq:
$('.brand').hover(function(){
$(this).stop().animate({width: '160px'},'slow',function(){
$(this).children('div').children('.full').stop().fadeIn('slow');
});
},function(){
$(this).children('div').children('.full').stop().fadeOut('slow',function(){
$(this).parent().parent().stop().animate({width: '36px'},'slow');
});
});
css:
.full{
display: none;
}
note: there is a simple bug that happens in a specific case and I'm working on it.
regards,

Javascript: prevent internal element "scrolling" in an element

I have a script that has a div with a width larger than its' parent, with the parent being set to overflow: hidden;. I have javascript that is setting the left positioning of the big div to create "pages". You can click a link to move between pages.
All of that works great, but the problem is if you tab from one "page" element to another, it completely messes up all the left positioning to move between the pages.
You can recreate this bug in the fiddle I set up by setting your focus to one of the input boxes on page ONE and tabbing until it takes you to page two.
I've set up a demo here.
The code that is important is as follows:
HTML:
<div class="form">
<div class="pagesContainer">
<div class="page" class="active">
<h2>Page One</h2>
[... Page 1 Content here...]
</div>
<div class="page">
<h2>Page Two</h2>
[... Page Content here...]
</div>
</div>
CSS:
.form {
width: 400px;
position: relative;
overflow: hidden;
border: 1px solid #000;
float: left;
}
.pagesContainer {
position: relative; /*Width set to 10,000 px in js
}
.form .page {
width: 400px;
float: left;
}
JS:
slidePage: function(page, direction, currentPage) {
if (direction == 'next') {
var animationDirection = '-=';
if (page.index() >= this.numPages) {
return false;
}
}
else if (direction == 'previous') {
var animationDirection = '+=';
if (page.index() < 0) {
return false;
}
}
//Get page height
var height = page.height();
this.heightElement.animate({
height: height
}, 600);
//Clear active page
this.page.removeClass('active');
this.page.eq(page.index()).addClass('active');
//Locate the exact page to skip to
var slideWidth = page.outerWidth(true) * this.difference(this.currentPage.index(), page.index());
this.container.animate({
left: animationDirection + slideWidth
}, 600);
this.currentPage = page;
}
The primary problem is that whatever happens when you tab from say, an input box on page one to something on page 2, it takes you there, but css still considers you to be at left: 0px;. I've been looking all over for a solution but so far all google has revealed to me is how to stop scrollbar scrolling.
Any help or suggestions would be appreciated, thanks!
P.S. The html was set up like this so that if javascript is disabled it will still show up all on one page and still function properly.
I updated your fiddle with a fix for the first tab with the form: http://jsfiddle.net/E7u9X/1/
. Basically, what you can do is to focus on the first "tabbable" element in a tab after the last one gets blurred, like so:
$('.form input').last().blur(function(){
$('.form input').first().focus();
});
(This is just an example, the first active element could be any other element)
Elements with overflow: hidden still have scrolling, just no scroll bars. This can be useful at times and annoying at others. This is why your position left is at zero, but your view of the element has changed. Set scrollLeft to zero when you change "pages", should do the trick.

Categories