HTMX - Transition on target element - css

I've been experimenting with HTMX recently and I cant seem to find a way to apply a transition to a target element. I have a form that submits a GET request and returns a table.
<form class="mt-3" hx-get="/data/statement/AJAX" hx-target="#statementAJAX" >
It basically returns a div containing the table like this:
<div id="statementAJAX" class="fade-in">
</div>
the CSS for the div is the following:
.fade-in {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 0.5s;
}
#keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
Now the css transition works when i first load the page but when I execute the AJAX request nothing happens.
I tried apllying style="opacity:0" to the form but obviously it applies only to the form and not the target...
Any idea how to apply the transition to the target element?

What you have there works for me. Are you trying to replace the entire table or add to the table?
This works for me using your CSS and hx-swap="outerHTML" to replace the table.
<a href="#" id="test" hx-get="/load.html" hx-target="#table" hx-trigger="click" hx-swap="outerHTML">
Submit
</a>
<div id="table" class="fade-in"></div>
load.html
<div id="table" class="fade-in">
table content
</div>

Related

Blazor Animation - set div to display: none after animation ends

Recently I have implemented some animations but I am having some problems when the animation ends. I have a div structure for responsiveness, that shows a menu button when the screen size is smaller than X.
When someone clicks on the menu button a left side bar, which is default set to display:none, is being shown by removing the display: none property immediately and then adding an animation class, this all works fine.
However, when the sidebar is collapsed again (by clicking on a close button), a new animation (for removing the menu) is being added, when this animation ends I need to set the display back to display:none (I don't want the sidebar take up any space).
In the current situation I accomplished this by setting some boolean variables that add display:none on false and removes it on true. My animation takes up to 300MS so I added a Task.Delay of 300MS to set the boolean. Sadly this doesn't create a perfect 'flow', you can see the screen hiccup because the setting of the display:none happens just a few MS to late. Of course I can decrease the Task.Delay to 290MS~ but this isn't a great solution.
Any ideas how I can accomplish this using Blazor?
Below the code:
HTML:
<!-- The mobile side bar, display: none default on screen sizes > X -->
<div class="md:hidden" style=#mobileSideBarDisplay>
<div class="fixed inset-0 flex z-40">
<! this sets the opacity of tyhe space to the right (grayed out) -->
<div class="fixed inset-0 #sidebarOverlayAnimation">
<div class="absolute inset-0 bg-gray-600 opacity-75"></div>
</div>
<!-- the actual side bar with it's buttons -->
<div class="relative flex-1 flex flex-col max-w-xs w-full pt-5 pb-4 bg-gray-800 #sidebarMenuAnimation">
<!-- Close button with which the sidebar menu can be closed -->
<button class=".." aria-label="Close sidebar" #onclick="ToggleSidebar"></button>
... Left out for readability
</div>
</div>
</div>
<!-- Static sidebar for desktop -->
<div class="hidden md:flex md:flex-shrink-0">
.. Left out for readability
</div>
<!-- menu button div which becomes visible at screensize < X
<div class="flex flex-col w-0 flex-1 overflow-hidden">
<!-- Menu button with which the sidebar menu can be opened -->
<button class=".. md:hidden" aria-label="Open sidebar" #onclick="ToggleSidebar">
.. Left out for readability
</div>
C# backend code:
#code {
// used to set display: none; (or empty)
private bool showMobileSideBar = false;
// Used to show / toggle animations
private bool showMobileSideBarAnimation = false;
// toggle animation and display classes
private string mobileSideBarDisplay => showMobileSideBar ? "" : "display: none;";
private string sidebarOverlayAnimation => showMobileSideBarAnimation ? "sidebar-overlay-animation-entering" : "sidebar-overlay-animation-leaving";
private string sidebarMenuAnimation => showMobileSideBarAnimation ? "sidebar-menu-animation-entering" : "sidebar-menu-animation-leaving";
// Function to display entering or leaving animation depending on the boolean value)
private async Task ToggleSidebar()
{
showMobileSideBarAnimation = !showMobileSideBarAnimation;
if (showMobileSideBar == true) // only delay when we need to set div to display: none;
{
await Task.Delay(300); // this works kinda clunky now
}
showMobileSideBar = !showMobileSideBar;
}
}
The CSS / animations:
/*
Animations for setting the right-space opacity (when the sidebar is shown / hidden)
*/
.sidebar-overlay-animation-entering {
animation-name: sidebar-overlay-entering;
animation-duration: 300ms;
animation-timing-function: linear;
}
#keyframes sidebar-overlay-entering {
from { opacity: 0; }
to { opacity: 1; }
}
.sidebar-overlay-animation-leaving {
animation-name: sidebar-overlay-leaving;
animation-duration: 300ms;
animation-timing-function: linear;
}
#keyframes sidebar-overlay-leaving {
from { opacity: 1; }
to { opacity: 0; }
}
/*
Animations for displaying the sidebar (in- and out)
*/
.sidebar-menu-animation-entering {
animation-name: sidebar-menu-entering;
animation-duration: 300ms;
animation-timing-function: ease-in-out;
}
#keyframes sidebar-menu-entering {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
.sidebar-menu-animation-leaving {
animation-name: sidebar-menu-leaving;
animation-duration: 300ms;
animation-timing-function: ease-in-out;
}
#keyframes sidebar-menu-leaving {
from { transform: translateX(0); }
to { transform: translateX(-100%); }
}
P.S. I tried using https://github.com/dazinator/BlazorDeferredRemove but I cant get it this to work. There is also not an example using animations (only transition with visibility) or using display: none; (But perhaps the library can work if someone could give a few pointers)

