I am trying to implement custom animations on a ng-repeat list. When an element is removed, all the elements that are below it go up.
This is done using a CSS animation on the transform attribute. On the beginning the element is not really removed from the ng-repeat list (there is an animation on the opacity attribute).
At one point, I should actually delete the element from the list. And, at the same time, I need to wind back the animation on the other elements, that have been artificially put too high.
Here is the HTML:
<div ng-repeat="card in cards" ng-style="shouldBeUpped ? uppedStyle : ''">...</div>
And here is the JS:
$timeout(function() {
$scope.shouldBeUpped = false;
$scope.cards.splice(index, 1);
}, 1000);
The problem is that $scope.cards.splice(index, 1); and $scope.shouldBeUpped = false; are not simultaneous. There is a small noticeable delay (maybe 20 or 30 milliseconds), that looks very bad, because in the meantime there is a blank space on the screen ($scope.shouldBeUpped = false; is rendered before $scope.cards.splice(index, 1);).
Do you know what I can do please?
I heard about ng-leave and ng-move classes, but the examples I found on the web don't work for me... (I am using Angular 1.4).
I think you problem is $timeout. You're adding 1s delay there.
I'm not sure how view could know about $scope.shouldBeUpped = false; earlier than $scope.cards.splice(index, 1); as all the changes are reflected when $scope.$apply()
Related
So a little disclaimer: I am completely and utterly self taught. Bear over with me if I'm being a clown.
Anyways, I am currently working on a some platform and in need for a dropdown functionality. That's simple right? Just use HTML5 select tag. However option tags can't be styled :>
So onwards to build my own. The HTML5 select tag uses keyboard input (up/down/enter) for those with disabilities, and I thought I would implement that too. That did present a problem though: The :hover selector collided with my custom attribute, which I use to style keyboard selected items (&[data-selected=true] to be precise).
So onwards to implement my own :hover. And this is where my bewilderment starts.
const handleChildMouseOver = () => {
const items = Array.from(listItem.current?.children!); // The wonders of typescript XD
for (const item of items) {
if (item === event.target) {
item.setAttribute("data-selected", "true");
} else {
item.removeAttribute("data-selected"); // I'm removing the attribute, rather than toggling it, because I got components with 3 states: On, off, and default.
}
}
}
(...)
<ul css={css.list} /*emotion prop*/ data-toggled={toggled} /*parent state*/ onMouseOver={handleChildMouseOver}>
{children} // parent prop
</ul>
So it works as intended, which is fine. But I recall from my pre-react days that you should never manipulate the DOM in loops, as it causes repaints on every iteration. However when I look at the Dev Tools performance profiler, I barely see any "Paints", 8 or so, even when I'm switching hover targets like a madman. What I do see is one million "Composite layer". Oh, and as a bonus React doesn't re-render. Which is fine right? 'Cause I'm not really changing the state of anything, just adding some CSS.
So my question boils down to: Am I being bonkers or smart?
N.B.: I would love to share the actual component, but seeing as this is my first post on stackoverflow, I've got no clue how you do those fancy script tag. Well github is involved somehow, I know that much 🤔
In short, I am trying to trigger a change detection loop between renderer.removeStyle and renderer.addStyle.
The style I am adding is an css animation. When it's removed and added in the same change detection loop Angular won't detect that something changed (for the same animation name).
More Details
Let's say I have a button event (click)="addAnimation('animation1')" that should add existing animation and add the new animation named animation1, animation2 ....
Of course the following code won't work:
addAnimation(animationName: string): void {
this.renderer.removeStyle(this.animate.nativeElement, 'animation');
// setTimeout(() => {
this.renderer.setStyle(this.animate.nativeElement, 'animation', animationName)
// }, 0);
}
since removing and adding a style under angular nose won't trigger any change.
One possible solution is adding a timeout (like the commented code above, but it has side effects that I am not interested in, and also the code is a little wired.
I was hoping to solve it by adding something like this.appRef.tick(); in between to force angular create another change detection loop.
That doesn't work, what am I missing? any suggestions how to do that correctly?
Thanks!
Try following way.
isClick=false;
onClick(){
isClick=true;
}
<div [ngClass]="{'yourCSSClass': isClick}">
I've got a Blazor server app which displays a grid of images. I want to have the images fade when they're displayed. I'm currently using a CSS style/animation:
.gridimage {
animation: fadeIn ease 1s;
}
<img class="gridimage" src="#ImageUrl">
This works fine on initial page load - but when a user changes a filter criteria and the grid of images changes, my #code updates the #ImageUrl and I call StateHasChanged, but the fade doesn't kick in, because the image has already loaded.
I've thought about trying a different approach, where I define a JS method:
function fadeIn(obj) {
obj.style.transition = "opacity 1s";
obj.style.opacity = "1";
}
and then detect DOM changes and trigger that fadeIn() call when the img src attribute changes, but that feels kindof like fighting with the Blazor DOM update model. I've also toyed with using JSInterop when I update ImageUrl but again, it seems messy.
Is there a more elegant way to do it?
Turned out that Brian Parker's answer was correct; adding a unique #key to the item caused the CSS to re-trigger when the page transitions and the image updates - presumably because Blazor sees the <img #key=1234> item as different to <img #key=1235> and so forces it to re-evaluate the CSS.
I'd like to have a component, I called it information-board, to animate away after some seconds. I had the idea to make it slide up as exit-animation.
My approach for this is quite simple, since I can do this with css-animations regarding to this thread: Angular 2 Slide Up and Down Animation
My scss-file is looking quite simple:
.info-board {
transition: height 1s;
overflow: hidden;
}
The problem arises in the sentence from the mentioned thread: The height set to 'auto' can't be animated. This makes sense, I guess, but causing me a heap of trouble, because my information-board should be a shared component and also be allowed to be invisible at the start, only being shown when something interesting happens.
So, looking at my component-html:
<div *ngIf="informationMessage">
<div #contentElement class="info-board" [style.height]="contentHeight">
<alert type="{{alertType}}">
<strong>{{ informationHeading }}</strong> {{ informationMessage.messageText }}
</alert>
</div>
</div>
Nothing too fancy: If the informationMessage, a simple dto, is set, it should be shown. I set the height via binding in order to animate it properly.
Now the complicated part: If the info-board is not shown at the beginning, I basically need to wait for the dto to be set AND the html to be rendered. The only hook I found so far is the "afterViewChecked" one, leading to this Code:
#ViewChild('contentElement') public contentElement: ElementRef;
ngAfterViewChecked(): void {
this.checkSetBoardSize();
}
private checkSetBoardSize() {
if (this.contentElement && this.contentElement.nativeElement) {
this.contentHeight = this.contentElement.nativeElement.scrollHeight + 'px';
}
}
This event is the only one I can be sure, that the ViewChild is set, but it seems to be too late: Since this is the last step of the changetracking-logic, the height I set is ignored.
The only other hook, which looked helpful was "ngAfterContentChecked", but in this one, the ViewChild is not set.
I also didn't find a possibility to 'retrigger' the changetracking nor did the approach on Angular 2 #ViewChild in *ngIf with ViewChildren work for me.
Am I missing some sort of possibility? I know, that working with the nativeElements isn't a good idea, but from my research, this is currently needed working with heights.
You could use the animation feature of Angular, the example for ur case can be found in the angular docs
Sidenote: Be aware that the usage of the animation package (it's outsourced to #angular/animations) is changing in angular version >4.0.0-rc.1. For more the the changelog of angular
When moving over a dragable element I want the cursor to change to a hand and upon mouse down until mouse up I want to change to a "grabbing" hand. What is the proper, cross browser compatible way to do this?
Googling this only brings up websites from year two thousand, with tutorials on IE6. BLA!
Are there any good MODERN tutorials on this topic out there? If not, someone needs to write one. That'd make an excellent smashing magazine article!
Using the jQuery framework, you could do something like this:
// define a hover event so that when you hover over and out of the dragable element
// the cursor changes accordingly
$('#element').hover(function(){
$(this).css('cursor','move');
} , function(){
$(this).css('cursor','default');
});
// this cursor property is only supported in mozilla, but here you can insert
// an image as other posters have specified
// this event changes the cursor when you click the dragable element
$('#element').mousedown(function(){
$(this).css('cursor','-moz-grabbing');
});
// this event changes the cursor back to the default type after you let go
// of the dragable element
$('#element').mouseup(function() {
$(this).css('cursor','default');
});
For a live example, check this out: http://jsfiddle.net/EaEe3/ Let me know if you need more information. I hope this helps.
The propper way is to use cursor rule default values, as 'move' in your case.
If you want a custom cursor you must have a .cur file for IE and a png/gif file for others, so you can write
cursor:url(notie.png),url(ie.cur),move;
Using CSS:
http://www.w3schools.com/css/pr_class_cursor.asp
.myElement {
cursor: move;
}
.myCustomCursor {
cursor: url(myCoolCursor.gif);
}