countdown timer based on window local storage - javascript

I am working on a simple Electron app project. So far I am only at the Javascript and HTML stage.
I am making a countdown timer where the user enters a future date –their birthday for example– and the app then displays a counter with the remaining days, hours, minutes and seconds. You only see the input fields at first, then a simple toggle function removes the input fields and brings up a large clock instead.
So far I have a working prototype with a basic styling. But this prototype will need a new input every time you bring it up. If I can make the window local storage work, then I would get a website (hence Electron app) that will remember your special date even when closed.
My failed attempt at coding below (see headline with 'local storage problem' in capitol letters) has been taken from various youtube tutorials and StackOverflow questions. But I guess I am missing a fairly basic principle in order to make it work.
All suggestions would be greatly appreciated.
Thanks.
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script type="javascript" src="p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script>
// Event listener made to work with Materialize's .hide class
let hideInput = document.getElementById('input-hide');
// console.log(hideInput);
let hideCountdown = document.getElementById('countdown-hide');
// console.log(hideCountdown);
let button = document.querySelector("button");
// console.log(button);
button.addEventListener('click', () => {
if (hideInput.classList.contains("hide")) {
hideInput.classList.remove("hide");
hideCountdown.setAttribute("class", "hide")
} else {
hideInput.setAttribute("class", "hide");
hideCountdown.classList.remove("hide");
}
});
// Find the user's input
const Calender = document.querySelector('.datepicker');
M.Datepicker.init(Calender, {
format: 'yyyy-mm-dd',
firstDay: 1,
// minDate: '15 05 2021', <-- I could't get this to work...
})
// Create a countdown timer and display the user's text
function enterSpecialDate() {
let userDate = new Date(document.getElementById('special-date').value);
// console.log(userDate);
let currentTime = new Date();
/////// LOCAL STORAGE PROBLEM ///////
// window.localStorage.setItem("storedObject", userDate.value);
// console.log(storedObject);
// console.log(dtUserDate);
// let diff = storedObject - currentTime;
let diff = userDate - currentTime;
/* we've been given the difference in milliseconds, so some division is needed */
const d = Math.floor(diff / 1000 / 60 / 60 / 24);
const h = Math.floor(diff / 1000 / 60 / 60) % 24;
const m = Math.floor(diff / 1000 / 60) % 60;
const s = Math.floor(diff / 1000) % 60;
/* send values back into HTML document */
document.getElementById('days').innerHTML = d;
document.getElementById('hours').innerHTML = h;
document.getElementById('minutes').innerHTML = m;
document.getElementById('seconds').innerHTML = s;
// console.log(s < 10 ? ‘0’ + s : s;) <-- I could't get this to work...
/*collect user's special occasion and send back into document*/
var userOccasion = document.getElementById('user-occasion').value;
document.getElementById('userOccasionOutput').innerHTML = userOccasion;
console.log(document.getElementById('user-occasion').value);
}
setInterval(enterSpecialDate, 1000);
<body>
<div class="container">
<!-- welcome message and input area - should show on start then dissappear after you click buttton-->
<div class="" id="input-hide">
<div class="row">
<div class="col s12 m12 distance-1"></div>
<div class="col s12 m3"></div>
<div class="col s12 m6">
<h2>
Countdown to your special occasion!
</h2>
</div>
<div class="col s12 m3"></div>
</div>
<div class="row">
<div class="col s12 m3"></div>
<div class="col s12 m6">
<form action="">
<div class="input-field">
<textarea class="materialize-textarea" name="user-occasion" id="user-occasion"
placeholder="e.g. my birthday"></textarea>
<label for="user-occasion">what is your special occasion?</label>
</div>
</form>
</div>
<div class="col s12 m3"></div>
</div>
<div class="row">
<div class="col s12 m3"></div>
<div class="col s12 m6">
<form action="">
<div class="input-field">
<input type="text" id="special-date" class="datepicker" placeholder="click here">
<label for="date">when is your special occasion?</label>
</div>
</form>
<button onclick="enterSpecialDate()">Enter</button>
</div>
<div class="col s12 m3"></div>
</div>
</div>
<!-- countdown ticker - should appear only after you click the button -->
<div class="hide" id="countdown-hide">
<div class="row">
<div class="col s12 m12 distance-2">
<p></p>
</div>
<div class="col s12 m12">
<div class="time col s12 m3">
<span class="number" id="days"></span>
<br>
<span id="unit">days</span>
</div>
<div class="time col s12 m3">
<span class="number" id="hours"></span>
<br>
<span id="unit">hours</span>
</div>
<div class="time col s12 m3">
<span class="number" id="minutes"></span>
<br>
<span id="unit">minutes</span>
</div>
<div class="time col s12 m3">
<span class="number" id="seconds"></span>
<br>
<span id="unit">seconds</span>
</div>
<!-- <div class="time col s12 m3"></div> -->
</div>
<div class="col s12 m12 distance-3"></div>
<div class="col s12 m12">
<div class="time col s12 m12 until">
<span>until </span><span id="userOccasionOutput"></span></p>
</div>
<div class="col s12 m12">
start again
</div>
</div>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<link href='https://fonts.googleapis.com/css?family=Poppins' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="css/DatePicker1.css">

