How can I count form fields with the same id? - javascript

What I want should be very simple I think, but I end up with too complex situations if I search here, or on Google.
<script language="javascript">
// putten tellen
$(document).ready(function () {
$("input[type='number']").keyup(function () {
$.fn.myFunction();
});
$.fn.myFunction = function () {
var minute_value = $("#minute").val();
var second_value = $("#second").val();
if ((minute_value != '')) {
var productiesec_value = (1 / (parseInt(minute_value) * 60 + parseInt(second_value)));
var productiemin_value = productiesec_value * 60;
var productieuur_value = productiesec_value * 3600;
var productiedag_value = productiesec_value * 86400;
var productieweek_value = productiesec_value * 604800;
var productiemaand_value = productiesec_value * 2629700;
var productiejaar_value = productiesec_value * 31556952;
productiesec_value = (productiesec_value).toFixed(5);
productiemin_value = (productiemin_value).toFixed(2);
productieuur_value = (productieuur_value).toFixed(2);
productiedag_value = (productiedag_value).toFixed(0);
productieweek_value = (productieweek_value).toFixed(0);
productiemaand_value = (productiemaand_value).toFixed(0);
productiejaar_value = (productiejaar_value).toFixed(0);
$("#productiesec").val(productiesec_value.toString());
$("#productiemin").val(productiemin_value.toString());
$("#productieuur").val(productieuur_value.toString());
$("#productiedag").val(productiedag_value.toString());
$("#productieweek").val(productieweek_value.toString());
$("#productiemaand").val(productiemaand_value.toString());
$("#productiejaar").val(productiejaar_value.toString());
}
};
});
</script>
The thing I'd like to accomplish is:
Calculate the production time of a gem in multi-types of time (seconds, minutes, hours etc.) - (Done)
Calculate the production of gems by multiple pits.
Preview: http://hielke.net/projecten/productie/edelsteenput.htm
The idea is that you fill in the minutes in the first field and the seconds in the second field. Then the script should count the production in seconds, minutes, hours etc. on the right side.
After that it must be possible to fill in the second row of minutes and seconds and then counts the total production time. The same for the rest of the rows.

Welcome to SO!
A caveat about your setup: whenever possible, avoid having elements share IDs on your page. IDs are generally for elements which only occur once on your page; otherwise use a class. This practice is why document.getElementById() returns a single element, while document.getElementsByClassName() returns an array, which makes the answer to your question as easy as getting that array's .length.
This being said -- counting the number of elements with the same ID in Javascript is generally considered invalid, as getElementById() will only return one element, and (as far as I know) there isn't a way to iterate over instances of the same ID on a page.
Try changing those IDs to class names if you can, the run a document.getElementsByClassName().length on them to get the count.

Related

How to use JavaScript to replace an attribute inside a span tag?

I'm looking to update the data-value attribute's value in the code below with a dynamic integer value I will return in a small JS code I wrote. My code will generate a different integer based on a few factors that vary day to day, but in any case, it returns one single integer value that I want to insert into the data-value attribute.
I have a current solution that works but is "ugly" I think. I basically used DOM manipulation to hide the value the code below produces in the UI, and implemented my own counter from 0 to the dynamic integer value. Is there a more direct and "proper" way of solving the problem, something like innerHTML but maybe for attributes? Thanks!
<div class="content-box-percentage content-box-counter" style="color:#ffffff;font-size:60px;line-height:normal;">
<i class="counter-box-icon fontawesome-icon fa-mug-hot fas" style="font-size:70px;" aria-hidden="true"></i>
<span class="display-counter" data-value="21" data-direction="up" data-decimals="0">0</span>
</div>
Thanks
EDIT: adding the "ugly" code I had, as requested. Originally I had the class ID bsa-counter in the first code snippet. As I was looking to make it prettier (therefore the reason for my post in the first place), I removed the class ID and the JS code as I was planning on starting over.
"use strict";
// CounterBox multiplier - multiplies the number of days by an integer
const bsaMultiplier = 3;
// Customize counter boxes to support counting from a start date to the current date, in number of days
// Run custom counter box function, passing in bsaMultiplier
bsaCounterBoxToToday(bsaMultiplier);
function bsaCounterBoxToToday(bsaMultiplier) {
const bsaStartDateC = "2019/07/14"; // enter in the format of "YYYY/MM/DD", including quotes
const bsaDomElementId = "bsa-counter"; // DOM ID element to select
const bsaDomElementClass = "display-counter"; // DOM Class element to select
const bsaCounterDuration = 500;
// Date range
const bsaStartDate = new Date(bsaStartDateC);
const bsaToday = new Date(
`${new Date().getFullYear()}/${
new Date().getMonth() + 1
}/${new Date().getDate()}`
);
// Days * multiplier
const bsaCountToValue =
Math.ceil(Math.abs(bsaToday - bsaStartDate) / (1000 * 60 * 60 * 24)) *
bsaMultiplier;
let bsaCurrentValue = 0;
let bsaIncrSpeed = setInterval(() => {
bsaCurrentValue < bsaCountToValue
? (document
.getElementById(bsaDomElementId)
.getElementsByClassName(bsaDomElementClass)[0].textContent =
++bsaCurrentValue)
: clearInterval(bsaIncrSpeed);
}, bsaCounterDuration / 100);
}
I think this might be what you're looking for:
var yourInt = 4;
document.getElementsByClassName("display-counter")[0].setAttribute("data-value", parseInt(yourInt));
There are multiple ways of getting the span element's DOM, but this is one way if your span element is first on your html doc. Consider using an id and the "getElementById()" function instead:
document.getElementById("the-id-name-you-added").setAttribute("data-value", parseInt(yourInt));
change your span to be:
<span id="the-id-name-you-added" class="display-counter" data-value="21" data-direction="up" data-decimals="0">0</span>

