ng-animate and ng-if cause transition not to played in Internet Explorer - angularjs

I have a simple div which has a transition. It transitions from a yellow background to a red one.
<div class="foo" ng-class="{'foo-visible': vm.visible}">
The transition is played once the foo--visible class is added to the div.
This works fine in Chrome, IE...etc.
However once I add a wrapper div around it, the transition stops working in Internet Explorer (tested with IE10).
<div class="foo--wrapper" ng-if="vm.visible">
<div class="foo" ng-class="{'foo--visible': vm.visible}">
</div>
I need to include ngAnimate in this case. Then it works in Chrome, but in IE I immediately get the red div, the transition is never played. No transitionstart (IE only) or transitionend events are fired.
Here's a plunker illustrating the issue:
http://plnkr.co/vpJzudnLxTwoJGZoZaNd
Does anybody have an idea what is causing this?

This plnkr adds two similar boxes to yours. http://plnkr.co/edit/lkyWHu?p=preview
<div ng-if="vm.visible">
<div class="animate-box animate-if">
<h2>Inner Class</h2>
</div>
</div>
<div class="animate-box animate-if" ng-if="vm.visible">
<div>
<h2>Outer Class</h2>
</div>
</div>
The "Outer" works in both IE and Chrome.
Chrome iterates the child animation for "Inner" in a way that makes sense. Internet Explorer, as for your example, does not.
On closing, neither do the child animation because the delay to remove the parent is zero.
An interesting point though, IE and Chrome appear to work the same for the authoritative answer at https://docs.angularjs.org/api/ngAnimate/directive/ngAnimateChildren
The CSS I used was:
.animate-box {
height: 100px;
width: 100px;
background-color: red;
}
.animate-if.ng-animate {
transition: all 3s linear;
}
.animate-if.ng-enter,
.animate-if.ng-leave.ng-leave-active {
background-color: yellow;
opacity: 0;
}
.animate-if.ng-leave,
.animate-if.ng-enter.ng-enter-active {
background-color: red;
opacity: 1;
}

Related

Blueimp Gallery inside Boostrap Modal not vertical aligned properly

I have a modal window that shows a few data that also has Images which open in Blueimp gallery. The problem I have is, when the image is opened in BlueImp gallery, the image is not vertically aligned in the middle of the screen. Its either to the bottom or to the top and it depends on where I have scrolled in the modal window. I need to go to the middle of the modal window and open the gallery in which case the Lightbox looks centered. This issue doesnt happen when blueimp is used directly in the page without a modal. It appears the blueimp gallery's lightbox is centered to the whole modal height instead of the viewport height. How can I override that for blueimp inside modal windows only? Is there a css fix or js fix to override this when blueimp is used in boostrap modals?
Here is a sample of my set-up:
<div uib-modal-window="modal-window" class="modal fade" role="dialog" size="xl" index="0" animate="animate" ng-style="{'z-index': 1050 + $$topModalIndex*10, display: 'block'}" tabindex="-1" uib-modal-animation-class="fade" modal-in-class="in" modal-animation="true" style="z-index: 1050; display: block;">
<div class="modal-dialog modal-xl">
<div class="modal-content" uib-modal-transclude="">
<div class="lightBoxGallery">
<a ng-repeat="image in vm.ngModel" ng-href="{{::vm.imageurl(image.name)}}" data-gallery="">
<img ng-src="{{::vm.getImage(image.name)}}" class="img-responsive img-thumbnail animated fadeIn">
</a>
<div id="blueimp-gallery" class="blueimp-gallery">
<div class="slides"></div>
<h3 class="title"></h3>
<a class="prev">‹</a>
<a class="next">›</a>
<a class="close">×</a>
<a class="play-pause"></a>
<ol class="indicator"></ol> </div>
</div>
</div>
</div>
</div>
My set-up: Angular 1.5 + Bootstrap 3 + Bootstrap UI + BlueImp Gallery
UPDATE:
The problem I am having here is, my Bootstrap Modal window has overflow-y as scrollable and it has a fixed positioning:
.modal-open .modal {
overflow-x: hidden;
overflow-y: auto;
}
.modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1050;
display: none;
overflow: hidden;
-webkit-overflow-scrolling: touch;
outline: 0;
}
And when the blueimp-gallery is opened, as a child div with fixed position, it is positioning the Div to the center of the parent's fixed position instead of center of the viewport:
.blueimp-gallery {
position: fixed;
z-index: 999999;
overflow: hidden;
background: #000;
background: rgba(0,0,0,.9);
opacity: 0;
display: none;
direction: ltr;
-ms-touch-action: none;
touch-action: none;
}
The blueimp-gallery is aligning to the middle, but I dont want it aligning to the middle of parent (modal) div. I want it aligned to the middle of viewport. For example, in my laptop, my modal has a height of 2000px where as my viewport height is a lot less like 860px. That is why the gallery lightbox is opening either to the top or bottom of the viewport unless the user is right in the middle of the modal window. If I place the blueimp-gallery directly in the body without the modal window, I dont have this issue. But in this use case, I have to place the blueimp-gallery inside a Modal window that has variable height depending on the dynamic content loaded in it.
I am still stuck on this, does anyone have a suggestion to this problem please?
The only way I was able to resolve this issue was to pull the "#blueimp-gallery" element out of the Modal Window and then insert it again as a direct child of the body element. Using Jquery, I added this code that fixed the issue:
$(document).ready(function(){
$("#blueimp-gallery").prependTo($("body"));
});
Now, after the above code, the BlueImp Gallery's fixed position is relative to the body element and therefore the height is that of the viewport. The Modal height no longer affects the BlueImp Gallery's height since it is now placed as a direct child of body element.
You should try to put the blueimp in a div with the class row and then another div with the class col-md-6 not 100% sure but it should be alligned in the middle then.
<div class="container">
<div class="row">
<div class="col-md-6">
<div id="blueimp-gallery" class="blueimp-gallery vcenter ">
...
</div>
</div>
</div>
Edit tried it it has to have container tag above it to.
most likely this is not the sollution to getting it to the center vertically but this is worth a try i guess
ADDITION
.vcenter {
display: inline-block;
vertical-align: middle;
float: none;
}
create a costum tag add it in a css file and call on it.