I don't really see the problem.
I've just made something like this for a 'promo'.
I haven't tested your code, but in order to make it work using localStorage,
I would, and did, something like this:
Retrieve user inputs ONCE, after checking if localStorage hasn't that item.
if (!localStorage.getItem('birthday_key_HASH'))
// Retrieve user's input and then store it.
let userDate = new Date(document.getElementById('special-date').value);
localStorage.setItem('birthday_key_HASH', userDate);
If it's already set, just do your math using the user birthday value.
// ...Do your calculus.
userBirthdayDate = localStorage.getItem('birthday_key_HASH');
Let me know if this is clear enough.

Related

java script code not working in chrome mobile browser but in desktop its working fine

in my WordPress site i created java bootstrap loan calculator its working perfectly on desktop but when i use mobile chrome its not working. i tried with wp-coder plugin and try with manually adding this. in chrome dev tools mobile view its working fine with the real devise this issue occured.is there any way to resolve this issue i much appreciate you help to resolve this issue
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css"
/>
<div class="columns is-12-tablet is-6-desktop is-3-widescreen" style="height: 500px; width:100% " >
<div class="column w-50 p-3 " >
<div class="card w-50 p-3">
<div class="card-content w-50 p-3">
<form id="loan-form">
<div class="level w-50 p-3">
<div class="level-left is-marginless w-50 p-3s">
<div class="level-item">
<p class="number">1</p>
<p> Loan Amount </p>
<p id="yearssliderfuc"> </p>
</div>
</div>
</div>
<input id="amount" type="range" min="20000" max="200000" step="10000" onchange="yrthslide();computeResults()" />
<div class="level">
<div class="level-left is-marginless">
</div>
<div class="level-right">
<div class="level-item">
<div class="field">
<div class="control has-icons-right">
<span class="icon is-small is-right">
</span>
</div>
</div>
</div>
</div>
</div>
<div class="level">
<!-- Left side -->
<div class="level-left is-marginless">
<div class="level-item">
<p class="number">2</p>
<p> Number Of Days </p>
<p id="monthssliderfuc"> </p>
</div>
</div>
</div>
<input id="years" min="30" max="120" step="30" type="range" onchange="monthslide();computeResults()" />
<div class="control">
<br>
</div>
</form>
</div>
</div>
<div >
<div class="notification is-link has-text">
<p id="totalPayment" class="title ">LKR</p>
<p class="subtitle is-4">Total Amount</p>
</div>
</div>
<div >
</div>
</div>
<script >
function computeResults(e) {
// UI
const UIamount = document.getElementById("amount").value;
/* var UIinterest = 50
if(UIamount> 50){
var UIinterest = 50
}*/
if(UIamount<50000){
var UIinterest = 16/100;
}else if(UIamount>50000 && amount<90000){
UIinterest = 18/100;
}else if(UIamount>100000 && amount<140000){
UIinterest = 20/100;
}else{
UIinterest = 22/100
}
const UIyears = document.getElementById("years").value;
var interestperday = (UIamount * UIinterest)/365;
console.log(interestperday);
console.log("interest per day");
const monthly = parseFloat(interestperday);
const monthlyPayment = monthly.toFixed(2);
var interest = interestperday*UIyears;
const interestfinalee = parseFloat(interest);
console.log(interestfinalee);
console.log("interest all time");
var ProFees = (UIamount*10)/100;
const ProFeesfin = parseFloat(ProFees);
console.log(ProFeesfin);
console.log("ProFees");
var DocHFees = (UIamount*5)/100;
const DocHFeesfin = parseFloat(DocHFees);
console.log(DocHFeesfin);
console.log("DocHFees");
var TransFee = (UIamount*5)/100;
const TransFeefin = parseFloat(TransFee);
console.log(TransFeefin);
console.log("TransFee");
const UIamountfin = parseFloat(UIamount);
// Calculating total payment
const all = TransFeefin + DocHFeesfin + ProFeesfin + interestfinalee + UIamountfin
console.log(all);
console.log("allallallallallallallallallallallallallall");
///*****************************************************
const totalPayment = all.toFixed(2);
document.getElementById("totalPayment").innerHTML = "LKR " + totalPayment;
e.preventDefault();
}
function monthslide(){
var Monthslider = document.getElementById("years").value
document.getElementById("monthssliderfuc").innerHTML = Monthslider;
}
function yrthslide(){
var Monthslider = document.getElementById("amount").value
document.getElementById("yearssliderfuc").innerHTML = Monthslider;
}
</script>
You are using the "computeResults()" function, but "computeResults()" function is not defined and the "Calculate()" function is not being used.
Update: Add other details, after the code has been updated:
e.preventDefault() function is not defined and that generates the issue, I removed that and it already works in mobile.
problem resolved.
its because of same function name for mobile view and desktop view after changing the function names its resolved

