How can I use these JavaScript math functions ?
For example, I want to compute the square of all <input> values in a form, without submiting the form.
Can you give a little example? Thank you.
JQuery doesn't need to support math functions as it is an addon library for Javascript, you can still use Javascript in your JQuery code, so you can still use all the native math functions.
Examples:
Addition
var x = 1;
var y = 2;
var lol = x+y;
alert(lol);
Subtraction
var x = 10;
var y = 1;
var lol = x-y;
alert(lol);
Edit: Now we understand your question a little better...
<input type="text" id="field1" value="16" />
<input type="text" id="field2" value="25" />
<input type="text" id="field3" value="36" />
var field1Value = document.getElementById("field1").value;
var field2Value = document.getElementById("field2").value;
var field3Value = document.getElementById("field3").value;
alert(Math.sqrt(field1Value ));
alert(Math.PI * field2Value);
alert(Math.sin(field3Value));
You can act on each individual input using an each()(docs) loop.
Click here to test a working example. (jsFiddle)
$('a.square').click(function() {
$('#myform :text').each(function() {
this.value *= this.value;
});
});
$('a.square_root').click(function() {
$('#myform :text').each(function() {
this.value = Math.sqrt(this.value);
});
});
When either link is clicked, it finds all the text inputs in myform and iterates over them.
Inside the each function, this refers to the current input element.
JavaScript is the programming language, not jQuery, which is a library for web application programming written in JavaScript. To effectively use jQuery, you need to know JavaScript.
It is, however, possible to use jQuery's functionality to easily work with multiple textboxes at once:
// Set each single-line textbox's value to the square
// of its numeric value, if its value is in fact a number.
$('input:text').each(function() {
var num = +this.value;
if(!isNaN(num)) {
this.value = num * num; // or Math.pow(num, 2)
}
});
It would be quite useful if jQuery had a reduce() function.
When dealing with lists of data, most functional languages, and indeed most traditional languages these days, have methods that perform a repetitive function over the entire list, taking each element in turn and applying a function to it.
The simplest of these is map, which jQuery implements for you. This takes a list and applies a function to each element and returns the list of results, one result per entry in the list. eg. [1,2,3] -> (map x2) -> [2,4,6].
Sometimes you want a total or collective result from a list, rather than a list of individual mappings. This is where the reduce (or fold) operation comes in. Unfortunately jQuery does not have this method available as standard, so below is a plugin for it. A reduce function takes an accumulator value and the value of the current element, and returns the modified accumulator, which will be passed on to the next call. eg. [1,2,3,4] -> (reduce + [initial:0]) -> 10 = ( ( ( (0 + 1) + 2 ) + 3 ) + 4 ) or ([1,2,3,4] -> (reduce * [initial:1]) -> 24 = ( ( ( (1 * 1) * 2 ) * 3 ) * 4 ).
(function($) {
$.reduce = function(arr, callback, initial) {
var accumulator = initial || 0;
$.each(arr, function(index, value) {
accumulator = callback(accumulator, value, index);
});
return accumulator;
}
})(jQuery);
Then you can use it like this to get a sum of squares:
var answer = $.reduce($('input:text'), function(acc, elem) {
var cVal = $(elem).val();
return acc + cVal * cVal;
}, 0);
i was looking for a solution too , and i saw a lot of questions here that doesn't work (even this one) in case someone wondering like me , here is my working solutiuon :
$("#apport").keyup(
function(){
var apport = parseFloat($("#apport").val());
var montant = parseFloat($("#montant-financer").val());
var moinmontant = parseFloat(montant) - parseFloat(apport);
$("#montant-financer").val(moinmontant);
}
);
All the id's selector are input
Use the jquery map function to create an array
$('input:text').map(function() {
return this.value * this.value; // math calculation goes here
}).get();
See a live example
Looking at the initial question that was posted, it clearly states compute the square of all values in a form, without submiting the form.
i think keyup would be the best solution.
$("input").keyup(function () {
var value = $(this).val();
var x=value*value;
$("p").text(x);
}).keyup();
Click here to check the working example.
http://jsfiddle.net/informativejavascript/Sfdsj/3/
For more details visit http://informativejavascript.blogspot.nl/
Related
Note: I just want to to understand what is $.map doing in following code..
I am working on openstack horizon,In one of the javascript file they are using $.map function Please seehorizon.d3linechar.js
My question is how $.map is works, what is $ before map. $.map is associated with javascript or jquery..
$.map(self.series, function(serie) {
serie.color = last_point_color = self.color(serie.name);
$.map(serie.data, function(statistic) {
// need to parse each date
statistic.x = d3.time.format.utc('%Y-%m-%dT%H:%M:%S').parse(statistic.x);
statistic.x = statistic.x.getTime() / 1000;
last_point = statistic;
last_point.color = serie.color;
});
});
Please read the jQuery documentation. Their are many many examples. Our folk is realy trying to help you. But what is the lack of your understanding in the $.map() function?
$ is only the namespace and makes at least the map function work. So forget about it.
map( input, outputFunction ) is iterating through the input which has to be an real array. The outputFunction, usually a self executing function, is able to manipulate the content of each element of the inputed array.
In your example:
$.map(self.series, function(serie) {
self.series is the input and each element of that array will be called as serie in the anonymous or rather self executed function.
serie.color = last_point_color = self.color(serie.name);
Change some color stuff...
$.map(serie.data, function(statistic) {
Next call of the mapping function.
// need to parse each date
statistic.x = d3.time.format.utc('%Y-%m-%dT%H:%M:%S').parse(statistic.x);
Parsing the date to a specific format like discribed in the comment.
statistic.x = statistic.x.getTime() / 1000;
Take the x value parse to a time or maybe to seconds and divide through 1000.
last_point = statistic;
Save element of serie.data to a temporar variable.
last_point.color = serie.color;
Save the color of the of the serie to the element of that serie.
});
});
All in all...
... $.map() iterates through self.series, then iterates through its children and then it looks like it changes the color of every single element to the color of that series.
$ is an alias for the jQuery object.
As for map(), it is an api function in jQuery used to convert the items in an array.
If you look at the source for map, the basic algorithm is to iterate over the passed in elems and obtain a converted value using the callback
function (elems, callback) {
var value, i = 0,
length = elems.length,
ret = [];
for (; i < length; i++) {
//alternatively, for objects, for (i in elems) {
value = callback(elems[i], i);
if (value != null) {
ret.push(value);
}
}
// Flatten any nested arrays
return concat.apply([], ret);
}
I have a lot of inputs like this where user enters value:
<INPUT TYPE=TEXT NAME="Milk" ONKEYUP="convcase(document.convert.Milk.value)">
<INPUT TYPE=TEXT NAME="Buckwheat" ONKEYUP="convcase(document.convert.Buckwheat.value)">
and a lot of calculation like this:
document.convert.Fe.value = BuckwheatFe * document.convert.Buckwheat.value + PeaFe * document.convert.Pea.value + MilkFe * document.convert.Milk.value + ...
document.convert.Hexadecanoic.value = BuckwheatHexadecanoic * document.convert.Buckwheat.value + PeaHexadecanoic * document.convert.Pea.value + MilkHexadecanoic * document.convert.Milk.value + ...
so the result after calculation shows dynamically and when the program has hundreds of products the delay between input and count is too large. I calculate all products: milk, buckwheat... even if the user does not enter their value.
Could you advise me how to modify the algorithm to reduce the delay?
I would approach it something like the following. The inputs that need to be used in the calculation can be denoted with a class, say "itemValue", and retrieved once then cached. This supposes that they don't change.
The markup can look like:
<form name="convert">
Milk: <input class="itemValue" name="Milk" onkeyup="convcase(this)"><br>
Buckwheat: <input class="itemValue" name="Buckwheat" onkeyup="convcase(this)"><br>
Fe value: <input name="Fe"><br>
Hex value: <input name="Hexadecanoic"><br>
</form>
Things like the Fe and Hexadecanoic values can also be cached. It also helps if the collection of nodes is converted to an array so that built–in array functions can be used. These may be slower than using a for loop, so if they are, convert the reduce call to a loop.
// Helper to convert a NodeList to an array so built-in methods can be used
function toArray(list) {
var i = list.length, arr = [];
while (i--) {
arr[i] = list[i];
}
return arr;
}
The function that does the actual work:
var convcase = (function() {
// Cache stuff in a closure. Note that the names of each factor set
// must match the form control name where the related total is written
var factors = {
Fe: {Buckwheat:0.5, Milk:0.75},
Hexadecanoic: {Buckwheat:0.6, Milk:0.82}
};
var nodes;
return function (el) {
// Only get nodes the first time, assumes they don't change, and convert to Array
// This can be done before validation as it's not dependent on it
nodes = nodes || toArray(el.form.querySelectorAll('input.itemValue'));
// Validate el.value here and deal with invalid values.
// Only proceed if it's a valid value
// For each set of factors, do all the calculations and write totals to form
for (var factor in factors) {
// Get the factor set
var set = factors[factor];
// Write the total to the related form control
el.form[factor].value = nodes.reduce(function(sum, node){
sum += node.value * set[node.name];
return sum;
}, 0);
}
};
}());
I wouldn't do this on keyup, I'd wait for the change or blur events so calculation was only done when there was a good chance the user has finished for the moment, otherwise there may be lots of useless calculations.
Store elements in the array and use looping . Also you can store previous values (old one in some other array ) and before performing calculation compare the old value with the new one . If the value changed then only do it .
I know a standard way to handle this. The point is: you don't want every key stroke to trigger the algorithm. You want to wait for the client to stop typing (for a while); then you trigger the algorithm.
(EDIT: by the way, read the comments below. You might be helped just by changing "onkeyup" by "onchange")
With a clearTimeout/setTimeout combination you can do exactly that. I set the 'typing time' to 400ms, feel free to change this value.
<script>
var timer = null;
var interval = 400; // feel free to change this value
function imputChanged(elm) {
// if any previous key stroke happend less than 400ms ago; clearTimeout will cancel that request.
// only the last request will trigger executeAlgorithm().
clearTimeout(timer);
timer = setTimeout(function() {
executeAlgorithm(elm);
},
interval
);
}
function executeAlgorithm(elm) {
// do what ever you have to do here. As an example, I show the value in a div
document.getElementById('messages').innerHTML = elm.value;
}
</script>
<input onkeyup="imputChanged(this)">
<div id="messages"></div>
(EDIT: it looks like onkeyup works better on IE than onimput; I now set the trigger to onkeyup)
jquery novice here so please resist the urge to punish my ignorance. I am attempting to auto calculate and fill the value of two inputs on change of another. One should be 120% of the original. The other should be 140% of the original. Where am i going wrong here:
jQuery(document).ready(function({
jQuery("#jform_listprice").on("change", function() {
var val = +this.value || 0;
var result_low = +val * 1.20.val();
var result_high = +val * 1.40.val();
jQuery("#jform_newprice").val(result_high.toFixed(2));
jQuery("#jform_usedprice").val(result_low.toFixed(2));
});
});
jQuery(document).ready(function(){
jQuery("#jform_listprice").on("change", function() {
var val = $(this).val();
if(isNaN(val)) return; // Leave now if value is not a number
var result_low = val * 1.20,
result_high = val * 1.40;
jQuery("#jform_newprice").val(result_high.toFixed(2));
jQuery("#jform_usedprice").val(result_low.toFixed(2));
});
});
Actually you don't need to typecast an integer or a float, JS tries to convert it as soon there's an arithmetic operation involved. If it fails to do so, the result will be NaN. Also .val() is a jQuery method, not a JS native one which you can call on a Number object.
Situation
I'm currently writing a javascript widget that displays a random quote into a html element. the quotes are stored in a javascript array as well as how many times they've been displayed into the html element. A quote to be displayed cannot be the same quote as was previously displayed. Furthermore the chance for a quote to be selected is based on it's previous occurences in the html element. ( less occurrences should result in a higher chance compared to the other quotes to be selected for display.
Current solution
I've currently made it work ( with my severely lacking javascript knowledge ) by using a lot of looping through various arrays. while this currently works ( !! ) I find this solution rather expensive for what I want to achieve.
What I'm looking for
Alternative methods of removing an array element from an array, currently looping through the entire array to find the element I want removed and copy all other elements into a new array
Alternative method of calculating and selecting a element from an array based on it's occurence
Anything else you notice I should / could do different while still enforcing the stated business rules under Situation
The Code
var quoteElement = $("div#Quotes > q"),
quotes = [[" AAAAAAAAAAAA ", 1],
[" BBBBBBBBBBBB ", 1],
[" CCCCCCCCCCCC ", 1],
[" DDDDDDDDDDDD ", 1]],
fadeTimer = 600,
displayNewQuote = function () {
var currentQuote = quoteElement.text();
var eligibleQuotes = new Array();
var exclusionFound = false;
for (var i = 0; i < quotes.length; i++) {
var iteratedQuote = quotes[i];
if (exclusionFound === false) {
if (currentQuote == iteratedQuote[0].toString())
exclusionFound = true;
else
eligibleQuotes.push(iteratedQuote);
} else
eligibleQuotes.push(iteratedQuote);
}
eligibleQuotes.sort( function (current, next) {
return current[1] - next[1];
} );
var calculatePoint = eligibleQuotes[0][1];
var occurenceRelation = new Array();
var relationSum = 0;
for (var i = 0; i < eligibleQuotes.length; i++) {
if (i == 0)
occurenceRelation[i] = 1 / ((calculatePoint / calculatePoint) + (calculatePoint / eligibleQuotes[i+1][1]));
else
occurenceRelation[i] = occurenceRelation[0] * (calculatePoint / eligibleQuotes[i][1]);
relationSum = relationSum + (occurenceRelation[i] * 100);
}
var generatedNumber = Math.floor(relationSum * Math.random());
var newQuote;
for (var i = 0; i < occurenceRelation.length; i++) {
if (occurenceRelation[i] <= generatedNumber) {
newQuote = eligibleQuotes[i][0].toString();
i = occurenceRelation.length;
}
}
for (var i = 0; i < quotes.length; i++) {
var iteratedQuote = quotes[i][0].toString();
if (iteratedQuote == newQuote) {
quotes[i][1]++;
i = quotes.length;
}
}
quoteElement.stop(true, true)
.fadeOut(fadeTimer);
setTimeout( function () {
quoteElement.html(newQuote)
.fadeIn(fadeTimer);
}, fadeTimer);
}
if (quotes.length > 1)
setInterval(displayNewQuote, 10000);
Alternatives considered
Always chose the array element with the lowest occurence.
Decided against this as this would / could possibly reveal a too obvious pattern in the animation
combine several for loops to reduce the workload
Decided against this as this would make the code to esoteric, I'd probably wouldn't understand the code anymore next week
jsFiddle reference
http://jsfiddle.net/P5rk3/
Update
Rewrote my function with the techniques mentioned, while I fear that these techniques still loop through the entire array to find it's requirements, at least my code looks cleaner : )
References used after reading the answers here:
http://www.tutorialspoint.com/javascript/array_map.htm
http://www.tutorialspoint.com/javascript/array_filter.htm
http://api.jquery.com/jQuery.each/
I suggest array functions that are mostly supported (and easily added if not):
[].splice(index, howManyToDelete); // you can alternatively add extra parameters to slot into the place of deletion
[].indexOf(elementToSearchFor);
[].filter(function(){});
Other useful functions include forEach and map.
I agree that combining all the work into one giant loop is ugly (and not always possible), and you gain little by doing it, so readability is definitely the winner. Although you shouldn't need too many loops with these array functions.
The answer that you want:
Create an integer array that stores the number of uses of every quote. Also, a global variable Tot with the total number of quotes already used (i.e., the sum of that integer array). Find also Mean, as Tot / number of quotes.
Chose a random number between 0 and Tot - 1.
For each quote, add Mean * 2 - the number of uses(*1). When you get that that value has exceeded the random number generated, select that quote.
In case that quote is the one currently displayed, either select the next or the previous quote or just repeat the process.
The real answer:
Use a random quote, at the very maximum repeat if the quote is duplicated. The data usages are going to be lost when the user reloads/leaves the page. And, no matter how cleverly have you chosen them, most users do not care.
(*1) Check for limits, i.e. that the first or last quota will be eligible with this formula.
Alternative methods of removing an array element from an array
With ES5's Array.filter() method:
Array.prototype.without = function(v) {
return this.filter(function(x) {
return v !== x;
});
};
given an array a, a.without(v) will return a copy of a without the element v in it.
less occurrences should result in a higher chance compared to the other quotes to be selected for display
You shouldn't mess with chance - as my mathematician other-half says, "chance doesn't have a memory".
What you're suggesting is akin to the idea that numbers in the lottery that haven't come up yet must be "overdue" and therefore more likely to appear. It simply isn't true.
You can write functions that explicitly define what you're trying to do with the loop.
Your first loop is a filter.
Your second loop is a map + some side effect.
I don't know about the other loops, they're weird :P
A filter is something like:
function filter(array, condition) {
var i = 0, new_array = [];
for (; i < array.length; i += 1) {
if (condition(array[i], i)) {
new_array.push(array[i]);
}
}
return new_array;
}
var numbers = [1,2,3,4,5,6,7,8,9];
var even_numbers = filter(numbers, function (number, index) {
return number % 2 === 0;
});
alert(even_numbers); // [2,4,6,8]
You can't avoid the loop, but you can add more semantics to the code by making a function that explains what you're doing.
If, for some reason, you are not comfortable with splice or filter methods, there is a nice (outdated, but still working) method by John Resig: http://ejohn.org/blog/javascript-array-remove/
I've got an order form, to which I can append fields by clicking a button. I've got some back end javascript running which totals up the order price, but the grand total script is eluding me.
My problem is that I need the script to seach the entire DOM and find how many have an ID which matches the following pattern.
totprice01
totprice02
totprice03
totprice(n)
I've been playing with this regex, but with not a lot of luck i'm afraid:
matchStr = new RegExp("\\btotprice\\d{2}\\b", "gi");
Once i've got an array of all the HTML IDs I need to pass them into a function which so far looks like this - notice it's all hard coded, not in the least dynamic:
document.getElementById('totpricetot').value = Math.round((parseFloat(document.getElementById('totprice1').value)+parseFloat(document.getElementById('totprice2').value)+parseFloat(document.getElementById('totprice3').value)+parseFloat(document.getElementById('totprice4').value)+parseFloat(document.getElementById('totprice5').value)+parseFloat(document.getElementById('totprice6').value)+parseFloat(document.getElementById('totprice7').value)+parseFloat(document.getElementById('totprice8').value)+parseFloat(document.getElementById('totprice9').value)+parseFloat(document.getElementById('totprice10').value))*100)/100;
Is anyone able to help me put this into expression + function to return the sum of all the values into ?
Thanks a lot!
EDIT
OK I decided to ditch just using plain ol' javascript - JQuery it is! I've put together this code using some of the examples below, but can someone help me debug it I keep get "not defined" errors from the debugger - it appears this function is unavailable to the rest of the DOM?
<input id="totprice08" onChange="totChange()" class="total_field" />
<input id="totprice09" onChange="totChange()" class="total_field" />
<input id="totprice10" onChange="totChange()" class="total_field" />
etc...
<input id="totpricetot" value="0.00" name="totpricetot" />
jQuery(function($) {
function totChange() {
var sum=0;
$('.total_field').each(function() {
sum += $( this ).val () * 1;
} );
$('#totpricetot').val(sum);
}
});
I love it how every javascript question on SO is answered by, "use jQuery"...
Anyways...you can do it with just plain ol' javascript too:
var inputs = document.getElementsByTagName("input");
var priceInputs = [];
for (var i=0, len=inputs.length; i<len; i++) {
if (inputs[i].tagName.indexOf("totprice") > -1) {
priceInputs[priceInputs.length] = parseInt(inputs[i].value);
}
}
calcTotal(priceInputs);
Then just create a function to loop through the array and sum up (:
There are lots of solutions. Besides giving all the elements in question the same class name and use jQuery (or something similar), you could also simply remember the total number of the elements in some JavaScript variable. Would it be possible? I know - it’s kind of an old school solution. You have not indicated that you are using jQuery or any other JavaScript library, so it may be more suitable for you.
Edit: Just to be more explicit:
// your variable, updated every time you add/remove a new field
var fieldsCount;
// whenever you need to do anything with all the fields:
for (var i = 0; i < fieldsCount; i++)
{
var field = document.getElementById("totprice" + i);
// ...
}
Using jQuery, you could select and sum the elements like this:
var sum = 0;
$('[id^=totprice-]').each(function()
{
sum += $(this).val();
});
Give the inputs you need to sum up a class and then get those inputs by that class name (jQuery or some other framework would come in handy here).
if you would use jQuery you could do something like this:
function calculateSum () {
var sum = 0;
$( '.YourClass' ).each ( function () {
sum += $( this ).val () * 1;
} );
return sum;
}
You could give all your total price elements the same CSS class and then get all elements of this class (nice and easy with JQuery).
Give each element a class and use jQuery.