AngularJS ng-click on mobile device fire at wrong position

I'm using Ionic Framework to develop a mobile application for Android.
My issue is that I need to have a list of containers at random positions and are able to be clicked.
The list of containers are displayed correctly at the random positions but the click areas only work when i click at the top of the view, not at the position itself.
The clicking works fine in the mobile browsers at the correct position but when I run the app as a native application in Android, the clicks messed up.
It seems like clicking areas are lined up at the top of the view, does anyone know what is causing this?
The codes are here:
HTML file
<div class="col" ng-model="qtablelayout">
<div qtable ng-model='qtable' ng-repeat='qtable in qtablelayout.qtables' class="tablediv" ng-class="qtable.tstatus" ng-style="{'left': {{qtable.x}}+'px', 'top':{{qtable.y}}+'px'}" ng-click="tblActions(qtable)">
<h2>{{qtable.tableNo}}</h2>
<ul>
<li class="tablesize">{{qtable.currentHP.qsize}}/{{qtable.maxSize}}</li>
<li class="tabletime">{{qtable.tabletime.hours}}h {{qtable.tabletime.mins}}m {{qtable.tabletime.secs}}s</li>
</ul>
</div>
</div>
CSS file
div.tablediv
{
position: absolute;
background: url("../img/table/tablestatus.png") no-repeat;
color: #fff !important;
width: 178px;
height: 178px;
padding: 0;
margin: 0;
text-align: center;
display: block;
overflow: hidden;
}
The Controller side
$scope.tblActions = function(m)
{
alert("x:" + m.x + ",y:" + m.y);
}
I found out the cause of the problem is that I had an Ion-Refresher before the list of containers and it seemed to have shifted up the clicking areas together with the space for the Ion-Refresher.
It worked when I put the Ion-Refresher at the bottom of the HTML.

How to implement a flip over effect using AngularJS animations?

