I want to implement the following feature: when click a button, another div under the same controller move to right a little bit (left+=50). However, when I searched for ngAnimate and find that it is mostly about "start" and "end" state in CSS, not increment manipulation. (I am new to Angular).
I now have to use jquery animate to move.
I get $($element) from the controller
find the div I want to move, say var toMove = $($element).find(".tomove")
toMove.animate({left:"+=50}, 200);
I want to know if there is an elegant way in Angular to achieve this?
Angular doesn't really provide a lot in the way of DOM manipulation, if you can't achieve the desired effect using CSS3 animations then using jQuery is probably your best bet. Any time your doing DOM manipulation it should be encapsulated in a directive but aside from that there's nothing special in Angular for working with the DOM it's just whatever the browser/jQuery provides.
If you don't need to have access to a 'done' callback, and only need to support supporting browsers, then just CSS3 transitions should work. So
.my-el {transition: left 0.5s ...
And then in the directive set the left value dynamically on click. CSS will animate to the value from the current one.
If you want Angular to calculate when the transition finishes, and give you the ability to use a 'done' callback, then the only way I have found is to add a dynamically generated style sheet to the page, that contains a unique class with the target left value, and use $animate.addClass to add it. It feels like a bit of a long-winded faff though, so I can't quite recommend it, and would love a nicer way!
Related
I am using angularjs and ngmap (https://ngmap.github.io).
The map is initially hidden from view (using ng-show), and i want to be able to toggle between views without having to reload the whole map.
I also want to display a kml on the map.
The map is only initialized (using lazy initialization) when that part of the page is shown.
It seems to work fine, except that sometimes the map can't zoom into the kml (using fitBounds). I think I have established that this is because the height of the containing div is zero (due to the controller code firing before the view is actually rendered), and fitBounds needs that.
I am trying to wait until I am sure the map is good and ready. I have tried the following events:
bounds_changed
tilesloaded
but neither do what I want.
Currently I am using a $timeout, but I don't like it, as I don't know how long it takes to initialize the map, and whether or not my code will fire between that time.
My next idea is to repeatedly check for the height of the map, but I would prefer something more explicit.
Another idea is to always have the map in the background, and use absolute positioning to cover it with the other information when that part is visible, but that breaks my current design.
I've decided to avoid the issue.
The map is always going to be there, but I use some ng-class s to make it "visibility: hidden" and hide an unneeded scroll bar when the map tab is unselected.
As long as the visibility is hidden (instead of display: none) the initialization and positioning of the map goes okay.
It isn't perfect (I might need to scroll the other tabs one day), but it works for me for now.
I'm using Angular Material 1.0.1 library, but I don't want DOM elements' removal to be delayed when using ng-repeat. When the dataset changes, elements stick around for a little bit more and it looks like the page is lagging.
I found out that disabling all animations with $animate.enabled(false) fixes that problem, but still I want some animations, such as for $mdToast to be shown.
How to disable animations only for changes in dataset for ng-repeat?
After doing some research, I think I found my answer.
AngularJS's animations are built to work with CSS transition rules, so I just made the objects disappear with CSS as soon as they were being "animated out".
.repeated .ng-leave {
display: none;
}
This approach works, but still attaches unnecessary animation classes to new objects, which might affect performance. Any suggestions on how to fix this are welcome.
As you already found out, you can use $animate. There is a function that takes the element as argument, so you don't have to disable it globally: $animate.enabled([element], [enabled]);
It should be pretty easy to write a directive which disables the animations on the directive's element.
Alternatively you can probably configure the $animateProvider with $animateProvider.classNameFilter([expression]); to exclude elements with a certain CSS class, the parameter is a RegExp - so something like /^(?:(?!repeated).)*$/ may work (not tested).
If you are after performance then the second approach is probably what you are after. From the docs:
Sets and/or returns the CSS class regular expression that is checked when performing an animation. Upon bootstrap the classNameFilter value is not set at all and will therefore enable $animate to attempt to perform an animation on any element that is triggered. When setting the classNameFilter value, animations will only be performed on elements that successfully match the filter expression. This in turn can boost performance for low-powered devices as well as applications containing a lot of structural operations.
I've been reading up on animation with AngularJS and from my understanding, the ngAnimate module can be used out of the box with standard Angular directives. I also understand that css animation is encouraged as the first port of call.
In order to learn Angular, I created a dummy project and I wanted to have a panel fade in when a button is clicked and then have it fade out when clicked again. Since I come from a jquery background, my typical approach would be to use something along the lines of:
$('button').on('click', function() {
// If box is visible
$('.box').stop().fadeOut();
// If box is hidden
$('.box').stop().fadeIn();
});
However with Angular I'm not quite sure what the best way of accomplishing the same thing is. I've had a look at some tutorial vids and this demo is the approach I've come up with. The problem I'm having however is that if I rapidly click on the button it seems to glitch and the animations get screwed up. I suppose the questions I'm asking are a) Is my approach to fading in/out an element a wise one (since I really want to adopt an Angular mindset) and b) How do I replicate jquery's .stop() ie. how do I stop an animation to start another one instead?
I'm struggling a little in understanding how to do animations with Angular since it was so simple with jquery :-)
Thanks
I am using a directive "slideable" which creates a slideout area and has a toggle. This code that was not written by me but it demonstrates a larger issue for me. When I changing views (most commonly /user/:id type), slideable is a directive used on the template. The directive searches for an element during its link function and binds a click event. The issue is that when I am changing routes and the new view ( same type but different id ) is being loaded the directive is re-binding to the old view. If I stop the browser in chrome during the link then I will see two ng-views on the dom and the issue is it binds to the one that is leaving.
I also have other issues that appear to be related to this phenomenon. Is it normal that the old view would still be on the dom while the new view is being formulated?? Why wouldnt the old-view be destroyed before the new one is rendered? How do I get around this issue in a directive like this?
Thanks.
I am looking to understand conceptually what is happening. I already modified the directive to select the latest view and to appropriately search and bind to the correct element. But I am a bit perplexed as to why there would be a state where both co-exist on the dom.
One definitive reason why the old HTML fragment is briefly present along with the new one is to support animation of transitions from the old to the new. Take a look at the ngView documentation and you'll see an example of an animated transition, and it'll be clear that this is not a bug or a design flaw.
Usually when someone has problems with binding to the right element or element's event, it's because they are selecting the element without limiting the scope of the selector to the HTML fragment being added or updated, or trying to target parts of the DOM outside of the directive. So that's the first place to check, that the directive is doing things right, but like I said we'll need code to check on that.
Getting into ngAnimations; I was wondering how page transition could completely be controlled.
I mean by this : being able to control the same way an ng-leave as it is done for the ng-enter while having a change in the url in the process. New to angular but I'd described it as trying to get some ng-leave control before an ng-view change.
As far as I've searched, the ng-leave state only has a meaning with ng-switch (there is another ng but you got the idea); which for the moment means for me that all the elements have to be already in the page and that no url change are involved in the process.
If any help, highly appreciated. I've found the ng-animations really cool but thinking that this point is quite missing.
Assuming there might be another pattern to follow probably though.
Have you read:
Animation in AngularJS
http://www.yearofmoo.com/2013/04/animation-in-angularjs.html
Enhanced Animation in AngularJS
http://www.yearofmoo.com/2013/05/enhanced-animations-in-angularjs.html
Remastered Animation in AngularJS 1.2
http://www.yearofmoo.com/2013/08/remastered-animation-in-angularjs-1-2.html
I have found these useful.