Fire JS code for every element with the same class

I have a cart page with multiple products that have a new price. I now want to show the customer, using JS, how much he can save. For that I use my very basic knowledge of JS to write the old and new price into a variable, replace stuff I don't want in there like "€" and do my math. Then I create a new div with a certain text and how much the customer can save. What I want to achieve is that he writes that under every product.
As you can see from the snippet he only does that for the first product. I need some kind of loop or anything where he does that code for every product in the cart. So far I searched for 2 hours and couldn't find a hint. Maybe you guys and girls can help me.
var neuerpreis = document.querySelector(".price.price--reduced").childNodes[2].nodeValue.replace(/,/g, '.').replace(/ /g, '');
var alterpreis = document.querySelector(".price.price--reduced .price__old").childNodes[2].nodeValue.replace(/,/g, '.').replace(/ /g, '');
var difference = (alterpreis - neuerpreis).toFixed(2);
var newDiv = document.createElement("div");
var newContent = document.createTextNode(("You save ") + difference + (" €"));
newDiv.appendChild(newContent);
document.querySelector(".cart-item__price").appendChild(newDiv);
<div class="cart-item ">
<div class="cart-item__row">
<div class="cart-item__image">
<div class="cart-item__details">
<div class="cart-item__details-inner">
<div class="cart-item__price">
<div class="price price--reduced">
<span class="price__currency">€</span> 66,95<span class="price__old">
<span class="price__currency">€</span> 79,00</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="cart-item ">
<div class="cart-item__row">
<div class="cart-item__image">
<div class="cart-item__details">
<div class="cart-item__details-inner">
<div class="cart-item__price">
<div class="price price--reduced">
<span class="price__currency">€</span> 100,95<span class="price__old">
<span class="price__currency">€</span> 79,00</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
You can use querySelecetorAll and relative addressing
I select the .cart-item__price as the relevant container
Then I set some content as default
Note I do not convert to the string (toFixed) until I want to present it.
The INTL number formatter could also be used here
[...document.querySelectorAll(".cart-item__price")].forEach(div => {
const neuerpreis = div.querySelector(".price--reduced").childNodes[2].nodeValue.replace(/,/g, '.').replace(/ /g, '');
const alterpreis = div.querySelector(".price__old").childNodes[2].nodeValue.replace(/,/g, '.').replace(/ /g, '');
const difference = alterpreis - neuerpreis;
let newContent = document.createTextNode("No savings on this product")
const newDiv = document.createElement("div");
if (difference > 0) {
newContent = document.createTextNode(("You save ") + difference.toFixed(2) + (" €"));
}
newDiv.appendChild(newContent);
div.appendChild(newDiv);
})
<div class="cart-item ">
<div class="cart-item__row">
<div class="cart-item__image">
<div class="cart-item__details">
<div class="cart-item__details-inner">
<div class="cart-item__price">
<div class="price price--reduced">
<span class="price__currency">€</span> 66,95
<span class="price__old">
<span class="price__currency">€</span> 79,00
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="cart-item ">
<div class="cart-item__row">
<div class="cart-item__image">
<div class="cart-item__details">
<div class="cart-item__details-inner">
<div class="cart-item__price">
<div class="price price--reduced">
<span class="price__currency">€</span> 100,95<span class="price__old">
<span class="price__currency">€</span> 79,00</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
var el = document.querySelectorAll(".test_class");
for (i = 0; i < el.length; i++) {
el[i].innerHTML = "test"+i
}
<div class="test_class">hey</div>
<div class="test_class">hey</div>
<div class="test_class">hey</div>
<div class="test_class">hey</div>
Here you go

