I\'ve developed a couple of alert boxes that display on all site pages.
The user is able to close each box separately:
Updated the script with a 24 hour check
How and where you store the time stamp has more to do with which control you want to have on it.
Since there is a user involved, I would go the server side way, and create i.e. an extra field in the users database table, where these states is kept.
This way, in opposite of the user being able to clear cookies/storage, you control which alerts that should stay hidden and for how long.
A second advantage would be that this can be, on top of time, rolled based, where certain action can be taken based on the users and their credentials.
Either way I would construct the show/hide like this, where you store a class, or an attribute, in i.e. the html tag, which control whether a box will be visual or not.
The advantage this has, is you get rid of the "first show then hide" issue and it will work either you add it server side or using script.
Here is a simple sample using script, plain javascript, and it is by no means optimized, it simply for the logic I wanted to show.
Since this will actually not run as a Stack snippet due to some security issue, here is a fiddle that does: https://jsfiddle.net/essjuj4y/10/
By clicking the For this demo - to clear local storage
button, the storage will be cleared and when page will be run again, the boxes will appear.
/* add an event handler to be able to close a box */
var alerts = document.querySelectorAll('.alert-box-close');
for (var i = 0; i < alerts.length; i++) {
alerts[i].addEventListener('click', function(e) {
var boxtype = e.target.parentElement.id.split('-').pop();
document.getElementById('alert-box-' + boxtype).style.display = "none";
localStorage.setItem("al-" + boxtype, new Date());
})
}
/* add an event handler to be able to clear storage - for demo purpose */
document.querySelector('button').addEventListener('click', function(e) {
localStorage.clear();
})
.alert-box {
display: none;
width: 50vw;
position: relative;
margin: 20px auto;
border: 1px solid black;
}
.alert-box-close {
position: absolute;
top: -12px;
right: -12px;
cursor: pointer;
}
.al-news #alert-box-news,
.al-maintenance #alert-box-maintenance {
display: block;
}
<html>
<head>
<script type='text/javascript'>
function has24HourPassed(key) {
var storeval = localStorage.getItem(key);
if (!storeval) return true; /* nothing stored in storage */
var T24_HOUR = 24 * 60 * 60 * 1000;
if ((new Date - new Date(storeval)) < T24_HOUR) return false;
localStorage.removeItem(key); /* 24 hours passed so we can remove stored date */
return true;
}
(function(d) {
if (has24HourPassed('al-news')) {
d.classList.add('al-news');
}
if (has24HourPassed('al-maintenance')) {
d.classList.add('al-maintenance');
}
})(document.documentElement);
</script>
</head>
<body>
<article class="alert-box" id="alert-box-news">
<h1>News Alerts</h1>
<p>text text text text text text text text text text text text text text</p>
<a class="alert-box-close" id="close-alert-box-news">
<img src="http://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
</a>
</article>
<article class="alert-box" id="alert-box-maintenance">
<h1>Site Maintenance</h1>
<p>text text text text text text text text text text text text text text</p>
<a class="alert-box-close" id="close-alert-box-maintenance">
<img src="http://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
</a>
</article>
<button>For this demo - to clear local storage</button>
</body>
</html>
As far as I understand your question, hiding the alerts for 24 hours (and then subsequently showing them all again after a day) will be a bad user experience.
I assume you're loading these alerts from some sort of database. If so, the proper answer would be to store a status there. Whether it be a status
column or a deleted_at
timestamp, the implementations are endless.
Either way, I would store alert state in the database and filter your data when pulling accordingly.
Thus in your view you would have (assuming php here):
<?php
<?php if(!empty($newlyFilteredAlerts)): ?>
<article class="alert-box" id="alert-box-news">
<h1>News Alerts</h1>
<?php foreach(newlyFilteredAlerts as $alert): ?>
<p><?= $alert ?></p>
<?php endforeach;?
<a class="alert-box-close" id="close-alert-box-news">
<img src="http://i.imgur.com/czf8yas.png" height="25" width="25" alt="" >
</a>
</article>
<?php endif; ?>
Then you would accordingly want to add some sort of endpoint to alter that database status:
$(document).ready(function() {
$("#close-alert-box-news").click(function() {
$.post({
url: '/alerts',
type: 'DELETE',
success: function () {
$("#alert-box-news").hide(800);
},
});
});
});
NOTE: This answer is meant to point you in the right direction, not write your code
My answer is an extension of @Loading's answer. The issue of a flash of content on page load, even when the user has chosen to dismiss the alert(s), is due to the evaluation for localStorage being done after the DOM is loaded.
Therefore, I would recommend hiding the alerts by default, even though this might be an issue for browsers with no JS enabled. This can, however, be circumvented if you use modernizr.js which will add a class to the HTML element when JS is detected, and you can modify the base styles accordingly, e.g.:
.alert-box {
display: none;
}
.no-js .alert-box {
display: block;
/* Other styles */
}
My solution uses localStorage, and relies on storing options as a stringified object: the two keys stored per box is hidden
(to store the status of the box) and timestamp
(to store the time when the box is dismissed). These can be used to evaluate if (1) the user has chosen to dismiss the alert and (2) the action was performed within 24 hours.
Some modifications I have made to your code:
The working code is shown as follows, but localStorage does not work on here due to security restrictions: for a functional demo, refer to the updated JSfiddle instead.
$(function() {
// Check for localStorage
if (typeof window.localStorage !== typeof undefined) {
// Loop through all alert boxes
$('.alert-box').each(function() {
var $t = $(this),
key = $t.attr('id');
// If key exists and it has not expired
if (window.localStorage.getItem(key)) {
var json = JSON.parse(window.localStorage.getItem(key));
if (json.hide && json.timestamp < Date.now() + 1000 * 60 * 60 * 24) {
$t.hide();
} else {
$t.show();
}
} else {
$t.show();
}
});
}
// Bind click events to alert boxes
$('.alert-box a.alert-box-close').click(function() {
var $alertBox = $(this).closest('.alert-box');
// Hide box
$alertBox.hide(800);
// Store option in localStorage, using the box's ID as key
if (typeof window.localStorage !== typeof undefined) {
window.localStorage.setItem($alertBox.attr('id'), JSON.stringify({
hide: true,
timestamp: Date.now()
}));
}
});
// For demo purposes only, clear localStorage to ease testing
$('#clear-localstorage').click(function() {
window.localStorage.clear();
});
});
.alert-box {
display: none;
width: 50vw;
position: relative;
margin: 20px auto;
border: 1px solid black;
}
.alert-box-close {
position: absolute;
top: -12px;
right: -12px;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<article class="alert-box" id="alert-box-news">
<h1>News Alerts</h1>
<p>text text text text text text text text text text text text text text</p>
<a class="alert-box-close" id="close-alert-box-news">
<img src="https://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
</a>
</article>
<article class="alert-box" id="alert-box-maintenance">
<h1>Site Maintenance</h1>
<p>text text text text text text text text text text text text text text</p>
<a class="alert-box-close" id="close-alert-box-maintenance">
<img src="https://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
</a>
</article>
<button id="clear-localstorage">Clear local storage (for testing)</button>
Cookies and local storage serve different purposes. Cookies are primarily for reading server-side, local storage can only be read client-side.
In your case you're wasting bandwidth by sending all the data in each HTTP header. So I recommend you to use HTML local storage instead of cookie.
As per the technical difference and also my understanding:
https://jsfiddle.net/eath6oyy/33/
$(document).ready(function() {
var currentTime = new Date().getTime();
var timeAfter24 = currentTime + 24*60*60*1000;
$("#close-alert-box-news").click(function() {
$("#alert-box-news").hide(800);
//Set desired time till you want to hide that div
localStorage.setItem('desiredTime', timeAfter24);
});
if(localStorage.getItem('desiredTime') >= currentTime)
{
$('#alert-box-news').hide();
}else{
$('#alert-box-news').show();
}
$("#close-alert-box-maintenance").click(function() {
$("#alert-box-maintenance").hide(800);
//Set desired time till you want to hide that div
localStorage.setItem('desiredTime1', timeAfter24);
});
if(localStorage.getItem('desiredTime1') >= currentTime)
{
$('#alert-box-maintenance').hide();
}else{
$('#alert-box-maintenance').show();
}
});
.alert-box {
width: 50vw;
position: relative;
margin: 20px auto;
border: 1px solid black;
}
.alert-box-close {
position: absolute;
top: -12px;
right: -12px;
cursor: pointer;
}
<article class="alert-box" id="alert-box-news">
<h1>News Alerts</h1>
<p>text text text text text text text text text text text text text text</p>
<a class="alert-box-close" id="close-alert-box-news">
<img src="http://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
</a>
</article>
<article class="alert-box" id="alert-box-maintenance">
<h1>Site Maintenance</h1>
<p>text text text text text text text text text text text text text text</p>
<a class="alert-box-close" id="close-alert-box-maintenance">
<img src="http://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
</a>
</article>
You can go with the code you have plus setting a cookie which expires in 24 hours:
Install the MDN JavaScript Cookie Framework
On your js set a tomorrow
variable holding the expiration date for your cookie:
var today = new Date();
var tomorrow = today.setHours(today.getHours() + 24);
Set your cookies as follows:
docCookies.setItem('hide_news', 'true', tomorrow);
Conditionally hide the boxes based on the cookie's value
if (docCookies.getItem('hide_news') == 'true'){
$("#alert-box-news").add_class('hidden');
};
Define the hidden
class on your CSS file
.hidden {
display none;
}
You can see it all in action in this codepen.
You should simply use local storage.
HTML
<article class="alert-box" id="alert-box-news">
<h1>News Alerts</h1>
<p>text text text text text text text text text text text text text text</p>
<a class="alert-box-close" id="close-alert-box-news">
<img src="https://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
</a>
</article>
<article class="alert-box" id="alert-box-maintenance">
<h1>Site Maintenance</h1>
<p>text text text text text text text text text text text text text text</p>
<a class="alert-box-close" id="close-alert-box-maintenance">
<img src="https://i.imgur.com/czf8yas.png" height="25" width="25" alt="">
</a>
</article>
Javascipt
$(document).ready(function() {
var nd = new Date();
var md = nd;
var newsclicked = false;
var maintenanceclicked = false;
setInterval(function() {
newsclicked = (localStorage.getItem("newsclicked")) ? new Date(localStorage.getItem("newsclicked")) : false;
maintenanceclicked = (localStorage.getItem("maintenanceclicked")) ? new Date(localStorage.getItem("maintenanceclicked")) : false;
if (maintenanceclicked === false) {
console.log(maintenanceclicked);
$("#alert-box-maintenance").show(800);
} else {
var mddiff = (md.getTime() - maintenanceclicked.getTime()) / (60 * 60 * 24 * 1000);
if (mddiff >= 1) {
$("#alert-box-maintenance").show(800);
} else {
$("#alert-box-maintenance").hide(800);
}
}
if (newsclicked === false) {
$("#alert-box-news").show(800);
} else {
var nddiff = (nd.getTime() - newsclicked.getTime()) / (60 * 60 * 24 * 1000);
if (nddiff >= 1) {
$("#alert-box-news").show(800);
} else {
$("#alert-box-news").hide(800);
}
}
}, 200);
$("#close-alert-box-news").on("click", function() {
nd = new Date();
localStorage.setItem("newsclicked", nd);
$("#alert-box-news").hide(800);
});
$("#close-alert-box-maintenance").on("click", function() {
md = new Date();
localStorage.setItem("maintenanceclicked", md);
$("#alert-box-maintenance").hide(800);
});
});
CSS
.alert-box {
width: 50vw;
position: relative;
margin: 20px auto;
border: 1px solid black;
}
.alert-box-close {
position: absolute;
top: -12px;
right: -12px;
cursor: pointer;
}
#alert-box-news,#alert-box-maintenance{
display:none; // by default have both elements hidden.
}
Here is an update in your fiddle to test it in action. Refresh the page once you closed a div