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.
Related
I certainly hope that you guys can show me where did I go wrong.
So I try to put together ui-router with ng-animate. Routing works like charm. However, ng-animate staggers to kick in. According to all the samples and docs that I've been reading, the ui-view container should be duplicated, but it does not occur. Instead the container's innerHTML is replaced. I also use an external animation library called animate.css
So I put together a plunkr in hope that some of you could help me out.
Here is a plunkr demo
view1:
<section class="view1" >
<h1>VIEW 1</h1>
<a ui-sref="view2">view2</a>
</section>
view2:
<section class="view2" >
<h1>VIEW 2</h1>
<a ui-sref="view1">view1</a>
</section>
styles:
body {
width: 100%;
}
.view-container {
width: 100%;
}
.view-container.ng-enter .view1,
.view-container.ng-enter .view2,
.view-container.ng-leave .view1,
.view-container.ng-leave .view2 {
position: absolute;
left: 30px;
right: 30px;
transition: 0.5s all ease;
-moz-transition: 0.5s all ease;
-webkit-transition: 0.5s all ease;
}
.view-container.ng-enter .view1,
.view-container.ng-enter .view2 {
-webkit-animation: slideInRight 0.5s both ease;
-moz-animation: slideInRight 0.5s both ease;
animation: slideInRight 0.5s both ease;
}
.view-container.ng-leave .view1 .view-container.ng-leave .view2 {
-webkit-animation: slideOutLeft 0.5s both ease;
-moz-animation: slideOutLeft 0.5s both ease;
animation: slideOutLeft 0.5s both ease;
}
.view1,
.view2 {
width: 100%;
height: 300px;
border: 2px solid red;
}
.view2 {
border: 2px solid green;
}
scripts:
'use strict';
var mainModule = angular.module('poc', ['ui.router', 'ngAnimate']);
mainModule.config(["$stateProvider", "$urlRouterProvider",
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('view1', {
url: '/view1',
templateUrl: 'view1.html',
}).state('view2', {
url: '/view2',
templateUrl: 'view2.html',
});
$urlRouterProvider.otherwise('/view1');
}
]);
mainModule.run(["$rootScope", "$state",
function($rootScope, $state) {
$rootScope.$on('$stateChangeSuccess', function(event, endState, endParams, startState, startParams) {
console.log(endState);
});
$rootScope.$on('$stateChangeError', function(event, endState, endParams, startState, startParams) {
console.warn(startState);
console.warn(endState);
});
}
]);
index.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body data-ng-app="poc">
<div ui-view="" class="view-container"></div>
<script src="https://code.angularjs.org/1.4.9/angular.js" data-semver="1.4.9" data-require="angular.js#1.4.9"></script>
<script src="https://code.angularjs.org/1.4.9/angular-animate.js" data-semver="1.4.9" data-require="angular-animate#*"></script>
<script data-require="ui-router#0.2.18" data-semver="0.2.18" src="//cdn.rawgit.com/angular-ui/ui-router/0.2.18/release/angular-ui-router.js"></script>
<script src="script.js"></script>
</body>
</html>
Any help is appreciated.
You need to add some animation definitions for slideInRight and slideOutLeft
Can use animate.css library for those.
For starters I suggest moving the animation selectors to your <ui-view> element
What actually happens is when a transition time is detected....the element will be cloned allowing for 2 in dom at once ... one entering and one leaving. You can see this in the live html in browser dev tools
DEMO
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 ?
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
I'm encountering some strange behavior in one of my web apps when using Angular's routeProvider as a template engine. Although it works, it doesn't make sense to me why it works.
Whats happening is that during transitions from page to page (mostly in safari/mobile safari) you will see the page you're transitioning to flicker in the front of view before transitioning in. How I fixed this problem is just by adding a slash to the end of the href's url, ex:href="#/home/" instead of href="#/home . Does anyone out there know why adding a "/" to the url would fix such a problem?
I set up the routeProvider like this:
.config(function($routeProvider) {
$routeProvider.when('/home', {
controller : 'HomeCtrl',
templateUrl : './home.html'
}).when('/pageTwo', {
controller : 'twoCtrl',
templateUrl : './pageTwo.html'
}).otherwise({
redirectTo: '/home'
});
})
My html like this:
<ul id="nav">
<li>
HOME
</li>
<li>
TWO
</li>
</ul>
and css like this:
.view-animate-container {
position:relative;
width: 100%;
height: 100%;
}
.view-animate {
position: absolute;
width: 100%;
height: 100%;
-webkit-perspective: 1000;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.view-animate.ng-enter, .view-animate.ng-leave {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
}
.view-animate.ng-enter {
opacity:0;
-webkit-transform: translate3d(20%,0,0);
transform: translate3d(20%, 0, 0);
}
.view-animate.ng-enter.ng-enter-active {
display: block;
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0, 0, 0);
opacity:1;
}
.view-animate.ng-leave.ng-leave-active {
-webkit-transform: translate3d(-20%,0,0);
transform: translate3d(-20%, 0, 0);
opacity:0;
}
Is there a reason why you link to the hash instead of the route itself?
Have you tried changing your links to Home instead of href="#/home" ?
Angular will manage the hash for you, (or not, if your browser supports pushState).
I am trying to toggle between two animation classes within my ng-view. This is how I have my ng-view setup in my html:
<div id="animation-container" class="view-animate-container">
<div id="ng-view" ng-view class="view-animate"></div>
</div>
And here is the css for my first animation
.view-animate.ng-enter, .view-animate.ng-leave {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.8s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.8s;
display:block;
position:absolute;
top:0;
left:0;
}
.view-animate.ng-enter {
-webkit-transform: translate3d(100%, 0, 0);
}
.view-animate.ng-enter.ng-enter-active {
-webkit-transform: translate3d(0, 0, 0);
}
.view-animate.ng-leave.ng-leave-active {
-webkit-transform: translate3d(-100%, 0, 0);
}
2nd animation:
.view-leave.ng-enter, .view-leave.ng-leave {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.8s;
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.8s;
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.8s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.8s;
display:block;
position:absolute;
top:0;
left:0;
}
.view-leave.ng-enter {
opacity:0;
-webkit-transform: translate3d(-100%, 0, 0);
}
.view-leave.ng-enter.ng-enter-active {
opacity:1;
-webkit-transform: translate3d(0, 0, 0);
}
.view-leave.ng-leave.ng-leave-active {
opacity:0;
-webkit-transform: translate3d(100%, 0, 0);
}
All I'm trying to do is change the class from view-enter to view-leave when the back button is clicked.
<a id="back-btn" class="btn back" href="javascript:history.back()">BACK</a>
This Jquery code I wrote almost got the job done, but not 100%:
$("#back-btn").click(function(){
$("#ng-view").attr('class','view-leave');
});
It seemed to animate the leaving container in the right direction, but not the entering container. So I'm looking for a simple solution to what seems like a simple problem.
You don't even need jQuery for this, you can use Angular's ng-class attribute. Add an ng-click to your back button which calls a function inside your controller. Something like this:
In your HTML:
<div id="animation-container" class="view-animate-container">
<div id="ng-view" ng-view class="view-animate" ng-class="animationClass"></div>
</div>
<a class="btn back" href="javascript:history.back()" ng-click="toggleAnimation()">BACK</a>
In your Controller:
$scope.animationClass = "view-enter";
$scope.toggleAnimation = function() {
if ($scope.animationClass === "view-enter") {
$scope.animationClass = "view-leave";
} else if ($scope.animationClass === "view-leave") {
$scope.animationClass = "view-enter";
}
};
I found a different way with the new $routeChangeStart event.
This solution saves history to check if the next page is actually the previous page.
Place this in your controlller:
$scope.backward = false;
$scope.history = [];
$scope.$on('$routeChangeStart', function(next, current) {
var previous = $scope.history[$scope.history.length - 2];
if (previous && current.originalPath === previous.originalPath) {
$scope.backward = true;
$scope.history.pop();
} else {
$scope.backward = false;
$scope.history.push(current);
}
});
Then use a container around your ng-view with an ng-class reacting to the $scope.backward.
<div ng-class="{'backward': backward}">
<ng-view class="view-animate">
</div>
And have two CSS animations. The forward on .view-animate or whatever class you use for your ng-view. And the backward on .backward .view-animate.
Just for anyone else that might be looking for a simple solution to this question, expanding off #muenchdo answer. I set a timeout to revert to the previous animation after the transition was over.
like this:
$scope.animationClass = "view-enter";
$scope.toggleAnimation = function() {
$scope.animationClass = "view-leave";
$timeout(function() {
$scope.animationClass = "view-enter";
}, 350);
}
This was the simplest way I could find out there, hopefully this helps someone out there that is looking for a simple solution to what seems like simple functionality.