How to convert millisecond to minutes in AngularJS

In my question I want to display values of 4 entities (I am getting those values from server side in milliseconds) in minutes. I can easily do using a custom filter. But I want to display this using a function, not a custom filter
itemTypes is the global variable where I am storing all parameter of all my items. I am getting all my data from a webservice in this global variable.
Now my code
$scope.itemTypes = itemTypes; // itemTypes is a global variable
$scope.selectedItem = {}; // In this variable I am storing all parameters of one particular item type.
if(selectedItemIndex > -1){
$scope.selectedItem = $scope.itemTypes[selectedItemIndex];
}
Now this $scope.selectedItem have 10 parameters whenever a partular iem type is selected.
4 of those parameters are in milliseconds, I need to display those 4 in minutes
I don't want to use a filter, instead I want to use a function called getTimeInMinute
I want to display only in minutes , not in seconds
This is my function
$scope.getTimeInMinute = function(timeInMilli){
var ms = timeInMilli;
ms = 1000*Math.round(ms/1000); // round to nearest second
var d = new Date(ms);
//console.log(d.getUTCMinutes());
var x = d.getUTCMinutes()
return x;
}
I got this function from this Stackoverflow question (link provided)
Link 1
In my template I want to display like this
<div>{{getTimeInMinute(selectedItem.parameter1)}}</div>
<div>{{getTimeInMinute(selectedItem.parameter2)}}</div>
<div>{{getTimeInMinute(selectedItem.parameter3)}}</div>
<div>{{getTimeInMinute(selectedItem.parameter4)}}</div>
I am unable to display the data in milliseconds using function. I can easily do using a custom filter. But I want to display this using a function, not a custom filter
If you are getting the time in milliseconds and not a timestamp (milliseconds since 01/01/1970), don't make a Date from the milliseconds, instead just divide some more until you get minutes and then (maybe) round the number:
$scope.getTimeInMinute = function(timeInMilli){
let seconds = timeInMilli/1000;
let minutes = seconds/60;
return Math.floor(minutes);
}
Here as an example without angular
function getTimeInMinute(timeInMilli){
let seconds = timeInMilli/1000;
let minutes = seconds/60;
return Math.floor(minutes);
}
console.log(getTimeInMinute(1334000));
Here is an example with the numbers from your comment:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.getTimeInMinute = function(timeInMilli){
let seconds = timeInMilli/1000;
let minutes = seconds/60;
return Math.floor(minutes);
}
$scope.selectedItem = {};
$scope.selectedItem.parameter1 = 600000;
$scope.selectedItem.parameter2 = 240000;
$scope.selectedItem.parameter3 = 480000;
$scope.selectedItem.parameter4 = 360000;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div>{{getTimeInMinute(selectedItem.parameter1)}}</div>
<div>{{getTimeInMinute(selectedItem.parameter2)}}</div>
<div>{{getTimeInMinute(selectedItem.parameter3)}}</div>
<div>{{getTimeInMinute(selectedItem.parameter4)}}</div>
</div>
Use the java script: moment.js libary
var x = 433276000
var tempTime = moment.duration(x);
var y = tempTime.hours() + tempTime.minutes();