What would be the best way to achieve a flip over effect using AngularJS animations?
I would like the flip over effect to occur on click. Every time it's clicked, it should flip over to the other side.
Ideally, I guess, I'm looking for a directive implementation that uses Angular animations.
PLNKR - here is a seed of a configurable angular directive that provides 3d flipping functionality. I do not see any good reason why to use ngAnimate for it.
basic usage
<flip flip-width="200px" flip-height="100px">
<flip-panel>
content-front
</flip-panel>
<flip-panel>
content-back
</flip-panel>
</flip>
Comments
It appends css-styles on its own, to be fully independent.
In a proper, generic directive all names should be configurable.
flip-width and flip-height sets style of flip and both flip-panels.
Directive makes some basic check, if both front and back are set.
First flip-panel is front and the second is back.
Due to usage of transclusion content of the flip-panel may be arbitrary html. (you are right Misha no transclusion needed)
It only works in -webkit. (update to make it work in Firefox, just duplicate all pieces with -webkit with no prefix - you do not need -moz)
UPDATE
PLNKR - here is an updated and extended version. It shows what I meant by making the directive configurable. In more details:
Introduced flipConfig via provider, that allows to set in app.config:
default dimensions
css class names
speed of the transition
if the flip action is triggered by a click on the panel
Introduced flip-show attribute that specifies which side to show.
Changing flip-show we can trigger the flip action from outside of the directive.
It works in Firefox and [almost:-)] in IE11.
(btw: it is just a seed and it may be improved in a lot of ways. E.g: specifying axis, specifying origin of the transform, specifying radius and margin of the panels, allowing flip on hover, defaults colors, margins and so on)
I had the same usecase just recently for an angular memory game.
My implementation is the same by the idea of the other answers. I also released the flipping code along with a DEMO.
Github: https://github.com/zwacky/angular-flippy
P.s.: Looks i'm late to the party ;)
You can use ng-click and ng-class to add a class when the flip container is clicked.
<div class="flip-container" ng-click="flip = !flip" ng-class="{'flip': flip}">
<div class="flipper">
<div class="front" style="background: lightblue;">
front
</div>
<div class="back" style="background: lightgreen;">
back
</div>
</div>
</div>
This is essentially the angular way of doing what Walsh suggested in his article:
Adding the flip class to the container element will flip the card using JavaScript -- no user hover required. A JavaScript comment like document.querySelector("#myCard").classList.toggle("flip") will do the flip!
The only change to David Walsh's css was removing the :hover selector - the html structure is unchanged. It works nicely in chrome and firefox.. but the flip isn't as pretty in IE.
Here is a working demo: http://plnkr.co/edit/0dn775vpuoOeh2PS1T6k?p=preview
Update
I created a simple directive to encapsulate this basic technique. It allows you to flip over a black card, to reveal a picture on the other side.
app.directive("flipReveal", function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'template.html',
scope: {
url: '=',
flip: '='
}
}
})
Here is a link to a new demo: http://plnkr.co/X4pSav
Disclaimer Based on #artur's answer https://stackoverflow.com/a/23139242/1319998 , but hopefully both simplified and made more flexible.
A custom directive is the way to go, one that can be used as:
<flip flip-side="{{side}}">
<flip-front>
Front side contents
</flip-front>
<flip-back>
Rear contents
</flip-back>
</flip>
I think it should have certain properties:
Programatically controlled by an attribute. In this case, a string that is equal to 'front' or 'back'
<flip flip-side="{{side}}">....</flip>
this would allow programmatic access via the surrounding scope.
Integrated with ngAnimate/$animate. Specifically, if ngAnimate is removed or disabled, the animation should not occur, but the reveal of the other side happen immediately. Using $animate.addClass/$animate.removeClass would achieve this, adding/removing a flip-visible class together with display:block and display:none styles to make sure the right side is visible/hidden when the animations are disabled.
flip > flip-front, flip > flip-back {
display: none;
}
flip > .flip-visible {
display: block;
}
Controlled by CSS, with defaults. So if you want to change the duration of the flip, it's a CSS, and not a Javascript, addition.
So it will have a style sheet to add styles required for the various stages of $animate.addClass / $animate.removeClass CSS animations explained at Year of Moo and $animate docs . The class will be flip-visible, so the extra classes will be .flip-visible-add, .flip-visible-add-active, .flip-visible-remove, and .flip-visible-remove-active classes.
The full set of styles can be seen at http://plnkr.co/edit/bbYbMhiURnm6FqC9patp?p=preview, but the main construction is of the form:
.flip-visible-add {
// Initial setup: time and initial, pre-animation, transform
}
.flip-visible-add.flip-visible-add-active {
// Target transform
}
Putting all this together, the directive is quite short:
app.directive("flip", function($animate) {
return {
restrict : "E",
controller: function($scope, $element, $attrs) {
var elements = {
'front': $element.find('flip-front'),
'back': $element.find('flip-back')
};
$attrs.$observe('flipSide', function(visibleSide) {
visibleSide = visibleSide || 'front';
var otherSide = visibleSide == 'front' ? 'back' : 'front';
$animate.removeClass(elements[otherSide], 'flip-visible');
$animate.addClass(elements[visibleSide], 'flip-visible');
});
}
}
});
This can all be seen in an example, together with the stylesheets to make it all work, at http://plnkr.co/edit/bbYbMhiURnm6FqC9patp?p=preview
I realise there is a benefit to not integrating with the $animate service, and having a purely class-based solution.
If you use $animate with addClass and removeClass, but interrupt the animation (say, by clicking quickly and repeatedly on the element), the animation will 'jerk' to its end/starting point, and then animate from that position, at least on Chrome. Using a pure CSS solutions avoids this issue, and always animates from the exact current point, giving a smoother effect.
An added benefit is the solution is also simpler, and you don't need a custom directive.
For example, the HTML can be as follows:
<flip class="{{side === 'front' ? 'flip-front' : 'flip-back'}}">
<flip-front>
Front side contents
</flip-front>
<flip-back>
Rear contents
</flip-back>
</flip>
I use custom elements, but they don't need to have any directives attached: they are just for CSS to hook into:
flip > flip-front, flip > flip-back {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
/* Time can be overriden */
transition: -webkit-transform 0.5s;
transition: transform 0.5s;
}
/* Front visible */
flip > flip-front {
-webkit-transform: perspective(800px) rotateY(0);
transform: perspective(800px) rotateY(0);
}
flip > flip-back {
-webkit-transform: perspective(800px) rotateY(180deg);
transform: perspective(800px) rotateY(180deg);
}
/* Back visible */
flip.flip-back > flip-front {
-webkit-transform: perspective(800px) rotateY(-180deg);
transform: perspective(800px) rotateY(-180deg);
}
flip.flip-back > flip-back {
-webkit-transform: perspective(800px) rotateY(0);
transform: perspective(800px) rotateY(0);
}
This can be seen in a demo at http://plnkr.co/edit/A7IeGa1JEsZishmTDTaK?p=preview
I would simply add / remove a class on click.
If you want to hook into the angular animation system then take a look at the $animate service, in particular add/remove/setClass(). The service is usually used in directives. You might want to create a directive that reacts on a click event and triggers the animation. You even get informed when the animation has completed.
Chances are that it's not worth it ;)
You are going to want to create 3 divs.
<div class="wrapper">
<div class="front"></div>
<div class="back"></div>
</div>
You then position back behind front using z-index, and flip it upside down using rotateX (-180deg or so). Set a transition on wrapper as well.
Then, on click of wrapper, rotateX(+180deg). This will pretty much infinitely flip it over.
** Update: For angular, bind to click and use setClass to toggle between two classes on wrapper, one at rotateX(0deg) , the other at rotateX(180deg)
Here is a slightly modified version of artur's answer:
DEMO
angular.module('FlipDemo', []).directive("flip", function() {
return {
restrict : "A",
scope: true,
link: function(scope, element) {
var $panels = element.css({ position: 'relative' }).children().addClass("flip-panel");
var frontPanel = $panels.eq(0);
var backPanel = $panels.eq(1);
scope.showFrontPanel = function() {
frontPanel.removeClass("flip-hide-front-panel");
backPanel.addClass("flip-hide-back-panel");
};
scope.showBackPanel = function() {
backPanel.removeClass("flip-hide-back-panel");
frontPanel.addClass("flip-hide-front-panel");
};
scope.showFrontPanel();
}
}
});
.flip-panel {
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-webkit-transition: -webkit-transform .4s;
-moz-transition: -moz-transform .4s;
-webkit-transform: perspective(800px) rotateY(0deg);
-moz-transform: perspective(800px) rotateY(0deg);
}
.flip-hide-back-panel {
-webkit-transform: perspective(800px) rotateY(180deg);
-moz-transform: perspective(800px) rotateY(180deg);
}
.flip-hide-front-panel {
-webkit-transform: perspective(800px) rotateY(-180deg);
-moz-transform: perspective(800px) rotateY(-180deg);
}
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.1/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-app="FlipDemo">
<div style="width: 100px; height: 150px">
<div flip style="width: 100%; height: 100%">
<div style="background-color: green">
<div>Front</div>
<button ng-click="showBackPanel()">Show Back</button>
</div>
<div style="background-color: blue">
<div>Back</div>
<button ng-click="showFrontPanel()">Show Front</button>
</div>
</div>
</div>
<br>
<div style="width: 150px; height: 100px">
<div flip style="width: 100%; height: 100%">
<div style="background-color: green">
<div>Front</div>
<button ng-click="showBackPanel()">Show Back</button>
</div>
<div style="background-color: blue">
<div>Back</div>
<button ng-click="showFrontPanel()">Show Front</button>
</div>
</div>
</div>
</body>
</html>
Main differences:
Works in Chrome and Firefox.
More flexibility with when the flip happens.
Just one directive rather than two. Less code.
I took the CSS outside of the directive for clarity sake.

