ngAnimate transition scrolls current page to top in ui-view - angularjs

When I click next button which is down below on one of my views to go to another state, the current page where I'm at scrolls back to the top then finally ngAnimate and css starts to slide the 2 partials. However, I don't like the resulting transitions as it causes somewhat a flickering effect.
What I'd like to happen is that when I click next button, I'd like to maintain the position of where current view is on the screen, then start the sliding.
Is there something I need to change on my code? autoscroll="false" on my ui-view doesn't seem to help.
Here is my new css.
#content-view.ng-enter, #content-view.ng-leave {
position: absolute;
// width: 100%;
-webkit-transition:all 2s ease-in-out;
transition:all 2s ease-in-out;
}
#content-view.ng-enter {
// transform: translateX(100%);
// -webkit-transform: translateX(100%);
transform: translate3d(100%, 0, 0);
-webkit-transform: translate3d(100%, 0, 0);
}
#content-view.ng-enter-active {
// transform: translateX(0);
// -webkit-transform: translateX(0);
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
}
#content-view.ng-leave {
opacity: 1;
// transform: translateX(0);
// -webkit-transform: translateX(0);
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
}
#content-view.ng-leave-active {
opacity: 0;
// transform: translateX(-100%);
// -webkit-transform: translateX(100%);
transform: translate3d(-100%, 0, 0);
-webkit-transform: translate3d(-100%, 50, 50);
}
Here is a plunker but I'm not sure why it's not happening here. There might be something in my code that's doing the behavior.
Anyways, I like the behavior of this one when switching between view. However, I was hoping if we can correctly position the new target view when we click it. Right now, if let's say i'm displaying view1 and I scroll it down, once I click view 2, I want the position of view1 to stay as is but I want the position of view 2 to proper top position and not the same position as view1.
http://plnkr.co/edit/thDO1WZ9YUcV9yGfkVjh?p=preview
UPDATE:
Here is the solution on how I got it to work. I love the slide transition. It really looks so professional.
Snippet from main.html
<div id="content-view" ng-class="{ 'backEvent' : $root.backEvent === true, 'entryComplete' : $root.entryComplete === true }" ui-view="content" autoscroll="false"></div>
Initial load of the form, $scope.entryComplete is set to false. When I fill out the form and click next, $scope.entryComplete becomes true. I set it in the controller. Since it became true, these 2 classes will be used, #content-view.entryComplete.ng-enter and #content-view.entryComplete.ng-enter-active.
Now when I click Back button, $root.entryComplete becomes false and $root.backEvent becomes true. Now that entryComplete is gone, these will be used #content-view.ng-enter and #content-view.ng-enter-active and for the ng-leave, these will be used #content-view.backEvent.ng-leave and #content-view.backEvent.ng-leave-active. I set backEvent back to false when I click Next again
Here is part of the magic that I've worked all day.
#content-view.ng-enter {
opacity: 0;
transform: translate3d(-100%, 0, 0);
-webkit-transform: translate3d(-100%, 0, 0);
transition: all 2s ease-in-out;
}
#content-view.ng-enter-active {
opacity: 1;
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
}
#content-view.ng-leave {
position: absolute;
opacity: 1;
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
transition: all 2s ease-in-out;
}
#content-view.ng-leave-active {
position: absolute;
opacity: 0;
transform: translate3d(-100%, 0, 0);
-webkit-transform: translate3d(-100%, 0, 0);
}
#content-view.entryComplete.ng-enter {
opacity: 1;
transform: translate3d(100%, 0, 0);
-webkit-transform: translate3d(100%, 0, 0);
transition: all 2s ease-in-out;
}
#content-view.entryComplete.ng-enter-active {
opacity: 1;
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
}
#content-view.backEvent.ng-leave {
position: absolute;
opacity: 1;
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
transition: all 2s ease-in-out;
}
#content-view.backEvent.ng-leave-active {
position: absolute;
opacity: 0;
transform: translate3d(100%, 0, 0);
-webkit-transform: translate3d(100%, 0, 0);
}
Don't forget about the other magic that I mentioned somewhere in the thread, the one that will store the current Y(top) coordinate value.
var offsets = document.getElementById('content-view').getBoundingClientRect();
document.getElementById('content-view').style.top = (offsets.top - 65) + 'px';
I took out the .style.position = "absolute" since I already got it hardcoded in the css. Enjoy!

this may be what you're looking for?
$scope.gotoTop = function() {
$location.hash('top');
$anchorScroll();
};
add this function to the controller of your navbar and add the function to each of your links.
<a ng-click="gotoTop()" href="#/home">Example</a>
Example NavCtrl.js
angular.module('app').controller('NavCtrl', ['$scope', '$location', '$anchorScroll', function($scope, $location, $anchorScroll) {
$scope.gotoTop = function() {
$location.hash('top');
$anchorScroll();
};
}]);

