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.
Related
In my application, I have two components communicating with each other with BehaviorSubject since they are siblings. I have a form and a card, card can be either "question" or " answer" and its color changes accordingly.
To change it I use CSS variables. But I also want a "tilting" animation whenever the color changes.
I can't use angular animation because the animation is not data-binded related and in my application, the card component is nested inside various components that are animated with "angular animation" and it's not working anyway.
What I try to do is to bind a class with animation to my card main div but it only triggers when the component loads. What is the correct way to make my card tilt whenever its color changes?
Here is a stackblitz that describes my issue.
It can be done easily with Angular animations. Here is your example updated: https://stackblitz.com/edit/angular-ivy-aw3zs3?file=src/app/card/card.component.ts
You just need to provied a state function to handle the transtion trigger.
transition((fromState: string, toState: string) => toState != fromState, [
// animations
])
And you need to link the animation with the target variable
<div class="card" [style]="style" [#cardChange]="card.card">
</div>
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
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()
while exploring the pure awesomeness of Polymer and Dart I struggle to get some things animated right after they get inserted to the DOM by Data Binding.
Example:
<template repeat="{{item in items}}">
<my-item item="{{item}}"></my-item>
</template>
Everytime a new item is inserted or an old one is removed I would like to animate these changes.
Currently I am doing something like this, which works but isn't really nice:
<style>
[item] { transition: 300ms ease-in-out; transform: translateX(0); ]
[require-start-animation] { transform: translateX(-100%); }
</style>
<template repeat="{{item in items}}">
<my-item item="{{item}}" require-start-animation></my-item>
</template>
and before removing it, I add 'require-end-animation' to the elements which will be removed.
The solution works but isn't really that great since I have to keep track of a lot of stuff such as adding the correct attributes at the correct time and removing it. React to transition ending and so on.
Thus I am asking you, is there a cleaner way to react on changes to the DOM which are caused by Data Binding?
You could create a mixin which overrides attached and detached and does the attribute setting/removal before forwarding the call to super (the element itself) and then apply this mixin on elements you want to animate.
I haven't used mixins a lot myself yet. If mixins don't work well for this you could create an implementation in a normal class and then forward the calls to attached and detached to this implementation.
It could also work to create a wrapper element that just wraps the element you want to animate and implements the animation on attach/detach.
I am building a Modal window/overlay with CSS and Javascript for an email subscription form.
My plan is to Show the Modal when a visitor comes to a website and does not have a cookie set. I then set that cookie when they submit the form or click the close button I have on the Modal window. So on repeat visits if the cookie is there they will not have to see it.
The Modal windows has a background image that is around 75kb so I am trying to come up with the best solution to avoid users loading this image if there cookie is set (I realize it will likely be cached by tis stage)
So my question, in a CSS file for a class/id that has a Background image set, if that class/id has a property set to be hidden display: none; will it still download the image?
To directly answer your question, yes it will, at least for Chrome (might vary between browsers).
I tested using jsfiddle and looking at the network tab
http://jsfiddle.net/ytdun/4/
HTML:
<div id="test"><img src="http://images.google.com/images/nav_logo107.png"></img></div>
CSS:
#test { display:none }
to be sure that the image is downloaded.
what about if use
visibility:hidden;
and temporarily resize the element to 0x0.....
and when the element is now needed...
set again the visibility to
visibility:visible;
and then resize it to its true size...
using the visibility property...
it's like hiding on a invisibility cloak...
but's you're still there and not vanished...
or preload it using javascript
if (document.images){
preload_image_object = new Image();
image_url = new Array();
image_url[2] = "image.jpg";
image_url[3] = "imag2.jpg";
var i = 0;for(i=0; i<=3; i++)
preload_image_object.src = image_url[i];
}