AngularJS transitions with ui-view, wrong behaviour when changing direction - javascript

I'm trying to apply a transition on my content inside a ui-view. The transition is a simple slide effect which slides from right to left to go deeper in the app, and from left to right when going back.
I found several people with the same problem, then I found this thread Two different animations for route changes which gives a solution, but it was not working for me.
html
<div ng-app="exampleApp" id="app">
<a ui-sref="state1">State 1</a>
<a ui-sref="state2">State 2</a>
<a ui-sref="state3">State 3</a>
<div class="viewWrap" ng-controller="viewCtrl" ng-class="direction">
<div class="container" ui-view ></div>
</div>
</div>
js
var app = angular.module('exampleApp', ['ui.router.compat', 'ngAnimate']);
app.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state('state1', {
template: '<div id="state1"><p>Slide 1</p></div>',
url: '/state1',
depth: 1
});
$stateProvider.state('state2', {
template: '<div id="state2"><p>Slide 2</p></div>',
url: '/state2',
depth: 2
});
$stateProvider.state('state3', {
template: '<div id="state3"><p>Slide 3</p></div>',
url: '/state3',
depth: 3
});
// For any unmatched url, redirect to /state1
$urlRouterProvider.otherwise("/state1");
})
.controller('viewCtrl', function ($scope) {
$scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
if (fromState.depth > toState.depth) {
$scope.direction = 'right';
} else {
$scope.direction = 'left';
}
});
});
css
#state1 {
width: 100%;
height: 400px;
background: red;
}
#state2 {
width: 100%;
height: 400px;
background: blue;
}
#state3 {
width: 100%;
height: 400px;
background: green;
}
.container {
position: absolute;
width: 100%;
}
.viewWrap {
overflow: hidden;
}
.container.ng-enter,
.container.ng-leave {
-webkit-transition: 0.5s ease all;
transition: 0.5s ease all;
}
.left .container.ng-enter {
-webkit-transform: translate3d(100%, 0, 0);
}
.left .container.ng-leave.ng-leave-active {
-webkit-transform: translate3d(-100%, 0, 0);
}
.right .container.ng-enter {
-webkit-transform: translate3d(-100%, 0, 0);
}
.right .container.ng-leave.ng-leave-active {
-webkit-transform: translate3d(100%, 0, 0);
}
.container.ng-leave,
.container.ng-enter.ng-enter-active {
-webkit-transform: translate3d(0, 0, 0);
}
Then I saw that it wasn't ui.router that was used as a dependency, but ui.router.compat.
So I tried to use it instead of ui.router, and it seems to work.
ui.router (not working) http://codepen.io/anon/pen/LVWpXM
ui.router.compat (working) http://codepen.io/anon/pen/qdrOoM
But according to the doc https://github.com/angular-ui/ui-router/wiki/Backwards-Compatibility, ui.router.compat is not supposed to do that at all.
Any ideas to make this work with ui.router ?

Related

Executing keyframes animation in JS or jQuery