Related

AngularJS Material Slide Left to Right CSS3 Animation

I am trying to "translate" this AngularJS slide left / right example to an AngularJS Material one.
The latter link consists of the following code snippets:
HTML code:
<div ng-controller="ExampleController" ng-app="switchExample">
<!--<select ng-model="slide" ng-options="item as item.name for item in slides">
</select>-->
<code>slide={{slide}}</code>
<code>moveToLeft={{mtl}}</code>
<md-button ng-click="prev()"><</md-button>
<md-button ng-click="next()">></md-button>
<div class="">
<div class="ngSwitchItem" ng-if="slide.name == 'first'" ng-class="{'moveToLeft' : mtl}">
<div class="firstPage page" md-swipe-left="selectPage(1)">
first
</div>
</div>
<div class="ngSwitchItem" ng-if="slide.name == 'second'" ng-class="{'moveToLeft' : mtl}">
<div class="secondPage page" md-swipe-right="selectPage(0)" md-swipe-left="selectPage(2)">
second
</div>
</div>
<div class="ngSwitchItem" ng-if="slide.name == 'third'" ng-class="{'moveToLeft' : mtl}">
<div class="thirdPage page" md-swipe-right="selectPage(1)" md-swipe-left="selectPage(3)">
third
</div>
</div>
<div class="ngSwitchItem" ng-if="slide.name == 'fourth'" ng-class="{'moveToLeft' : mtl}">
<div class="fourthPage page" md-swipe-right="selectPage(2)">
fourth
</div>
</div>
</div>
</div>
JS code
(function(angular) {
'use strict';
angular.module('switchExample', ['ngMaterial', 'ngAnimate'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.slides = [
{ index: 0, name: 'first' },
{ index: 1, name: 'second' },
{ index: 2, name: 'third' },
{ index: 3, name: 'fourth' }
];
$scope.selectPage = selectPage;
/**
* Initialize with the first page opened
*/
$scope.slide = $scope.slides[0];
$scope.prev = () => {
if ($scope.slide.index > 0) {
selectPage($scope.slide.index - 1);
}
}
$scope.next = () => {
if ($scope.slide.index < 3) {
selectPage($scope.slide.index + 1);
}
}
/**
* #name selectPage
* #desc The function that includes the page of the indexSelected
* #param indexSelected the index of the page to be included
*/
function selectPage(indexSelected) {
if ($scope.slides[indexSelected].index > $scope.slide.index) {
$scope.mtl = false;
} else {
$scope.mtl = true;
}
$scope.slide = $scope.slides[indexSelected];
}
}]);
})(window.angular);
CSS code
body {
overflow-x: hidden;
}
.ngSwitchItem {
position: absolute;
top: 50px;
bottom: 0;
right: 0;
left: 0;
animation-duration: 10.30s;
animation-timing-function: ease-in-out;
-webkit-animation-duration: 10.30s;
-webkit-animation-timing-function: ease-in-out;
}
.page {
position: inherit;
top: 0;
right: inherit;
bottom: inherit;
left: inherit;
}
.firstPage {
background-color: blue;
}
.secondPage {
background-color: red;
}
.thirdPage {
background-color: green;
}
.fourthPage {
background-color: yellow;
}
/* When the page enters, slide it from the right */
.ngSwitchItem.ng-enter {
animation-name: slideFromRight;
-webkit-animation-name: slideFromRight;
}
/* When the page enters and moveToLeft is true, slide it from the left(out of the user view) to the right (left corner) */
.ngSwitchItem.moveToLeft.ng-enter {
animation-name: slideFromLeft;
-webkit-animation-name: slideFromLeft;
}
/* When the page leaves, slide it to left(out of the user view) from the left corner,
in other words slide it from the left(out of the view) to the left corner but in reverse order */
.ngSwitchItem.ng-leave {
animation-name: slideFromLeft;
animation-direction: reverse;
-webkit-animation-name: slideFromLeft;
-webkit-animation-direction: reverse;
}
/* When the page leaves, slide it to the right(out of the user view) from the the left corner,
in other words, slide it from the right but in reverse order */
.ngSwitchItem.moveToLeft.ng-leave {
animation-name: slideFromRight;
animation-direction: reverse;
-webkit-animation-name: slideFromRight;
-webkit-animation-direction: reverse;
}
#keyframes slideFromRight {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
#keyframes slideFromLeft {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(0);
}
}
#-webkit-keyframes slideFromRight {
0% {
-webkit-transform: translateX(100%);
}
100% {
-webkit-transform: translateX(0);
}
}
#-webkit-keyframes slideFromLeft {
0% {
-webkit-transform: translateX(-100%);
}
100% {
-webkit-transform: translateX(0);
}
}
As seen, however, the second one doesn't behave as the first one, WHEN slide direction has changed.
For instance:
I slide to left the first one --> second slide loads with the correct animation
Then, I slide to right the second one --> it is supposed the first slide to start appearance from the left side, while the second one to start disappearance to to the right side. Instead, as you may see, the second one start to disappear to the left and from the right side a white slide is shown. At some point, the first slide starts its appearance from the middle of the content.
Please note, I deliberately delay the animations on the second example, just to see the undesired side effect mode clearly.
Actually, after a few more research hours, I found where the problem was buried - it seems, I have to move scope variable change for the next tick, to give time ng-class change to make its "magic".
Long story short - adding the following is what made the thing work:
$timeout(() => {
$scope.slide = $scope.slides[indexSelected];
}, 0)
Here is the updated example and the code snippet below:
JS code
(function(angular) {
'use strict';
angular.module('switchExample', ['ngMaterial', 'ngAnimate'])
.controller('ExampleController', ['$scope', '$timeout', function($scope, $timeout) {
$scope.slides = [
{ index: 0, name: 'first' },
{ index: 1, name: 'second' },
{ index: 2, name: 'third' },
{ index: 3, name: 'fourth' }
];
$scope.selectPage = selectPage;
/**
* Initialize with the first page opened
*/
$scope.slide = $scope.slides[0];
$scope.prev = () => {
if ($scope.slide.index > 0) {
selectPage($scope.slide.index - 1);
}
}
$scope.next = () => {
if ($scope.slide.index < 3) {
selectPage($scope.slide.index + 1);
}
}
/**
* #name selectPage
* #desc The function that includes the page of the indexSelected
* #param indexSelected the index of the page to be included
*/
function selectPage(indexSelected) {
if ($scope.slides[indexSelected].index > $scope.slide.index) {
$scope.mtl = false;
} else {
$scope.mtl = true;
}
// this will move a scope variable change to the next tick,
// hence will give time $scope.mtl to be handled by ng-class
$timeout(() => {
$scope.slide = $scope.slides[indexSelected];
}, 0)
}
}]);
})(window.angular);

