Reputation: 15039
I have the following DIV
containing multiple cards
elements:
Each of those cards
have the following HTML
structure:
<div class="user-w">
<div class="avatar with-status status-green">
<img alt="" src="img/avatar1.jpg">
</div>
<div class="user-info">
<div class="user-date">
12 min
</div>
<div class="user-name">
John Mayers
</div>
<div class="last-message">
What is going on, are we...
</div>
</div>
</div>
Those cards
are loaded dynamically using ajax
. What I need is to attach to each <div class="user-w">
a stopwatch so I can change for example background color when elapsed time is 4 min or make it hidden when elapsed time reaches 6 min.
I was thinking on using SetInterval
multiple times for I think this is not possible.
Each DIV
card element should be totally independant in terms of timing from the others.
Any clue on how to do it correctly?
Upvotes: 1
Views: 415
Reputation: 39270
The accepted answer can give you a lot of trouble if the ajax part
however_you_create_your_element;
attach cardElement to the DOM
Is replacing or adding elements. Ajax and processCards share cardlist and your ajax may remove items from DOM but leave them in cardlist.
You failed to mention if you replace the card list in your ajax or append new cards but the following solution would work either way.
To adjust to updating every minute and showing minutes you can change the following 2 lines:
const repeat = 1000;//repeat every second
const message = timePassed=>`${Math.round(timePassed/1000)} seconds`
to:
const repeat = 60000;//repeat every minute
const message = timePassed=>`${Math.round(timePassed/60000)} min`
(function(){//assuming cardContainer is available
const container = document.querySelector("#cardContainer");
const repeat = 1000;//repeat every second
const message = timePassed=>`${Math.round(timePassed/1000)} seconds`
const updateCards = function(){
Array.from(container.querySelectorAll(".user-w .user-date"))
.map(
(element)=>{
var started = element.getAttribute("x-started");
if(started===null){
started = Date.now()-
parseInt(element.innerText.trim().replace(/[^0-9]/g,""),10)*60000;
element.setAttribute("x-started",started);
}
return [
element,
Date.now()-parseInt(started,10)
];
}
).forEach(
([element,timePassed])=>
element.innerText = message(timePassed)
);
}
setInterval(updateCards,repeat);
}());
<div id="cardContainer">
<div class="user-w">
<div class="avatar with-status status-green">
<img alt="" src="img/avatar1.jpg">
</div>
<div class="user-info">
<div class="user-date">
12 min
</div>
<div class="user-name">
John Mayers
</div>
<div class="last-message">
What is going on, are we...
</div>
</div>
</div>
</div>
Upvotes: 0
Reputation: 1540
you want to add a function with setTimeout()
for ajax success:
parameter.
Ex(with jquery):-
$.ajax({
// your ajax process
success:function(){
setTimeout(function(){
$('.card-w').not('.anotherclassname').addClass('someclassname-'+i);
$('someclassname-'+i).addClass('.anotherclassname').fadeOut();
},6000);
}
})
Upvotes: 0
Reputation: 4830
One way to do this is, after your AJAX call completes and the DOM has been updated, you can use jQuery to select your cards and for each card you can:
milliseconds
- you can write a simple helper function for this or use something like momentjs
based on how complex your requirement issetTimeout
with the parsed value and do any style updates/hiding as neededSample Code:
$('.user-w').each(function(i, el){
var $el = $(el);
var val = $el.find('div.user-date').html();
val = parseTime(val) // Assuming a function to parse time from string to milliseconds is there
setTimeout(function(){
// Do any updates here on $el (this user card)
}, val);
/*setTimeout(function(){
// Do something else when val ms is close to completion
// here on $el (this user card)
}, 0.9 * val);*/
})
If you want multiple things to happen (change bg color and then, later, hide element, for example) you can set multiple setTimeout
s to happen with different time values derived from val
Upvotes: 0
Reputation: 3716
In general, shy away from the "attach everywhere" syndrome. Think in lists, and simple processors. You will thank yourself down the road, as will your users for more efficient code, and your maintenance programmer.
Accordingly, one thought process might be to setup an array of the elements in question, and use a single setInterval
. Something like:
...
var cardList = [];
function processCards ( ) {
var i, cardEl, cardStartTime, now;
now = Date.now();
i = -1;
while ( ++i < cardList.length ) {
cardEl = cardList[ i ][ 0 ];
cardStartTime = cardList[ i ][ 1 ];
if ( cardStartTime + 6 min < now ) {
// do 6 minute thing
}
else if ( cardStartTime + 4 min < now ) {
// ...
}
}
}
$.get('/your/new/cards/call')
.done(function(...){
...
var now = Date.now();
for ( i in returnedCards ) {
cardElement = however_you_create_your_element;
attach cardElement to the DOM
// save reference to element and time created for later processing
cardList.push([cardElement, now]);
}
});
setInterval(processCards, 2*60*1000); // or whatever granularity you want.
One advantage of this approach over multiple setTimeout
calls for each card is the simplicity of having a single processing function, rather than N copies lying around. It's easier to reason about and manage, and reduces the likelihood of errors if an element disappears before it's associated setTimeout
function executes.
Upvotes: 0
Reputation: 6368
When you build the card from the ajax object, set a data element to store the timestamp on the card. Use setInterval to trigger a function that loops through all of the cards and checks their timestamps against the current time and updates the date on the ui, changes the bgcolor, or removes the element altogether.
Upvotes: 1