I know that it is possible to set the animation of an element by id either in a stylesheet or in JS from the DOM. The issue is that I want the animation to execute every time a click action on a specific element is performed by the user. Adding the animation to an element's style in JS seems to add it permanently so that the keyframes animation cannot be performed again, (only performed once when the window finishes loading). I also thought about using jQuery's .animate() function however all documentation points to it animating over CSS specific styles and not setting/calling the animation style attribute as if I were to set it using CSS. I want to know the best way of executing my animation over an element when another element is clicked on by the user and consistently executing the animation for each click.
#keyframes fadeInDown {
from {
opacity: 0;
transform: translate(0, -20%);
}
to {
opacity: 1;
transform: translate(0, 0);
}
}
The current way I'm setting animation for an element:
$("#element").css("animation", "fadeInDown 0.5s ease-in 0s 1");
This is a toggling animation using transition and jquery, without using .animate()
$(document).ready(function() {
$('button').click(function() {
var box = $('.box')
box.removeClass("show")
setTimeout(function(){
box.addClass("trans").addClass("show")
setTimeout(function(){
box.removeClass("trans")
},100)
},200)
});
});
.box {
background: red;
height: 50px;
width: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
opacity: 0;
transform: translate(0, -20%);
}
.box.trans {
transition: all 0.7s;
}
.box.show {
opacity: 1;
transform: translate(0, 0);
}
<button>Test</button>
<div class="box show"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
It's my first answer on stack overflow.
I had the same question about animation.
What I did last was just like Vivek Patel's answer, but instead of toggling the css keyframe, I created a separated class only for css animation("animation-fadeInDown"), and toggle it.
Because the animation-name "fadeInDown" is correponding to the #keyframes name, so if you separate it you could apply the animation to other elements, by just toggling the animation class.
And, you can still do the css deco to the original box seperately, which might be more clear to read.
I hope this is close to what you looking for.
$('button').click(() => {
$('.box').toggleClass('animation-fadeInDown');
});
.box {
width: 50px;
height: 50px;
background: black;
}
.animation-fadeInDown {
animation: fadeInDown 0.5s ease-in 0s 1
}
#keyframes fadeInDown {
from {
opacity: 0;
transform: translate(0, -20%);
}
to {
opacity: 1;
transform: translate(0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="box"></div>
<button>
Test
</button>
Basically CSS animation only runs once when the page loads. So it is not possible to re-trigger it again. Here is the workaround for your use case: Remove the element from the page entirely and re-insert it.
Try this:
$('button').click(() => {
var oldDiv = $('#animated-div');
newDiv = oldDiv.clone(true);
oldDiv.before(newDiv);
$("." + oldDiv.attr("class") + ":last").remove();
});
#keyframes fadeInDown {
from {
opacity: 0;
transform: translate(0, -20%);
}
to {
opacity: 1;
transform: translate(0, 0);
}
}
.animated-div {
animation: fadeInDown 0.5s ease-in 0s 1
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="animated-div" class="animated-div" style="width: 50px; height: 50px; background: black"></div>
<button>
Test
</button>
This is an simple example that use jquery to animate in Queue as it works in #keyframes. The transition duration and animation duration gives more control on the animation character.
$(document).ready(function() {
$('button').click(function() {
$('.box')
.css('transition', 'all 0.2s')
.animate({ opacity: 0 }, {
duration: 200,
step: function(now) {
$(this).css({ opacity: now });
$(this).css({ transform: 'translate(0, -20%)' });
}
})
.animate({ opacity: 1 }, {
duration: 600,
step: function(now) {
$(this).css({ opacity: now });
$(this).css({ transform: 'translate(0, 0)' });
}
})
});
});
.box {
background: red;
height: 50px;
width: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
<button>Test</button>
<div class="box"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

jQuery animation after removing elements

I have the following HTML and CSS:
<div id="categories">
<h3 id="sports">Sports</h3>
<h3 id="videogames">Video Games</h3>
<h3 id="music">Music</h3>
<h3 id="web">Web</h3>
</div>
#categories {
left: 50%;
top: 50%;
position: absolute;
-webkit-transform: translate3d(-50%, -50%, 0);
-moz-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
}
#categories > h3 {
display: inline;
}
The h3 elements are displaying inline and centered. I have the following code in jQuery that when you click an h3 element, the other elements fade out. It works well to remove the elements, but once they disappear, the selected element just suddenly flashes into the center (which is where I want it) but is there a way to animate this? Make it a smoother transition?
$("#categories h3").click(function(){
if(this.id == "sports"){
$("#videogames").fadeOut(500);
$("#music").fadeOut(500);
$("#web").fadeOut(500);
}
})
Use transition, much better.
$("#categories h3").click(function(){
if(this.id == "sports"){
$("#videogames, #music, #web").css({opacity: 0});
}
});
#categories {
left: 50%;
top: 50%;
position: absolute;
-webkit-transform: translate3d(-50%, -50%, 0);
-moz-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
}
#categories > h3 {
display: inline;
transition: opacity .3s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="categories">
<h3 id="sports">Sports</h3>
<h3 id="videogames">Video Games</h3>
<h3 id="music">Music</h3>
<h3 id="web">Web</h3>
</div>
May be you can use this. correct me if i am wrongly understood.
if(this.id == "sports"){
$("#videogames").fadeOut(500);
$("#music").fadeOut(500);
$("#web").fadeOut(500);
$("#sports").fadeOut(500);
$("#sports").fadeIn(500);
}
To answer your question about smoothly transitioning the selected element to the center try the below code.
Your fundamental problem is that "The .fadeOut() method animates the opacity of the matched elements. Once the opacity reaches 0, the display style property is set to none, so the element no longer affects the layout of the page." And so the remaining selected element jumps to the center. And you cannot transition to display: none. So you need to find a property you can animate, like "left" which I have used here.
[As an aside there is some extra code there because I was testing the ability to animate flex "order" but it doesn't work at this time on Edge, and untested on other browsers. You do not need the order properties.]
Hope this helps.
$("#categories h3").click( function() {
var thisID = this.id;
$.each( $("#categories h3"), function (index, val) {
if (thisID == val.id) {
var containerWidth = $("#categories").width();
var thisWidth = val.getBoundingClientRect().width;
var thisComputedLeft = val.getBoundingClientRect().left;
var adjustLeft = (containerWidth / 2) - thisComputedLeft - (thisWidth / 2);
// to center the clicked element
$(this).css({ left: adjustLeft });
}
else $(val).css({opacity: 0});
});
});
#categories {
position: relative;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-flow: row nowrap;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
justify-content: space-around;
align-content: center;
width: 100%;
height: 100%;
//margin: 0 auto;
}
#categories > h3 {
cursor: pointer;
position: relative;
left: 0;
width: auto;
transition: all 0.5s ease, opacity 0.3s;
// transition: opacity 0.3s;
}
#sports { order: 1; }
#videogames { order: 2; }
#music { order: 3; }
#web { order: 4; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="categories">
<h3 id="sports">Sports</h3>
<h3 id="videogames">Video Games</h3>
<h3 id="music">Music</h3>
<h3 id="web">Web</h3>
</div>
Try the following:
$("#categories h3").on('click', function(){
if(this.id == "sports"){
$("#videogames").fadeOut(500, function(){
$("#music").fadeOut(400, function(){
$("#web").fadeOut(300, function(){
$("#sports").fadeIn(400);
});
});
});
}
});
The callback function is called once the first animation is complete. You can nest the functions for a sequence animation.
Update:
Here are better examples for chaining animations: Chaining jQuery animations that affect different elements