How to fade in a text after page loaded?

I'm trying to get a div container with some text to fade in after the page loaded, but I fail. I was using the ng-animate directive like this:
<div class="motd" style="text-align: center;" ng-init="quote = getQuote();">
<div class="slide-fade" ng-class="animation">
<span class="quote"><i>{{quote.content}}</i></span><br><br>
<span class="author">{{quote.author}}</span>
</div>
</div>
Which obviously does not work, due to the fact that the animation does not get triggered by a click or something like that.
So how do I tell the browser that after the page loaded, it should fade in my text?
I hope you can help me!
Edit: At the date where I asked, I did not know that animations will also trigger when the page has loaded. I always thought there have to be some "user interaction" like a click or something to trigger them.
If you're using bootstrap, you can do this:
<html ng-app="myApp" ng-strict-di>
<head>...</head>
<body ng-init="ngLoaded = true" class="fade" ng-class="{ in: ngLoaded }">
<div>Content</div>
</body>
</html>
It may also work do to it this way as well:
<body
ng-app="myApp"
ng-strict-di
ng-init="ngLoaded = true"
class="fade"
ng-class="{ in: ngLoaded }">
<div> Content </div>
</body>
The fade class has 0 opacity and the in class applies the transition. ngLoaded will become true (in the $rootScope, I believe) as soon as angular has loaded due to ng-init="ngLoaded = true".
I use this so that the page doesn't blip with bits of angular brackets and such while the page loads.
I don't see the problem.
You just want to have animation when the element appears( you can think about it that way right? ).
Basicaly what I would do.
I would use then animate.css
http://daneden.github.io/animate.css/
and I would just add:
class="animated fadeIn"
Or plain css with this animation.
What I like to do is to use delay
.delayedx1{
animation-delay: 0.2s !important;
-webkit-animation-delay: 0.2s !important;
-moz-animation-delay: 0.2s !important;
-o-animation-delay: 0.2s !important;
-webkit-transition-delay:0.2s;
transition-delay:0.2s;
}
x2 x3 x4 or in ng repeat delay directly in "style" based on $index.
One way to do this is to use a flag (like $scope.fade = false;) to indicate that the page has loaded. Then, on your element, you'd use an ng-class with a conditional e.g.
class="animation" ng-class="{'fade-in': fade }"
The actual fade would be handled by CSS.
.animation { opacity:0; transition:all 200ms ease-in-out; }
.animation.fade-in { opacity:1; }
In your case, the fade-in condition could be as simple as ng-class="{'fade-in': quote }" since any truthy value you cause the class to get applied.
Here's a working plunker for you to play around with: http://plnkr.co/edit/ncqEB3PafIWbwv0UH1QG?p=preview