get data from html page using javascript

I have some HTML - pretty nasty, but not mine and so I don't have control over it. I need to extract some data from the form, the First name value (ABDIGANI) and the Surname value (AHMED). What is the best way to do this with javascript?
<div class="voffset3"></div>
<div class="container well panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-md-3">
<span class="ax_paragraph">
First name
</span>
<div class="form-group">
<div class="ax_h5">
ABDIGANI
</div>
</div>
</div>
<div class="col-md-3">
<span class="ax_paragraph">
Surname
</span>
<div class="form-group">
<div class="ax_h5">
AHMED
</div>
</div>
</div>
</div>
</div>
</div>
</div>
You could consider HTML in most cases well structured. Try this the following snippet.
Edit: did a change due to the first comment.
Edit: if you have more than one rows, you should use
document.querySelectorAll('.container > .panel-body > .row');
and fetch the pairs for each found element as below.
const markers = ['First name', 'Surname'];
const mRx = [new RegExp(markers[0]), new RegExp(markers[1])];
function findMarker(element) {
for(let i = 0; i < mRx.length; i++) {
if(element.innerHTML.match(mRx[i])) {
return markers[i];
}
}
return null;
}
function findValue(el) {
return el.parentElement.querySelector('.form-group > div').innerHTML.trim();
}
const pairs = [... document.querySelectorAll('.ax_paragraph')]
.map(el => {
return {el: el, mk: findMarker(el)};
})
.filter(n => n.mk !== null)
.map(o => {
return {key: o.mk, value: findValue(o.el)};
});
console.log(pairs);
var x = document.querySelectorAll(".panel-body > div >.col-md-3 > div > div");
x.forEach(myFunction);
function myFunction(item, index) {
//console.log(item.innerHTML.trim());
if (index===0){
console.log("First name : "+item.innerHTML.trim());
}
if (index===1){
console.log("Surname : "+item.innerHTML.trim());
}
}
<div class="voffset3"></div>
<div class="container well panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-md-3">
<span class="ax_paragraph">
First name
</span>
<div class="form-group">
<div class="ax_h5">
ABDIGANI
</div>
</div>
</div>
<div class="col-md-3">
<span class="ax_paragraph">
Surname
</span>
<div class="form-group">
<div class="ax_h5">
AHMED
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Check this
const firstName = document.querySelector('.row .form-group div').textContent.trim();
const surname = document.querySelector('.row > div:last-child .form-group div').textContent.trim();
note: Its better to change html according to functionality needs, like if you need firstname then you must keep an id attribute to div which is having first name, same goes to surname. then select those fields using id selector, because even if you change html page structure in future, functionality will not get effected.
Check below for reference on how the html should actually be(just to make sure you know it, but the solution you are seeking is above in first two lines)
eg:
<div class="voffset3"></div>
<div class="container well panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-md-3">
<span class="ax_paragraph">
First name
</span>
<div class="form-group">
<div class="ax_h5" id="firstNameField">
ABDIGANI
</div>
</div>
</div>
<div class="col-md-3">
<span class="ax_paragraph">
Surname
</span>
<div class="form-group">
<div class="ax_h5" id="surnameField">
AHMED
</div>
</div>
</div>
</div>
</div>
</div>
</div>
document.querySelector('.form-group > div').textContent but without modifying the html there is no way to distinguish first name and surname.
If you can't edit the HTML, you can use the XPATH for Example.

Adding Media Query