Polymer 1.0 - HIDE Paper Drawer Panel

I am using Polymer 1.0 to implement paper-drawer-panel. I have some links on paper-header-panel topbar too. I have used the css selector for narrow to hide those links when narrow width. thus in mobile only using drawer for navigation. it looks like this right now on wide and narrow widths.
<paper-drawer-panel id="drawerPanel">
<paper-header-panel drawer id="test1">
<paper-toolbar><span>Menu</span></paper-toolbar>
<paper-menu vertical layout>
<paper-item data-route="home">Home</paper-item>
<paper-item data-route="about">About</paper-item>
<paper-item data-route="contact">Contact</paper-item>
<paper-item> Dropdown</paper-item>
</paper-menu>
</paper-header-panel>
<paper-header-panel main>
<paper-toolbar class="navbar">
<paper-icon-button icon="menu" id="navicon" paper-drawer-toggle></paper-icon-button>
<div>
TryDjango
</div>
<span class="flex"></span>
<paper-tabs selected="0" attr-for-selected="data-route" style="text-align:center" id="navbarmenu1">
<paper-tab>Home</paper-tab>
<paper-tab>About</paper-tab>
<paper-tab>Contact</paper-tab>
<paper-tab>Dropdown</paper-tab>
</paper-tabs>
<span class="flex"></span>
<paper-tabs selected="0" id = "navbarmenu2">
<paper-tab>Default</paper-tab>
<paper-tab>Static Top</paper-tab>
<paper-tab>Fixed Top</paper-tab>
</paper-tabs>
</paper-toolbar>
</paper-header-panel>
</paper-drawer-panel>
this is the css i used to hide my header-panel links when in narrow layout.
paper-drawer-panel[narrow] #navbarmenu1 {
display: none;
}
paper-drawer-panel[narrow] #navbarmenu2 {
display: none;
}
I gave those two paper-menu items IDs to hide them when [narrow]
HERE IS MY PROBLEM NOW:
I want to hide to drawer-panel all the time unless narrow. Like this:
I can't use force-narrow on my drawer panel as it will hide my paper-header links even in wide width.
So how can i make that drawer-panel hidden or implement what i want in a better way. any help is appreciated. :)
What you are looking for is implemented in the https://www.polymer-project.org/summit. They have implemented a custom element x-drawer. I am not sure whether the code for this website is published. However you can take a look at the code in your browser. It's well formatted. From that code, I see they have used 'visibility: hidden' to hide the drawer. Below is the complete definition of that element. Hope this helps!
<dom-module id="x-drawer" assetpath="../bower_components/app-layout/x-drawer/">
<style>
:host {
position: absolute;
top: 0;
right: auto;
bottom: 0;
left: 0;
width: 256px;
overflow: hidden;
background-color: var(--x-drawer-background-color, #fff);
visibility: hidden;
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
-webkit-transition: -webkit-transform 0.4s cubic-bezier(0.42, 0, 0.33, 1.01);
transition: transform 0.4s cubic-bezier(0.42, 0, 0.33, 1.01);
}
:host([position=right]) {
right: 0;
left: auto;
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
:host([position=top]) {
top: 0;
right: 0;
bottom: auto;
left: 0;
width: auto;
height: 256px;
-webkit-transform: translate3d(0, -100%, 0);
transform: translate3d(0, -100%, 0);
}
:host([position=bottom]) {
top: auto;
right: 0;
bottom: 0;
left: 0;
width: auto;
height: 256px;
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
:host([opened]),
:host([position][opened]) {
visibility: visible;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
</style>
<template>
<content></content>
</template>
<script>
Polymer({
is: 'x-drawer',
behaviors: [
Polymer.OverlayBehavior
],
properties: {
opened: {
type: Boolean,
value: false,
notify: true,
reflectToAttribute: true,
observer: '_hasOpenedChanged'
},
position: {
reflectToAttribute: true
}
},
listeners: {
'transitionend': '_onTransitionEnd'
},
toggle: function() {
this.opened = !this.opened;
},
_hasOpenedChanged: function(opened, prev) {
if (prev !== undefined) {
this.style.visibility = 'visible';
}
this.shouldEnableScroll(true);
},
_onTransitionEnd: function(e) {
if (e.currentTarget == this) {
this.style.visibility = '';
}
}
});
</script>
</dom-module>
In your case, try removing [narrow] on display: none as below
paper-drawer-panel #navbarmenu1 {
display: none;
}

AngularJS routing based on scroll

I'm using Angular for a project, and was wondering if it is possible to use Angular's routing functionality (or that of a 3rd party library such as ui-router) to control navigation in a scenario as demonstrated above.
If so, is it possible to have alternative routes in addition to this (e.g. a modal opens up presenting itself as a page)?
You could split your subsectons into different templates with different states and then use ui-router's animation API to do a transition between states. Here's an example impementation.
In your route config
app = angular.module('myApp', ['ui.router', 'ngAnimate']);
app.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('firstSubpage', {
url: '/',
template: '<div class="full-page">\
<h2>Page One</h2>\
<a ui-sref="secondSubpage">Next page</a>\
</div>'
})
.state('secondSubpage', {
url: '/page2',
template: '<div class="full-page two">\
<h2>Page Two</h2>\
<a ui-sref="firstSubpage">Next page</a>\
</div>'
})
}]);
In your CSS
/* set height explicitly on ui-view */
div[ui-view] {
position: absolute;
height: 100%;
width: 100%;
}
[ui-view].ng-enter, [ui-view].ng-leave {
position: absolute;
left: 0;
right: 0;
-webkit-transition:all .5s ease-in-out;
-moz-transition:all .5s ease-in-out;
-o-transition:all .5s ease-in-out;
transition:all .5s ease-in-out;
}
[ui-view].ng-enter {
-webkit-transform:translate3d(0, 100%, 0);
-moz-transform:translate3d(0, 100%, 0);
transform:translate3d(0, 100%, 0);
}
[ui-view].ng-enter-active {
-webkit-transform:translate3d(0, 0, 0);
-moz-transform:translate3d(0, 0, 0);
transform:translate3d(0, 0, 0);
}
[ui-view].ng-leave {
/*padding-left: 0px;*/
-webkit-transform:translate3d(0, 0, 0);
-moz-transform:translate3d(0, 0, 0);
transform:translate3d(0, 0, 0);
}
[ui-view].ng-leave-active {
/*padding-left: 100px;*/
-webkit-transform:translate3d(0, -100%, 0);
-moz-transform:translate3d(0, -100%, 0);
transform:translate3d(0, -100%, 0);
}
And then you just need an element with ui-view in your home template.
Here's a working example on plunker.