Tell ngAnimate to only animate ngShow/ngHide

I have an AngularJS 1.2.2 web application with a <div> that I show/hide based on some $scope property. Using the ngAnimate module, I animate the showing and hiding of the <div>.
<div id="square" ng-show="showSquare" class="animate-shiny"></div>
I also have a class I want to place on this <div> and for this I use ngClass.
<div id="square" ng-show="showSquare" class="animate-shiny" ng-class="{ cool: extraCool }"></div>
And as it so happens, sometimes that class gets applied at the same moment as when the <div> is shown/hidden. This causes the show/hide animation to not work anymore, apparantly it finds ngClass more interesting to animate, even though I don't want to use ngAnimate for that animation.
Here's a Plnkr that demonstrates the behavior. Clicking the show/hide button works great, clicking the make cool button works great, but the button that combines these two causes the show/hide animation to break.
How do I fix this? And can I do it without manually addressing $animate?
Thanks in advance!
The problem is that you are trying to animate using the class and not discriminate between when things should animate. That is, your transition effect applies to the class in general, which ng-animate perceives as having to do work whenever that class is referenced. I modified your css a bit to get pretty close, if not exactly, what you want:
#square {
width: 50px;
height: 50px;
background-color: blue;
transition: 0.4s all ease-out;
}
#square.cool {
box-shadow: 0 0 10px 3px green;
background-color: lightgreen;
}
#square.ng-hide-add, #square.ng-hide-remove
{
display: block !important;
}
#square.ng-hide-remove, #square.ng-hide-add.ng-hide-add-active{
margin-left: -80px;
opacity: 0;
}
#square.ng-hide-remove.ng-hide-remove-active, #square.ng-hide-add{
margin-left: 0;
opacity: 1;
}
Here is the new plunkr so you can play with it: http://plnkr.co/edit/a7wiZfCrEGCXfIDSvF9r?p=preview
If you want to ONLY animate the show/hide and do not want a transition for the color, simply move the transition to the #square.ng-hide-add, #square.ng-hide-remove declaration.

Resources