AngularJS Material Slide Left to Right CSS3 Animation - angularjs

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);

Related

Angular - how to make $interval work from user input

I am taking date and time from user as input and then wanted to display it interval in label
After that datetime completes I want to make that label color change.
Please guide me how can i achieve this.
https://codepen.io/shreyag020/pen/vKvmdx
$interval(function(){
todoTime=$scope.datetime;
});
Here is an example of how you could change the background color of a div over time. Clicking the start button begins a countdown timer from 1 minute. It starts out with no background, once the timer is started it turns green, at 15 seconds before time runs out it turns orange and when the time has run out it turns red. The change of the background color is animated using ng-class, ngAnimate and the animation hooks.
angular.module('app', ['ngAnimate'])
.controller('ctrl', function($scope, $interval) {
var timerPromise;
$scope.reset = function() {
$scope.userTime = new Date;
$scope.userTime.setMinutes(1);
$scope.userTime.setSeconds(0);
$scope.resetVisible = false;
$scope.started = false;
}
$scope.start = function() {
$scope.started = true;
$scope.resetVisible = false;
timerPromise = $interval(function() {
if ($scope.userTime.getSeconds() > 0 || $scope.userTime.getMinutes() > 0) {
$scope.userTime.setTime($scope.userTime.getTime() - 1000);
}
}, 1000);
}
$scope.pause = function() {
$interval.cancel(timerPromise);
$scope.started = false;
$scope.resetVisible = true;
}
$scope.timeBackground = function() {
if ($scope.started) {
if ($scope.userTime.getMinutes() === 0 && $scope.userTime.getSeconds() === 0) {
$scope.resetVisible = true;
$interval.cancel(timerPromise);
return 'expired';
}
if ($scope.userTime.getMinutes() === 0 && $scope.userTime.getSeconds() <= 15) {
return 'warning';
}
return 'ok';
}
return 'clear';
}
$scope.reset();
});
.timeDisplay {
color: white;
font-weight: bold;
}
.ok-add,
.ok-remove,
.warning-add,
.warning-remove,
.expired-add,
.expired-remove {
transition: background-color 1000ms linear;
}
.warning,
.warning-add.pre-warning-add-active {
background-color: orange;
}
.expired,
.expired-add.expired-add-active {
background-color: red;
}
.ok,
.ok-add.ok-add-active {
background-color: green;
}
.clear {
background-color: none;
color: black;
}
div {
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-animate.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="timeDisplay" ng-class="timeBackground()">
Time remaining: {{userTime | date: 'mm:ss'}}
</div>
<div ng-if="!started">
<button ng-click="start()">Start</button>
</div>
<div ng-if="started">
<button ng-click="pause()">Pause</button>
</div>
<div ng-if="resetVisible">
<button ng-click="reset()">Reset</button>
</div>
</div>

Custom Directive is not working with div id

I have a custom directive called packageHeader, When the user scrolls through the list, the header must show at top of the list until the next one is reached. It's working with only window element not with div id, here i'm attaching the html
<div id="list">
<package-header>
<div>Header 1</div>
</package-header>
<div>content Header 1</div>
<package-header>
<div>Header2</div>
</package-header>
<div>content Header2</div>
<package-header>
<div>Header 3</div>
</package-header>
<div>content Header 3</div>
<div>
my custom directive
angular.module('myApp')
.directive('packageHeader',
['$window', function($window) {
var stickies = [],
scroll = function scroll() {
var header= angular.element(document.querySelector("#List"))[0];
console.log("scroll _ scroll");
angular.forEach(stickies, function($sticky, index) {
var sticky = $sticky[0],
pos = $sticky.data('pos');
if (pos <= header.pageYOffset) {
console.log("scroll offset Y");
var $next = stickies[index + 1],
next = $next ? $next[0] : null,
npos = $next.data('pos');
$sticky.addClass("fixed");
if (next && next.offsetTop >= npos - next.clientHeight)
$sticky.addClass("absolute").css("top", npos - sticky.clientHeight + 'px');
} else {
console.log("scroll offset X");
var $prev = stickies[index - 1],
prev = $prev ? $prev[0] : null;
$sticky.removeClass("fixed");
if (prev && header.pageYOffset <= pos - prev.clientHeight)
$prev.removeClass("absolute").removeAttr("style");
}
});
},
link = function($scope, element, attrs) {
var sticky = element.children()[0],
$sticky = angular.element(sticky);
element.css('height', sticky.clientHeight + 'px');
$sticky.data('pos', sticky.offsetTop);
stickies.push($sticky);
};
angular.element(document.querySelector("#List"))
.off('scroll', scroll)
.on('scroll', scroll);
return {
restrict: 'E',
transclude: true,
//sticky - getting from style sheet
template: '<sticky ng-transclude></sticky>',
link: link
};
}]);
CSS
package-header,
sticky {
display: block;
}
package-header{
opacity:.8;
}
package-header>sticky {
background: #9aa2a8;
line-height: 24px;
z-index: 1;
color: #fff;
font-weight: 700;
}
package-header>sticky.fixed {
position: fixed;
top: 0;
width: 100%;
z-index: 0;
}
package-header>sticky.fixed.absolute {
position: absolute;
}
Please help me to resolve my issue

Setting the values in multi-select isteven of angular js

I'm trying to use Angularjs multi-select into my project.
The following html is my multi-select div.
<div
multi-select
input-model="marks"
output-model="filters.marks"
button-label="name"
item-label="name"
tick-property="ticked"
selection-mode="multiple"
helper-elements="all none filter"
on-item-click="fClick( data )"
default-label="Select marks"
max-labels="1"
max-height="250px"
>
</div>
I know that I can use $scope.marks=data in the controller.
But the problem is $scope.marks is a global variable which I couldn't change..
Is there any way to set the values in multi-select without using the input-model?
Well, doing some tests here, i could get something with multiselecting:
var languages = ["C#", "Java", "Ruby", "Go", "C++", "Pascal", "Assembly"]; //The items.
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.marks = {};
for (lang in languages) {
$scope.marks[lang] = {
name: languages[lang],
marked: false
};
}
$scope.marks[3].marked = true; //mark "Go" and "C++" by default.
$scope.marks[4].marked = true;
$scope.theMarkedOnes = function() {
outp = "";
for (m in $scope.marks) {
if ($scope.marks[m].marked)
outp += $scope.marks[m].name + ", ";
}
if (outp.length == 0) {
return "(none)";
} else {
return outp.substr(0, outp.length - 2);
}
}
$scope.setMark = function(markone) {
markone.marked = !markone.marked;
}
})
*,
*:before,
*:after {
box-sizing: border-box;
}
body {
font-family: sans-serif;
font-size: 0.7em;
}
::-webkit-scrollbar {
width: 7px;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5);
}
.multiselector {
background-color: #CCCCCC;
overflow-y: scroll;
width: 17em;
height: 13em;
border-radius: 0.7em;
}
.multiselector .item {
cursor: pointer;
padding: 0.2em 0.3em 0.2em 0.0em;
}
.itemtrue {
background-color: #9999AA;
}
.msshow {
background-color: #cccccc;
border-radius: 0.7em;
margin-top: 1em;
padding: 0.6em;
width: 17em;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div class="multiselector">
<div ng-repeat="mark in marks" class="item item{{mark.marked}}" ng-click="setMark(mark)">{{mark.name}}</div>
</div>
<div class="msshow"> <b>Selected:</b> {{theMarkedOnes()}}</div>
</div>
Set & Get selected values, name and text of Angularjs isteven-multi-select
<div isteven-multi-select
input-model="marks"
output-model="filters.marks"
button-label="name"
item-label="name"
tick-property="ticked"
selection-mode="multiple"
helper-elements="all none filter"
on-item-click="fClick( data )"
default-label="Select marks"
max-labels="1"
max-height="250px">
</div>
Add items
$scope.marks= [
{ name: 'Mark I', value: 'Mark i', text: 'This is Mark 1', ticked: true },
{ name: 'Mark II', value: 'Mark ii', text: 'This is Mark 2' },
{ name: 'Mark III', value: 'Mark iii', text: 'This is Mark 3' }
];
Get selected item (on change)
$scope.fClick = function (data) {
console.log(data.name);
console.log(data.value);
console.log(data.text);
return;
}
Select item (with code)
$scope.abc = function (data) {
console.log(data.element1, data.element2);
angular.forEach($scope.marks, function (item) {
if (item.value == data.element1) {
item.ticked = true;
}
else {
item.ticked = false;
}
});
}
Deselect item (clear)
$scope.ClearClick = function () {
$scope.Filter = { selectMarks: 'Mark i' };
$scope.marks.map(function (item) {
if ($scope.Filter.selectMarks == item.value)
item.ticked = true;
else
item.ticked = false;
});
}

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