jQuery animate not working for left attribute

I am trying to use jQuery animate to fly logos (<img> elements) into position from outside the screen. And once again, it is not working.
Here is my javascript (the relevant part is in the fly() method.)
$(document).ready( function () {
logoFlyer.init();
});
var logoFlyer = {
numberOfLogos : 0,
init: function () {
logoFlyer.numberOfLogos = $('.logo').length;
logoFlyer.fly(1);
},
fly: function (index) {
logo = "#logo_" + index;
$(logo).delay(300).animate({'left':'0px'}, 300, function () {
if (index < logoFlyer.numberOfLogos) {
logoFlyer.fly(index + 1);
}
});
}
}
And here is my css
.logo {
height: 100px;
display:inline-block;
margin-right: 30px;
overflow:visible;
border: 1px solid white;
}
.logo img {
height: 80px;
left: 1500px;
position:relative;
}
When I set the logos' left to 0, they are indeed where I want them to go. So the problem lies with jQuery animate
If someone can help me out here you might just save me from ditching jQuery altogether and switching to angular.js.
So this code:
$(logo).delay(300).animate({'left':'0px'}, 300, function () {
if (index < logoFlyer.numberOfLogos) {
logoFlyer.fly(index + 1);
}
});
The interesting part here is $(logo) which i assume treated something like $('#logo_1') or $('#logo_2') etc.. So now the point is only position relative/absolute elements are able to be animated.
So you can check if this element has the position relative/absolute.
There's already a solution, but this solution is without jQuery (only CSS3!)
HTML
<ul>
<li class='logo'>
--- Image 1 ---
</li>
<li class='logo'>
--- Image 1 ---
</li>
<li class='logo'>
--- Image 1 ---
</li>
<li class='logo'>
--- Image 1 ---
</li>
CSS
.logo {
list-style: none;
text-align: center;
/** To the left by default **/
-webkit-transform: translate(-100%);
-moz-transform: translate(-100%);
-o-transform: translate(-100%);
-ms-transform: translate(-100%);
transform: translate(-100%);
/** Translate Animation --> 0.3s ease effect **/
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
-ms-transition: all 0.3s ease;
transition: all 0.3s ease;
}
.logo.show {
-webkit-transform: translate(0%);
-moz-transform: translate(0%);
-o-transform: translate(0%);
-ms-transform: translate(0%);
transform: translate(0%);
}
JS
var logoFlyer = {
numberOfLogos : 0,
init: function () {
logoFlyer.numberOfLogos = $('.logo').length;
setTimeout(function() {
logoFlyer.fly(0);
}, 300);
},
fly: function (index) {
// No need to add indexes
logo = $(".logo")[index];
$(logo).addClass("show");
setTimeout(function() {
logoFlyer.fly(index + 1);
}, 300);
}
}
$(function () {
logoFlyer.init();
});
Live Demo

Categories

Resources