How Can I make millisecond Unique?

I'm using NodeJs.
I received constantly request from server.
I'm added some variable like createdTime to it and saved to the database.
when I sorted data by createdTime in some case It is not reliable, It is Repeated
How can I make differentiate between them ?
I do not want to count request.
I do not like to change timestamp's format.
var createdTime = new Date().getTime();
Here's a method of combining a counter with the current time to allow you to have as many as 1000 separate transactions within the same ms that are all uniquely numbered, but still a time-based value.
And, here's a working snippet to illustrate:
// this guarantees a unique time-based id
// as long as you don't have more than 1000
// requests in the same ms
var getTransactionID = (function() {
var lastTime, counter = 0;
return function() {
var now = Date.now();
if (now !== lastTime) {
lastTime = now;
counter = 0;
} else {
++counter;
}
return (now * 1000) + counter;
}
})();
for (var i = 0; i < 100; i++) {
document.write(getTransactionID() + "<br>");
}
If you want something that is likely to work across clusters, you can use process.hrtime() to use the high resolution timer instead of the counter and then make the id be a string that could be parsed into a relative time if needed. Since this requires node.js, I can't make a working snippet here in the browser, but here's the idea:
// this makes a unique time-based id
function getTransactionID () {
var now = Date.now();
var hrtime = process.hrtime();
return now + "." + ((hrtime[0] * 1e9) + hrtime[1]);
}
Due to my low rep I can't add a comment but it looks like you are needing to go beyond milliseconds.Maybe this stackoverflow question can help you
How to get a microtime in Node.js?

Improving speed and data efficiency with javascript calculator.

