I am developing a webpage to collect information about a person's sleep. Specifically, I am required to find the difference in time between two user inputs which may or may not cross midnight.
I am pretty new to programming in general so am trying to go on using just the skills I am familiar with, though would also like to know if there is an easier way!
The code I have written is as follows:
<script type="text/javascript">
function timeSec() {
var btHours = document.getElementById('bedtimeHours').value;
if (btHours == "") {
btHours = 0;
}
var btMins = document.getElementById('bedtimeMins').value;
if (btMins == "") {
btMins = 0;
}
var btSleepTillMidnight = 0;
var btSecTotal = (btHours*3600) + (btMins*60);
document.getElementById('btSec').value = btSecTotal;
if (btHours > 12) {
btSleepTillMidnight = 24*3600 - btSecTotal;
}
if (btHours <= 12) {
btSleepTillMidnight = ( -Math.abs(btSecTotal));
}
var wtHours = document.getElementById('waketimeHours').value;
if (wtHours == "") {
wtHours = 0;
}
var wtMins = document.getElementById('waketimeMins').value;
if (wtMins == "") {
wtMins = 0;
}
var wtSecTotal = (wtHours*3600) + (wtMins*60);
document.getElementById('wtSec').value = wtSecTotal;
var diffSec = wtSecTotal + btSleepTilMidnight;
document.getElementById('diffSec').value = diffSec;
var diffHours = diffSec/3600;
document.getElementById('diffHours').value = diffHours;
}
</script>
My HTML is as follows, and is pretty much designed to pinpoint errors during development:
<form method="post" action="" name="PSQI" id="PSQI">
Bedtime:
<input type="number" name="bedtimeHours" id="bedtimeHours" min="0" step="1" max="24" value=""> Hours
<input type="number" name="bedtimeMins" id="bedtimeMins" min="0" step="10" max="50" value=""> Minutes
<br>
Waketime:
<input type="number" name="waketimeHours" id="waketimeHours" min="0" step="1" max="24" value=""> Hours
<input type="number" name="waketimeMins" id="waketimeMins" min="0" step="10" max="50" value=""> Minutes
<input type="button" value="Score" onclick="timeSec();">
<br>
btSec: <input type="text" name="btSec" id="btSec" value="">
<br>
wtSec: <input type="text" name="wtSec" id="wtSec" value="">
<br>
diffSec: <input type="text" name="diffSec" id="diffSec" value="">
<br>
diffHours: <input type="text" name="diffHours" id="diffHours" value="">
</form>
Not sure if there's a question here or not, so maybe you're in the wrong place.
I don't know why you're using seconds if the resolution is minutes. Your code seems a bit convoluted, consider the following.
If you pass a reference from the button using this, you can get a reference to the form and save using getElementById, e.g.:
<input type="button" value="Score" onclick="timeSec(this);">
Now in the function you can get the form and access the form controls by name, e.g.
function timeSec(el) {
var form = el.form;
var btSecTotal = form.bedtimeHours.value * 3600 + form.bedtimeMins.value * 60;
var wtSecTotal = form.waketimeHours.value * 3600 + form.waketimeMins.value * 60;
form.btSec.value = btSecTotal;
form.wtSec.value = wtSecTotal;
var secTotal = wtSecTotal - btSecTotal;
if (secTotal < 0) secTotal += 24*60*60;
form.diffSec.value = secTotal;
form.diffHours.value = secondsToHM(secTotal);
}
// Convert seconds to hh:mm format
function secondsToHM(secs) {
function z(n){return (n<10?'0':'')+n}
return z(secs/3600 | 0) + ':' + z((secs%3600)/60 | 0);
}
If someone can't sleep more than 24 hours, get the difference between the bed time and wake time by subtracting wake time from bed time and if it's negative, subtract the difference from 24.
Conversely, if the wake time is earlier than the bed time, add 24hrs to the wake time. To allow for sleep time greater than 24 hours, a slightly different algorithm is required but you will also need something else to tell you that they've slept that long (a "next day" checkbox or similar).
Lastly, don't depend on the browser controlling the values based on the input element attributes. User input should be validated and out–of–range or invalid values should be detected and users asked to fix them. The above doesn't do any of that (it's not hard to do).
Here is a neater way to check the "" zero length input. Also, you don't need to repeat var every time.
var btHours = document.getElementById('bedtimeHours').value || 0,
btMins = document.getElementById('bedtimeMins').value || 0,
btSecTotal = (btHours*3600) + (btMins*60);
an inline if-else
var btSleepTillMidnight = (btHours > 12) ? 24*3600 - btSecTotal : ( -Math.abs(btSecTotal));
Related
I want to limit value/numbers inside a text input to match the HH:MM format, possibly also limit max hrs input (i.e. max 8) while also preventing any other input format in that field. Ideally would be if a number is entered to high, instead of resetting the field/number set it back to the previous number that was already contained or selected via the range slider (not simply clearing it).
Would I have to extract the first, second, fourth & fifth number from that text field and check them individually or any other approach I could use?
The only other alternative I can think of is using two separate text input fields and display a static colon symbol between them, checking each individually (but entry field may look neater where only hrs and mins are changeable) i.e.
document.getElementById('hrs').addEventListener('keyup', function(){
this.value = (parseInt(this.value) < 0 || parseInt(this.value) > 8 || isNaN(this.value)) ? "00" : (this.value)
});
document.getElementById('mins').addEventListener('keyup', function(){
this.value = (parseInt(this.value) < 0 || parseInt(this.value) > 8 || isNaN(this.value)) ? "00" : (this.value)
});
//still requires a reset to previous value instead of fixed "00"
//I also tried this with just one field but no idea how to target just the first and last double digits separately while ignoring the colon symbol.
Here is my HH:MM range slider with synced text input field to allow for either input (I haven't found yet any better alternative to this).
HTML
<script
src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"
integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<div class="slidecontainer">
<input type="text" id="durationtimestamp" value="00:00" oninput="durationtimestamp(this.value)" required="required">
<input type="range" min="0" max="480" value="0" class="durationslider" id="durationrange" oninput="durationslider(this.value)">
</div>
JS
function durationslider(value) {
var hours = Math.floor(value / 60).toLocaleString('en-US', {
minimumIntegerDigits: 2,
//useGrouping: false
});
var minutes = (value % 60).toLocaleString('en-US', {
minimumIntegerDigits: 2,
//useGrouping: false
});
duration = hours+':'+minutes;
document.getElementById("durationtimestamp").value = duration;
}
function durationtimestamp(value) {
var hours = Math.floor(value / 60).toLocaleString('en-US', {
minimumIntegerDigits: 2,
//useGrouping: false
});
var minutes = (value % 60).toLocaleString('en-US', {
minimumIntegerDigits: 2,
//useGrouping: false
});
var myduration = moment.duration(value).asMinutes().toString();
var current = document.getElementById("durationrange").value;
document.getElementById("durationrange").value = myduration;
}
Demo: https://jsfiddle.net/markusd1984/u3gfod5x/11/
You can check the input with js like this
const input = document.querySelector("input");
const checkingInput = (event) => {
console.log(event.target.value.length <= 5);
if(!/0[0-8]:[0-5][0-9]$/.test(event.target.value)){
input.value = null;
}
}
<input type="text" onchange="checkingInput(event)"/>
it should work 🤔
You can also use the pattern attribute or a <datalist>.
Although you didn't mention them a <select> or some radio buttons could also be used.
const error = document.getElementById("error");
document.getElementById("frm").addEventListener("change", function(e) {
const valid = this.checkValidity();
error.classList.toggle("hidden", valid);
if (!valid) {
const value = this.getAttribute("value");
this.value = value;
}
});
.hidden {
display: none;
}
.error {
color: red;
}
<span id="error" class="error hidden">Error</span>
<form id="frm">
<label for="time">Time</label>
<input type="text" id="time" pattern="[0]?[0-8]:[0-5][0-9]" placeholder="HH:MM" value="1:00" required>
<br>
<label for="duration">Time</label>
<input list="duration-options" id="duration" pattern="[0]?[0-8]:[0-5][0-9]" placeholder="HH:MM" value="1:00" required>
<datalist id="duration-options">
<option>0:30</option>
<option>1:00</option>
<option>4:00</option>
<option>8:00</option>
</datalist>
<br>
<label for="times">Time</label>
<select id="times">
<option>0:30</option>
<option>1:00</option>
<option>4:00</option>
<option>8:00</option>
</select>
<p>Time</p>
<label><input type="radio" name="time" value="0:30">0:30</label>
<label><input type="radio" name="time" value="1:00">1:00</label>
<label><input type="radio" name="time" value="4:00">4:00</label>
<label><input type="radio" name="time" value="8:00">8:00</label>
</form>
So basically I want the price of "renting a boat" to change when a specific requirement is met. If the user selects a date that is on a weekday it will grab the value from the input field and the price will be 10$ per hour. If its a Saturday the price will be 15$ per hour, and if its a Sunday the price will be 20$ per hour. The user can rent it up to 10 hours and they will get a total price at the bottom.
All I have at the moment is the HTML code for the input fields, and I don't even know how to begin the JavaScript part. So if anyone can teach how to start that would be greatly appreciated!
<div id="main">
<label for="which_date">Which date do you want to rent?</label>
<input type="date" id="which_date_input" min="2022-05-02">
<button id="submit">Submit</button>
<label for="total_hours">How many hours do you want to rent? (Max 10 hours)</label>
<input type="number" id="total_hours_input" placeholder="0" min="1" max="10">
<p id="result"></p>
I'm sorry if the explanation of what I want is hard to understand, I'm a beginner when it comes to JavaScript.
Thanks
You can try something like this...
function getPrice() {
const whichDate = new Date(document.getElementById("which_date_input").value);
const totalHours = document.getElementById("total_hours_input").value;
let perHour = 10;
if (whichDate.getDay() === 6) {
perHour = 15;
}
if (whichDate.getDay() === 0) {
perHour = 20;
}
document.getElementById("result").innerText = "Total price: $" + totalHours * perHour;
}
<div id="main">
<label for="which_date">Which date do you want the ticket for?</label><br>
<input type="date" id="which_date_input" min="2022-05-02"><br>
<label for="total_hours">How many hours do you want to rent? (Max 10 hours)</label><br>
<input type="number" id="total_hours_input" placeholder="0" min="1" max="10">
<button id="submit" onclick="getPrice()">Submit</button><br>
<p id="result"></p>
</div>
This should give somewhat of a good indication of what you're trying to do.
You can use the input event along with target.value to get the value.
I'm getting value by destructuring: const {value} = target it's similar to target.value.
If you don't want to work with real-time results you can use something like submitButton.addEventListener('submit', ... instead where you set the submitButton via querySelector. but you will still need to read the same target.value from the "hours" input element if you decide to go that way.
// Do something with the results
const someAction = (amount) => {
console.log(`The amount is: £${amount}`)
}
// Get the input element
const totalHoursInput = document.querySelector("#total_hours_input")
// Listen to the input event
totalHoursInput.addEventListener("input", ({
target
}) => {
// Get the day name
const day = new Date().toLocaleString('en-us', {
weekday: 'long'
}).toLocaleLowerCase()
const { value } = target // The input value
// Determine the correct rate
let rate = 10 // Weekday default
if (day === "saturday") {
rate = 15
} else if (day === "sunday") {
rate = 20
}
// do something with the rate x value
someAction(rate * value)
})
<label for="which_date">Which date do you want the ticket for?</label>
<input type="date" id="which_date_input" value="" min="2022-05-02">
<button id="submit" onclick="getDate()">Submit</button>
<p id="result"></p>
<script>
function getDate() {
var x = document.getElementById("which_date_input").value;
document.getElementById("result").innerHTML = x;
}
</script>
now use what condition you want to apply on var X. the pick up date will store in x you can use for your conditions.
I am trying to use a set of range sliders to impact each other in various ways. My If the statement is working correctly the first time I change a value, but the second time I change a value, it is adding the entire value instead of the change.
I've tried everything I know so far on how to resolve this, but breaks and continues do not seem to be fixing the problem.
<form>
<Label for="sliderBarOne">Ready</Label>
<input type="range" id="sliderBarOne" min="0" max="100" step="0.01" value="0" onchange="this.form.rangeOne.value=this.value">
<input type="number" id="rangeOne" value="0" onchange="this.form.sliderBarOne.value=this.value">
<br>
<Label for="sliderBarTwo">ACW</Label>
<input type="range" id="sliderBarTwo" min="0" max="100" step="0.01" value="0" onchange="this.form.rangeTwo.value=this.value">
<input type="number" id="rangeTwo" value="0" onchange="this.form.sliderBarTwo.value=this.value">
<br>
<Label for="sliderBarThree">Extra</Label>
<input type="range" id="sliderBarThree" min="0" max="100" step="0.01" value="0" onchange="this.form.rangeThree.value=this.value">
<input type="number" id="rangeThree" value="0" onchange="this.form.sliderBarThree.value=this.value">
<br>Sum: <span id="sum">0</span>
</form>
<script>
document.getElementById("sliderBarOne").addEventListener("change", updateReady);
document.getElementById("sliderBarTwo").addEventListener("change", updateACW);
document.getElementById("sliderBarThree").addEventListener("change", updateExtra);
document.getElementById("rangeOne").addEventListener("change", updateReady);
document.getElementById("rangeTwo").addEventListener("change", updateACW);
document.getElementById("rangeThree").addEventListener("change", updateExtra);
function updateReady() {
var readyBox = document.getElementById('sliderBarOne');
var acwBox = document.getElementById('sliderBarTwo');
var extraBox = document.getElementById('sliderBarThree');
var readyField = document.getElementById('rangeOne');
var acwField = document.getElementById('rangeTwo');
if (readyBox.value < 100 || readyField.value < 100) {
acwBox.value = 100 - parseFloat(readyBox.value);
//Set Slider Values Into Fields
readyField.value = readyBox.value;
acwField.value = acwBox.value;
extraField.value = extraBox.value;
}
updateSum();
}
function updateACW() {
var readyBox = document.getElementById('sliderBarOne');
var acwBox = document.getElementById('sliderBarTwo');
var extraBox = document.getElementById('sliderBarThree');
updateSum();
}
function updateExtra() {
var readyBox = document.getElementById('sliderBarOne');
var acwBox = document.getElementById('sliderBarTwo');
var extraBox = document.getElementById('sliderBarThree');
var readyField = document.getElementById('rangeOne');
var acwField = document.getElementById('rangeTwo');
var extraField = document.getElementById('rangeThree');
if (extraBox.value > 0 || extraField.value > 0) {
readyBox.value = parseFloat(readyBox.value) - parseFloat(extraBox.value);
acwBox.value = parseFloat(acwBox.value) + parseFloat(extraBox.value);
//Set Slider Values Into Fields
readyField.value = readyBox.value;
acwField.value = acwBox.value;
extraField.value = extraBox.value;
}
updateSum();
}
</script>
The first time I enter a value into Ready, it properly subtracts that value from 100 to provide ACW.
Then, when I put a value into Extra, it accurately subtracts that value from Ready and adds to ACW. For instance, Ready 95, ACW 5. Making Extra 1 makes Ready 94 and ACW 6. The problem is, when I change Extra to 2, it makes Ready 92 and ACW 8 instead of Ready 93 and ACW 7.
I'm not sure how to grab the change in the value on each change.
your updatesum() is not defined and your extrafield is not defined in updateready() function
Because the values are changed before. You first change them by 1, and then change them by 2. Hence, it means the extra is 3! Unless you reload the page to reinitialize the values to 95 and 6 and then apply extra 2. It will give you 93 and 7.
To solve the problem you can write an initialize function that initializes the values, and then call the function at the first line of the updateExtra function.
OmG provided the inspiration to create an initial value field. So, I adjusted the code as follows. Thanks OmG!
function updateExtra() {
var readyBox = document.getElementById('sliderBarOne');
var acwBox = document.getElementById('sliderBarTwo');
var extraBox = document.getElementById('sliderBarThree');
var readyField = document.getElementById('rangeOne');
var acwField = document.getElementById('rangeTwo');
var extraField = document.getElementById('rangeThree');
var initialReady = document.getElementById('initialReady');
var initialACW = document.getElementById('initialACW');
if (extraBox.value > 0 || extraField.value > 0) {
readyBox.value = parseFloat(initialReady.value) - parseFloat(extraBox.value);
acwBox.value = parseFloat(initialACW.value) + parseFloat(extraBox.value);
//Set Slider Values Into Fields
readyField.value = readyBox.value;
acwField.value = acwBox.value;
extraField.value = extraBox.value;
}
updateSum();
}
It seems pretty simple but I can't find a good way to do it.
I am doing a research bar which allow users to search something in terms of price mini and price maxi.
So :
I have two text input types (in html of course) "price_mini?" and "price_maxi?".
"Price_mini" cannot be bigger than "price_maxi".
How can I limit the users input of "price_mini" so that if does not allow the user to enter more than the "price_maxi" variable's input and then display an error on save(search) if the mini number is bigger than price_maxi.
Something like this should work, I couldn't get JSFiddle to handle the form to show you a good example and I don't do much in plain javascript now in days so pardon me if there is a small error or two.
HTML
<form name="myForm" onSubmit="submit()" method="post">
<input name="price_mini" type="text">
<input name="price_maxi" type="text">
<input type="submit" value="Submit">
</form>
Javascript
function submit(){
var price_mini = document.forms["myForm"]["price_mini"].value;
var price_maxi = document.forms["myForm"]["price_maxi"].value;
if(Number(price_mini) > Number(price_maxi)){
alert("Minimum price must be less than maximum price!");
}else{
// Your search code here
}
}
Imagine this html
<input id="min" type="text">
<input id="max" type="text">
This should be the correct javascript
var min = document.getElementById("min");
var max = document.getElementById("max");
min.change(function() {
if(Number(this.value) > Number(max.value)) {
this.value = max.value; // replace min with the same max value if it's bigger
}
}
Let's assume that this is your HTML.
<input id="min" type="text">
<input id="max" type="text">
The working JavaScript is this with the behavior if the max field is empty.
var min = document.querySelector('#min');
var max = document.querySelector('#max');
var calculate = function() {
if(max.value == '') return;
if(Number(min.value) > Number(max.value)) {
min.value = max.value;
}
}
min.addEventListener('input', calculate);
max.addEventListener('input', calculate);
You should compare them when they have value (min && max). If you notice that min is higher you can alert to the user or change it automatically to the lowest or to the highest.
$('.calc_input').change( function() {
var min = $('#min').val();
var max = $('#max').val();
if ( (min && max) && min > max ) {
alert('This can not be!');
// $('#min').val() = max;
// $('#max').val() = min;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Min:<input id="min" class="calc_input">
<br>
Max:<input id="max" class="calc_input">
I have 3 input fields, distance, time and average speed. I would like the average speed field to be automatically computed to minimise user effort. As such I have come up with this function but it doesn't work:
$('#Avg Speed').click(function(event) {
var distance = $('#Distance');
var time = $('#Time');
var speed = distance / time;
$(this).append(speed);
});
Any ideas? Even better than clicking the field would be that the result automatically comes up once distance and time is completed. No doubt my code reveals what a novice I am at this stuff.
If your speed is auto generated is good to make it disabled if it's input.
Also may be best event you search for is blur
HTML part:
<label>Distance <input type="text" name="distance" id="distance"></label><br />
<label>Time <input type="text" name="time " id="time"></label><br />
<label>Speed <input type="text" name="speed " id="speed" disabled></label>
Jquery part:
$('#distance,#time').on('blur', function() {
var distance = $('#distance');
var time = $('#time');
var speed = $('#speed');
if(parseInt(time.val()) > 0 && parseInt(distance.val()) > 0)
speed.val(distance.val()/time.val());
})
Also if it will be good a idea to add measures for times, distance and speed
<input type="text" id="Distance">
<input type="text" id="Time">
<input type="text" id="Speed">
$('#Avg Speed').focus(function(event) {
var distance = $('#Distance').val();
var time = $('#Time').val();
var speed = distance / time;
$(this).val(speed);
});
try with an onKeyUp event, i'll give you an example:
HTML:
<input type="number" id="distance"></input>
<input type="number" id="speed"></input>
<input type="number" id="speed" onKeyUp="calcultate()"></input>
<Label id="result"></Label>
JS:
function calculate(){
//get all input values calculate your thing and then put it back //in the result, this will be called each time a user presses a key in the //last input field
$('#result').text(yourResult);
}