Show an object right after hidding another with ng-show/ng-hide

I'm trying to make the effect when a button is clicked, the button fades out and in the same place a load animation fades in, but I can't manage to make the load animation show after the button is totally hidden.
In the HTML I have:
<div class="form-group">
<button ng-hide="login.sendingAjax" type="submit" id="loginButton" class="form-control btn btn-primary uppercase">INGRESAR</button>
<loader ng-if="login.sendingAjax" ng-show="login.sendingAjax" class="loaderContainer"></loader>
</div>
Then in my controller I have the function when the form is being submited, in that moment I put the login.sendingAjax variable to true for the button to be hidden and the animation to appear, and when it ends the call with a failure I put the login.sendingAjax variable back to false:
vm.loginError = false;
vm.sendingAjax = false;
/**
* Submit the form and check if login was ok
*/
vm.loginUser = function() {
vm.loginError = false;
vm.sendingAjax = true;
vm.alert = {};
authService.login(vm.formData).then(function () {
$location.path('/ubicaciones');
},
function () {
vm.alert = {type: 'danger', msg: 'Hola'};
vm.sendingAjax = false;
vm.loginError = true;
});
};
The CSS is:
.ng-hide-add { animation:0.5s hideObjectOpacity ease; }
/* when showing the picture */
.ng-hide-remove { animation:0.5s flipInX ease; }
/* ANIMATIONS (FROM ANIMATE.CSS) ======================== */
/* flip in */
#keyframes flipInX {
0% {
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
transition-timing-function: ease-in;
opacity: 0;
}
40% {
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transition-timing-function: ease-in;
transition-timing-function: ease-in;
}
60% {
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
opacity: 1;
}
80% {
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
}
100% {
transform: perspective(400px);
transform: perspective(400px);
transform: perspective(400px);
}
}
/* light speed out */
#keyframes hideObjectOpacity {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
there are two ways to handle that. one is that while NOT using ng-hide and ng-show, you can do the fade out animation with a function inside your JS (using a module like VelocityJS or ...), and inside it's callback, fade in the other element (the element should be display:none by default, and the animations should change the display property in their progress).
or you have to use different toggles for the ng-hide and ng-show, and set the ng-show toggle to true in the first function's callback or using $timeout ...
you can also fake the delay in entrance by manipulating the first few steps of the css animation and say set the opacity to 0 in them, until the first element is completely out... but i don't think it's a proper way of doing it . (considering your layout might change because an element with opacity:0 still exists in there!)
tell me if you need an example to understand it better