I'm building a javascript calculator (with jquery mobile) for simplifying routine calculations in microscopy. I'm looking to create more efficient code and would love any input... I don't expect anyone to dig through the whole thing, but here is the link to the program for reference: http://www.iscopecalc.com
(the javascript for the calculator is at http://www.iscopecalc.com/js/calc.js )
The calculator basically consists of about 12 inputs that the user can set. Using the values received from these inputs, the calculator generates values for about 15 different parameters and outputs the results in the display. Currently, whenever the state of an input changes, I bind that change event to a quick function that writes the value for that input to a cookie. But the meat of the program comes with the "updateCalc()" function which reads the values from all of the inputs (from stored cookies) and then recalculates every one of the parameters to be displayed and outputs them. I've coped just that function here for ease of access:
function updateCalc(){
readValues(); //load current calculator state into cookies
var data = $.cookie(); //puts all cookie data into object
var fluorData = fluoroTable[data['fluorophore']]; //fluorophore data taken from table at the end of the file depending on chosen fluorophore
var fluorem = fluorData['fluorem'];
var fluorex = fluorData['fluorex'];
var cameraData = cameraTable[data['camera']]; //camera data taken from table at the end of the file depending on chosen camera
var campix = cameraData['campix'];
var chipWidth = cameraData['chipWidth'];
var chipHeight = cameraData['chipHeight'];
var chipHpix = cameraData['chipHpix'];
var chipVpix = cameraData['chipVpix'];
var RefInd = data['media']; //simple variables taken directly from calculator inputs
var NA = data['NAslider'];
var obj = data['objective'];
var cammag = data['cameraRelay'];
var CSUmag = data['CSUrelay'];
var bin = data['binning'];
var pinholeRad;
var FOVlimit;
var mode;
if (data['modality']=='widefield'){ //FOVlimit, pinholeRad, and CSU mag will all depend on which modality is chosen
FOVlimit = 28;
pinholeRad = NaN;
mode = 'Widefield';
CSUmag = 1;
}
else if (data['modality']=='confocal'){
if (data['CSUmodel']=='X1'){
pinholeRad = 25;
if(data['borealis']=='true'){
mode = "Borealis CSU-X1";
FOVlimit = 9;
}
else {
mode = "Yokogawa CSU-X1";
FOVlimit = 7;
CSUmag = 1;
}
}
else if (data['CSUmodel']=='W1'){
mode = "Yokogawa CSU-W1";
FOVlimit = 16;
pinholeRad = data['W1-disk']/2;
CSUmag = 1;
}
}
//These are main outputs and they depend on the input variables above
var latRes = 0.61 * fluorem / NA;
var axRes = 1.4 * fluorem * RefInd / (NA*NA);
var BPpinhole = 1000 * pinholeRad / (obj * CSUmag);
var AU = BPpinhole / latRes;
var totalMag = obj * cammag * CSUmag;
var BPpixel = 1000 * campix * bin / totalMag;
var samples = latRes / BPpixel;
var pixperpin = BPpinhole * 2 / BPpixel;
var sampLit = 1000 * FOVlimit / (obj * CSUmag);
var coverage = FOVlimit * cammag / chipHeight;
if (coverage < 1) {
chipUsed = coverage;
FOV = sampLit;
}
else {
chipUsed = 1;
FOV = sampLit * chipHeight / (FOVlimit * cammag);
}
var sampWaste = 1 - FOV / sampLit;
var imgpix = 1000 * FOV / (chipVpix / bin);
//function goes on to update display with calculated values...
}
It works ok and I'm generally pleased with the results but here's what I'd like advice on:
Each of the input variables only really affects a handful of the outputs (for instance, a change in input #3 would only really change the calculation for a few of the outputs... not all 15), however, my function recalculates ALL outputs everytime ANY of the inputs are changed, regardless of relevance... I've considered making a giant If-Then function that would selectively update only the outputs that would have changed based on the input that was changed. This would obviously take a larger amount of code, but I'm wondering if (once loaded) the code would be faster when using the calculator, of if it would just be a waste of my time and clutter up my code.
I'm also wondering if storing inputs in cookies and reading values back from cookies is a reasonable way to do things and if I should maybe make a global variable instead that stores the state of the calculator. (the cookies have the added benefit of storing the users calculator state for later visits).
I'm pretty new at this stuff, so any and all comments on how I might improve the efficiency of my code would be greatly appreciated (feel free to just link to a page that I should read, or a method I should be using for instance...)
if you've made it this far, thanks for your time!!

Efficient ways to do a timer which updates every second in JavaScript

I had a task to make a progress bar and a process duration timer along with it. So, not thinking twice I did this:
<div class="mainInfo">
<div id="timer"><span id="elapsedText">0:00</span>/<span id="durationText">3:00</span></div>
<div id="progressBar"><div id="progress" style="width:0;"></div></div>
</div>​
And the JS:
var time = 1000;
var duration = 180;
var $progress = $("#progress");
var $elapsedText = $("#elapsedText");
updateTime();
function updateTime() {
var elapsed = time / 1000;
$elapsedText.text(Math.floor(elapsed / 60) + ":" + Math.floor(elapsed % 60));
$progress.css('width', (elapsed * 100 / duration) + "%");
time = time + 1000;
setTimeout("updateTime()", 1000);
}​
Time is actually retrieved from another variable - this ones for the demo (to illustrate that I actually have the value in miliseconds).
And it worked (not only on my PC), and still does, but the procmon shows a CPU spike on browser (chrome, ff) process when this cycle is running - 30-40% instead of regular 0,5%.
Is there a more efficient way to do this?
There is a standard function for that: SetInterval(function, delay_in_ms).
It calls a function in millisecond intervals.
Instead of
setTimeout("updateTime()", 1000);
use
setTimeout(updateTime, 1000);
The fact that you're invoking the compiler each second could really hurt performance. Passing a string to setTimeout is basically causing an eval within the setTimeout.
There is a default for that, and that is setInterval.
Be careful, the function passed as the first argument to setInterval is always executed in global scope.
Number two, a progress bar is usually created along-side expensive processes. You are using it for display purposes only and forcing a delay, which I don't particularly find useful, but if you like the layout, I guess you can go for it.
The way you would usually use it is:
executeFirstPotentiallyExpensiveProcess();// this is a call to a big function.
// then update the value of the progress bar in percentage style.
executeSecondPotentiallyExpensiveFunction()// this is the second part of your process.
// then again update..
// repeat until you have 100%.
// Basically, you logically divide the expenses of your various executions
// into numerable bits, preferably equal to one another for your convenience,
// but you chunk your loading process or whatever type of process and increment
// the progress after each chunk is complete.
Your use of jQuery disturbs me...
var time = 1000;
var duration = 180;
var $progress = document.getElementById("progress");
var $elapsedText = document.getElementById("elapsedText");
var beginTimestamp = new Date().getTime();
updateTime();
setInterval(updateTime,1000);
function updateTime() {
var now = new Date().getTime();
var elapsed = now-beginTimeStamp + time;
$elapsedText.firstChild.nodeValue = Math.floor(elapsed / 60) + ":" + Math.floor(elapsed % 60);
$progress.style.width = (elapsed * 100 / duration) + "%";
}​
Maybe without jQuery your browser might run better ;)
Try with the function setInterval.

Categories