Vue2: v-move not applied to "leave" transition

Goal —
Smoothly animate a changing list of items.
Problem —
When an item enters the list, everything repositions smoothly. When an item leaves the list, everything snaps abruptly.
I've discovered that .drawer-move is applied when new items enter, but .drawer-move is not applied when items leave.
Docs: https://v2.vuejs.org/v2/guide/transitions.html#List-Move-Transitions
Template —
<transition-group class="utilities -animate" tag="section" name="drawer">
<div class="drawer" key="application-drawer">
<div class="heading">Select An Application</div>
</div>
<div class="drawer" v-if="selectCompanyVisible" key="company-drawer">
<div class="heading">Select A Company</div>
</div>
<div class="drawer" key="manage-drawer">
<div class="heading">Manage {{ user.id }}</div>
</div>
</transition-group>
CSS —
.drawer-enter-active,
.drawer-leave-active,
.drawer-move {
transition-property: opacity, transform;
transition-timing-function: cubic-bezier(0.5, 0, 0.5, 1);
transition-duration: .4s;
}
.drawer-enter,
.drawer-leave-to {
opacity: 0;
transform: translateX(3rem);
}
The -leave-active transition class must apply a position: absolute declaration, in order to take it out of the layout flow, so the siblings can move in to place around it.
https://forum.vuejs.org/t/transition-group-move-class-not-occuring-in-the-array/6381/4
This also could mean that you should declare positioning within the transition-group element. No one mentions this in the Vue team, but I don't find this applied automatically by the transition classes.
.drawer-leave-active {
position: absolute;
// optional, depends on your layout
left: 0;
width: 100%;
}
.utilities {
position: relative;
}

Css animation queue

I have a troublesome task. Image should be hidden and button showed by default. I want to show image and hide button, but when one animation ends, secound should start. transition should peroid 1 second. How to make it?
All code:
https://jsfiddle.net/169vuuk8/
HTML code:
<div class="showSingle" itemprop="1">
<img src="https://img.thegearpage.net/board/data/avatars/m/47/47608.jpg?1487188345" alt="logo">
<button class="button">button </button>
</div>
Looks like you just need transition-delay css property for second animation: https://developer.mozilla.org/en/docs/Web/CSS/transition-delay
You can either use transitionend event in js, but it is not really needed here: https://developer.mozilla.org/en/docs/Web/Events/transitionend
Not sure what you need exactly but below the image fades in the first second and the button out after 2 seconds delay.
.showSingle img {
opacity: 0;
animation: fadeInImage 1s ease-out forwards;
}
.showSingle button {
opacity: 1;
animation: fadeOutButton 1s ease-out 2s forwards;}
#keyframes fadeInImage {
to {
opacity: 1
}
}
#keyframes fadeOutButton {
to {
opacity: 0
}
}
<div class="showSingle" itemprop="1">
<img src="https://img.thegearpage.net/board/data/avatars/m/47/47608.jpg?1487188345" alt="logo">
<button class="button">button </button>
</div>

Angular ng-repeat animate once