Angular - ngShow/Hide animation only fires on ng-click?

I'm using Angular version v1.2.20 and I'm encountering some weirdness with regards to css transitions when using ng-show/hide. For some reason, if I change the value of a scope object by calling a function through ng-click the animation works fine, but if I change it by some other method, say a timeout, or even just calling it in an init function, the element shows, but no animation happens. Here's a small example function that animates when being called from ng-click, but doesn't otherwise.
showFlash: (msg, type = "success") ->
#$.flash =
"message": msg
"type": type
#$timeout =>
#$.hideFlash()
, 3000
hideFlash: ->
#$.flash = null
P.S - I'm using Angular Classy for my controller if you're wondering about the funny #$ syntax.
CSS (Scss)
.dashboard-flash-message {
#include transition ( all 300ms ease-in-out );
#include transform( translateY(0) );
background: $primary;
color: #fff;
font-size: 0.75rem;
font-weight: bold;
opacity: 1;
padding: 20px;
position: absolute; bottom: 0; left: 0;
width: $dashboard-sidebar-width;
&.ng-hide {
#include transform( translateY(100%) );
opacity: 0;
}
}
There are 4 classes that Angular uses to animate ng-show/ng-hide:
.ng-hide-add
.ng-hide-add-active
.ng-hide-remove
.ng-hide-remove-active
I don't see that you're using them in your stylesheet.
CSS
.ng-hide-add {
-webkit-transition:0.5s linear all;
-moz-transition:0.5s linear all;
-o-transition:0.5s linear all;
transition:0.5s linear all;
opacity: 1;
}
.ng-hide-add.ng-hide-add-active {
opacity: 0;
}
.ng-hide-remove {
-webkit-transition:0.5s linear all;
-moz-transition:0.5s linear all;
-o-transition:0.5s linear all;
transition:0.5s linear all;
opacity: 0;
}
.ng-hide-remove.ng-hide-remove-active {
opacity: 1;
}
Script
var app = angular.module("app", ['ngAnimate']);
app.controller('Ctrl', function($scope, $timeout) {
$scope.show = false;
$scope.onShow = function() {
$scope.show = true;
$timeout(function() {
hideMe();
},2000);
}
function hideMe() {
$scope.show = false;
}
});
Here is a Plunker that demonstrates how they should be used.

Different swipe animations based on direction of swipe in AngularJS