I want to make my countdown timer responsive in mobile view I want to make it responsive in mobile device such a way that it should be like a list days ,hours,min,seconds how to do that ?
jsfiddle
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div id="main">
<div class="content">
<div class="text">
</div>
<!-- /.Text Div -->
<div class="counter">
<h3>Registration Closes In :</h3>
<div id="countdown"><span class="days">10 <b>Days</b></span> <span class="hours">7 <b>Hours</b></span> <span class="minutes">26 <b>Minutes</b></span> <span class="seconds">58 <b>Seconds</b></span></div>
<!-- /#Countdown Div -->
</div>
<!-- /.Counter Div -->
</div>
<!-- /.Content Div -->
</div>
<!-- /#Main Div -->
</div>
<!-- /.Columns Div -->
</div>
<!-- /.Row Div -->
According to what I understood, you are asking for, How to calculate the time difference between Today and the FinalDay ?
var today = new Date();
var FinalDay = new Date("7-01-2017 18:00");
var milliSecondsRemaining = (FinalDay - today); // milliseconds between now & FinalDay
var daysRemaining = Math.floor(milliSecondsRemaining / 86400000); // days
var hoursRemaining = Math.floor((milliSecondsRemaining % 86400000) / 3600000); // hours
var minutesRemaining = Math.round(((milliSecondsRemaining % 86400000) % 3600000) / 60000); // minutes
alert("Registration Closes In" + daysRemaining + " Days, " + hoursRemaining + " Hours, " + minutesRemaining + " Minutes");
Hope this solves your problem.

Bootstrap modal not firing following partial ajax load

I'm using Bootstrap with the latest version of jQuery and am having an issue displaying a modal following a partial update of the page via Ajax.
The modal fires ok multiple times before the UpdateRegister function runs after 60 seconds, after that I receive a "0x800a01b6 - JavaScript runtime error: Object doesn't support property or method 'modal'" when I click on the button to open the modal again.
The button that fires the modal ('#cmdAdd') is outside the Div updated by the Ajax call.
The javascript is as below:
$(function() {
// Display Add Visitor modal
$("#cmdAdd").on("click", function () {
var url = "/Visitor/Add/";
$.get(url, function (data) {
$("#myModal").html(data);
$('#myModal').modal('show');
});
});
// Update register every 60 seconds
setInterval(function () {
UpdateRegister();
}, 60000);
});
function UpdateRegister() {
var currentDate = new Date();
var day = currentDate.getDate();
var month = currentDate.getMonth() + 1;
var year = currentDate.getFullYear();
var thisDate = month + "/" + day + "/" + year;
var url = "/Visitor/RegisterList?date=" + thisDate + "&filter=current";
$.get(url, function (data) {
$("#RegisterList").html(data);
});
}
HTML is as follows:
<div class="row">
<div class="col-lg-12">
<h2>#Model.Date.DayOfWeek #Model.Date.ToLongDateString()</h2><br />
<div class="btn-group pull-right">
<button type="button" class="btn btn-danger" id="cmdEmergency">Emergency</button>
<button type="button" class="btn btn-default" id="cmdAdd">Add Visitor</button>
<button type="button" class="btn btn-default" id="cmdAddBulk">Add Bulk Visitors</button>
</div>
<ul class="nav nav-tabs">
<li class="active">Current Register <span class="label label-success" id="CountIn">#Model.VisitorsIn</span></li>
<li>Visitors Expected <span class="label label-success">#Model.VisitorsExpected</span></li>
<li>All Visitors <span class="label label-success" id="CountTotal">#Model.TotalVisitors</span></li>
</ul>
<div class="tab-content">
<!-- Visitors currently in the building -->
<div class="tab-pane active" id="register">
<br /><br />
<div class="row">
<div class="col-lg-12">
<div id="RegisterList">
#Html.Action("RegisterList", new { date = Model.Date, filter="current" })
</div>
</div>
</div>
</div>
<!-- Expected visitors not yet arrived -->
<div class="tab-pane" id="expected">
<br /><br />
<div class="row">
<div class="col-lg-12">
<div id="ExpectedList">
#Html.Action("RegisterList", new { date = Model.Date, filter="expected" })
</div>
</div>
</div>
</div>
<!-- All visitors for the day -->
<div class="tab-pane" id="all">
<br /><br />
<div class="row">
<div class="col-lg-12">
<div id="AllList">
#Html.Action("RegisterList", new { date = Model.Date, filter="all" })
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="myModal">
<!-- Modal content goes here -->
</div><!-- /.modal -->
How can I ensure that the modal still works after the update?
I know it sounds trivial but are you possibly missing a reference to bootstrap.js within the AJAX Html? Adding a reference worked for me when I faced the same error.
I think your #myModal just disappear when #RegisterList is set the data. You should go to check about it.

Categories