I am using ngAnimate to animate entries in an ng-repeat. When loading the data all elements are animated as I have defined in my css:
.chat-message.notice.ng-enter {
-webkit-animation: rubberBand 1s;
-moz-animation: rubberBand 1s;
-ms-animation: rubberBand 1s;
animation: rubberBand 1s;
}
This works when a notice is appended with the following html:
<ul>
<li class="media chat-message pointer fade-animate"
ng-repeat-start="message in guestbook.messages track by $index"
ng-if="!message.bot">
<!-- more html -->
</li>
<li class="chat-message notice" ng-repeat-end ng-if="message.bot">
<div>
<p class="text-center">
{{ message.message }}
<small>({{ message.date | amTimeAgo }})</small>
<span class="close pull-right" ng-click="guestbook.remove(message)">×</span>
</p>
</div>
</li>
</ul>
However, when a new message is appended (at the top), every element is again animated. Is there a way that elements animate only once? That when a new message is appended to the array, only that element will animate?
JSFIDDLE
EDIT
After a few clicks on a 'new message', I can see not all notices are animated. Maybe it has something to do with the ng-repeat-start and ng-repeat-end?
If understood correctly just change this:
$scope.messages.unshift(message);
to this:
$scope.messages.push(message);
Even above answer fixed the problem, my solution might be helpful in other scenarios. The fix is pretty straightforward.
Use Angular varible $first and just add CSS class for the first element using ng-class directive in your HTML. In this example, class "first" will be added only to first element in ng-repeat:
ng-class="{'first': $first===true}"
and then apply animation rules to element with "first" CSS class
.chat-message.notice.first.ng-enter {
color:red !important;
font-weight:bold;
animation: rubberBand 1s;
}
Updated JSFIDDLE: http://jsfiddle.net/t6x3a1zj/7/

jquery css problem in chrome

First of all, have a look at my div.
<div data-category="news" class="element news isotope-item loadimg" style="position: absolute; opacity: 1; -moz-transform: scale(1); left: 20px; top: 20px; height: auto; overflow: visible; width: auto; background-color: rgb(0, 0, 0);">
<div id="1" class="load_cont"></div>
<p class="number">1</p>
<div class="element_content">
<div class="thumb">
<img src="assets/website/news2.jpg" id="myImage">
<img style="display: none;" src="assets/ajax-loader.gif" id="prg1">
<div class="date_entry"> 14 may 2011</div>
<div class="title news">TEST 1</div>
</div>
</div>
</div>
When I hover over the div, the img, inside thumb, is supposed to disappear and reveal the div's background.
.element_content .thumb:hover img {
opacity:.0; /*FF/OPERA/Chrome*/
filter: alpha(opacity=0); /*IE 5-7*/
-webkit-transition-duration: 0.1s;
-moz-transition-duration: 0.1s;
transition-duration: 0.1s;
}
Now comes the jquery part, which is basically, if I click on the div, it would load-in content via ajax.The thing is, the ajax preloader and css changes work pretty well in Firefox but doesn't show up at all in IE and Chrome, unless I remove the ajax part.
$('#container').find('.element').click(function(){
if($(this).hasClass('large')){
return ;
}
var url="item_detail.php?";
var code=$(this).children().first().attr("id");
//the portion below this point works well in FF but not in IE or Chrome
$("#"+code).append("<img style='background-color:transparent;' src='assets/ajax-loader.gif'>");
$("#"+code).css({
"position":"absolute",
"top":""+(($("#"+code).parent().height()/2)-27)+"px",
"left":""+(($("#"+code).parent().width()/2)-27)+"px",
"z-index":"2",
});
var e_code = $("#"+code);
var e_cont = $('.element_content',this);
e_cont.css({"opacity":"0.3","filter":"alpha(opacity = 30)","zoom":"1"});
e_cont.find('.thumb img').css({"opacity":"1","filter":"alpha(opacity = 100)","zoom":"1"});
var url="item_detail.php?code="+code;
//If I turn off everything below this point, the preloader appears correctly in chrome and IE, otherwise it seems, the css changes above and the preloader thing don't have any effect in browsers other than firefox.
var httpRequest = new XMLHttpRequest();
httpRequest.open('POST', url, false);
httpRequest.send(); // this blocks as request is synchronous
if (httpRequest.status == 200) {
e_code.css({
"position":"static"
});
e_cont.html('');
e_cont.css({"opacity":"1","filter":"alpha(opacity = 100)","zoom":"1"});
$previousLargeItem.html(oldhtml);
$previousLargeItem.css({'height':'auto','width':'auto'});
var res=httpRequest.responseText;
$('#'+code).html(res);
}
});
The actual problem turned out to be the asynch false thing which froze chrome but for some reason continued to run code in firefox. I solved it by using asynch true and moving the later code in a success event call.
I don't know what You exactly want to do.
But try this code, maybe it can help You out:
http://jsbin.com/iserac/11
The transition works. Just make the interval bigger.
.element_content .thumb img {
opacity:1;
-webkit-transition: opacity 0.5s;
-moz-transition: opacity 0.5s;
transition: opacity 0.5s;
}
.element_content .thumb:hover img {
opacity:0; /*FF/OPERA/Chrome*/
filter: alpha(opacity=0); /*IE 5-7*/
}
Try using jQuery ajax api for ajax calls.

Resources