I've created a really basic version of what I've got so far in a JSFiddle, which can be found here: http://jsfiddle.net/hamchapman/a97Yq/5/
This is the code in case the JSFiddle doesn't work:
// ** view **
<div class="container" ng-controller="AdminCtrl">
<div class="tweet-list">
<div class="tweet" ng-repeat="tweet in tweets" ng-class="{ 'swipe-left': $index == activeIndexLeft, 'swipe-right': $index == activeIndexRight }">
<div ng-swipe-right="discardTweet(tweet, $index)" ng-swipe-left="verifyTweet(tweet, $index)">{{tweet.text}}</div>
<button ng-click="verifyTweet(tweet, $index)" type="button">Show Tweet</button>
<button ng-click="discardTweet(tweet, $index)" type="button">Discard Tweet</button>
</div>
</div>
</div>
// ** style **
.swipe-left.ng-leave, .swipe-right.ng-leave {
-webkit-transition: 500ms cubic-bezier(0.420, 0.000, 1.000, 1.000) all;
-moz-transition: 500ms cubic-bezier(0.420, 0.000, 1.000, 1.000) all;
-ms-transition: 500ms cubic-bezier(0.420, 0.000, 1.000, 1.000) all;
-o-transition: 500ms cubic-bezier(0.420, 0.000, 1.000, 1.000) all;
transition: 500ms cubic-bezier(0.420, 0.000, 1.000, 1.000) all;
}
.swipe-left.ng-leave {
left: 0;
}
.swipe-left.ng-leave.ng-leave-active {
position: absolute;
left: -100%;
}
.swipe-right.ng-leave {
left: 0;
}
.swipe-right.ng-leave.ng-leave-active {
position: absolute;
left: 100%;
}
// ** angular **
var myApp = angular.module('myApp', ['ngAnimate',]);
function AdminCtrl($scope) {
$scope.activeIndexLeft = -1;
$scope.activeIndexRight = -1;
$scope.tweets = [{
text: "tester"
}, {
text: "tester 2"
}, {
text: "tester 3"
}, {
text: "tester 4"
}, {
text: "tester 5"
}, {
text: "tester 6"
}];
$scope.verifyTweet = function (tweet, $index) {
$scope.activeIndexLeft = $index;
var i = $scope.tweets.indexOf(tweet);
if (i != -1) {
$scope.tweets.splice(i, 1);
}
};
$scope.discardTweet = function (tweet, $index) {
$scope.activeIndexRight = $index;
var i = $scope.tweets.indexOf(tweet);
if (i != -1) {
$scope.tweets.splice(i, 1);
}
}
};
You can see that it's what feels like a fairly hacked together method and it doesn't work perfectly either. No animation happens on the first click (or swipe) of an item at a given index (because the swipe-left/right class is only applied when clicked (or swiped).
It's generally pretty buggy and it doesn't seem like the way to do it using Angular.
What is a better way of achieving the differing animations based on the swipe direction (or which button is clicked)?

Angular ng animate slider

I am trying to create a slider using ng animate.
The slider works. You are able to click next and previous and get the next and previous images.
However I would like to add a transition to the element that original element that is being hidden whilst the new element comes in.
I am not able to do this and wondered if someone could spot where I am going wrong.
index.jade file...
div.gallery(ng-controller="aCtrl")
a.slider-prev(href="#" ng-click="prevSlide()")
a.slider-next(href="#" ng-click="nextSlide()")
ul.gallery
li(ng-repeat="image in gallery" class="gallery-animation" ng-swipe-right="prevSlide()" ng-swipe-left="nextSlide()" ng-show="isCurrentSlideIndex($index)")
figure
img.fluid(ng-src="{{imagePaths}}{{image.URL[0]}}")
figcaption.fluid
{{image.TITLE[0]}} : {{image.CAPTIONS[0]}}
nav.nav
div.wrapper
ul.dots
li.dot(ng-repeat="image in gallery")
a(href="#" ng-class="{'active':isCurrentSlideIndex($index)}" ng-click="setCurrentSlideIndex($index);")
...
controller.js =
App.controller('aCtrl', function (data , imgPath, $scope) {
data.get().then(function(d) {
$scope.gallery = d.data.PACKAGE.ITEM[4].GALLERY[0].MEDIA;
$scope.currentIndex = 0;
$scope.setCurrentSlideIndex = function (index) {
$scope.currentIndex = index;
};
$scope.isCurrentSlideIndex = function (index) {
return $scope.currentIndex === index;
};
// setting the next and previous controls
$scope.prevSlide = function () {
$scope.currentIndex = ($scope.currentIndex > 0) ? --$scope.currentIndex : $scope.gallery.length - 1;
};
$scope.nextSlide = function () {
$scope.currentIndex = ($scope.currentIndex < $scope.gallery.length - 1) ? ++$scope.currentIndex : 0;
};
$scope.imagePaths = imgPath['default'];
})
});
...
css
.gallery-animation {
position:absolute;
top:0;
left:0;
opacity:1;
}
.gallery-animation.ng-hide-add.ng-hide-add-active {
opacity:1;
-webkit-transition:1s linear all;
-moz-transition:1s linear all;
-o-transition:1s linear all;
transition:1s linear all;
-webkit-transform: rotateX(50deg) rotateY(30deg);
-moz-transform: rotateX(50deg) rotateY(30deg);
-ms-transform: rotateX(50deg) rotateY(30deg);
-o-transform: rotateX(50deg) rotateY(30deg);
transform: rotateX(50deg) rotateY(30deg);
-webkit-transform-origin: right top 0;
-moz-transform-origin: right top 0;
-ms-transform-origin: right top 0;
-o-transform-origin: right top 0;
transform-origin: right top 0;
}
.gallery-animation.ng-hide {
opacity:0;
}
.gallery-animation.ng-hide-remove {
-webkit-transition:1s linear all;
-moz-transition:1s linear all;
-o-transition:1s linear all;
transition:1s linear all;
display:block!important;
opacity:0;
}
.gallery-animation, .gallery-animation.ng-hide-remove.ng-hide-remove-active {
opacity: 1;
}
In your CSS you need to add a display property with a block value that shows the element that is being transitioned.
Like so
.gallery-animation.ng-hide-add, .gallery-animation.ng-hide-remove {
/* this needs to be here to make it visible during the animation
since the .ng-hide class is already on the element rendering
it as hidden. */
display:block!important;
}
ref: http://www.yearofmoo.com/2013/08/remastered-animation-in-angularjs-1-2.html

Resources