I've seen there are quite a few questions about decimal precision and display in Javascript. the thing is that I came to a solution that I thought it was gonna be enough for me'
The key thing is that I'm trying to parse to a string to round and then back to numbers using expressions like this.
return parseFloat(num.toFixed(2));
But there are some cases that it doesn't work as expected. To be honest I'm not sure if it has to do with the way I'm using ko or the javascript code for parsing I put in place. But let's say that in the below fiddle you type 14.385 in the upper text box, both fields will be properly rounded and will display the correct number of decimals, but without deleting the number you add 3333 (that means 14.393333) and the upper one won't be rounded. That's just an example because there are some strange behaviours.
Yo can see the fiddle here http://jsfiddle.net/RTexF/
Thanks
Edit. I add the code as per judgeja indication (I didn't understand the reason to ask for a code when you link fiddle, I see the point now)
The script
var decimalValue = 0.25;
function ViewModel() {
var self = this;
self.submittedValue = ko.observable(decimalValue);
self.percentage = ko.computed({
read: function() {
alert('read');
if (isNaN(parseFloat(self.submittedValue())))
return '';
var num = self.submittedValue() * 100;
return parseFloat(num.toFixed(2));
},
write: function(value) {
alert('write');
value = isNaN(value) ? '' : parseFloat((value / 100).toFixed(4));
self.submittedValue(value);
},
owner: self
});
}
ko.applyBindings(new ViewModel());
And the html
<p><input data-bind="value:percentage"></input></p>
<p><input data-bind="value:submittedValue"></input></p>
EDIT:
Know that it's an old one but I wanted to note that adding this to the write method
self.percentage.notifySubscribers(value);
it fixes the issue (ideally we could check against the current value and just notifiy if it actually changes)
Fiddle : http://jsfiddle.net/RTexF/1/ and http://jsfiddle.net/RTexF/2/
It may help you to think about this if you put an alert("read") in the read: and an alert("write") in the write: and then run your example again.
When you change the top box the first time the bottom box is written to through the write and then the top box is re-computed as the submittedValue observable has changed and you'll see the read for percentage being hit.
Next time you edit the top box the write will be hit again as we're changing the value, which makes sense, but since the submittedValue isn't changed, then the read won't happen again as the observable it depends upon won't have changed.
Related
I have a form using this maskMoney Jquery PLugin
https://github.com/plentz/jquery-maskmoney
and it's giving a wrong value when there's only 1 number behind the decimal symbol
(Ex: If I want to write "300.50" it will show "30.05")
But when I try with 2 number behind decimal symbol, it show the correct value (ex : If I want to write "300.59", it show "300.59")
My code is only this
$('#product_price_1').maskMoney('mask',300.50);
Even with hardcoded value like above, it's still showing the false result ('30.05')
Any body have the same issue like this ?
I had this same problem, and I managed to solve a simple way, I hope it works for you.
let element = document.getElementById('product_price_1');
let value = element.value;
value = parseFloat(valor.replace(',', '.')).toFixed(2).replace('.', ',');
document.getElementById('product_price_1').value = value;
I want to use either a slider question or a draggable bar chart in Qualtrics to present to respondents how they answered in former questions. More specifically, I compute a value out of then answers with weighting, and want the slider or bar to be positioned at this value.
Notably, as each respondent has a value (stored in an embedded data field), the position will thereby be individual for each respondent. Piping only works for text fields, as far as I understood the support page.
Based on this question/answer I came to the following code for the bar graph:
Qualtrics.SurveyEngine.addOnload(function()
{
var result = "${q://Field/result}";
var qwidth = $('QID1936~1~track').offsetWidth;
var resrec = ((qwidth*result)/100);
$('QID1936').select('.bar').each(function(name, index) {
name.setStyle({ width: resrec +"px"});
});
});
Basically, I get the result for each respondent out of the embedded data, get the width of the full bar graph, compute the ratio that should be colored based on the result, and update the position of the bar graph (following the mentioned answer).
Funny enough, everything works when done in the console. Also, the embedded data is correctly loaded, qwidth as well.
Two problems arise: it seems resrec could be computed wrongly, as a console.log() spits out 0 instead of the correct value. I assumed this could be somehow as a variable is not recognized as number, but several tries with Number() or 0+var did not change how this works in Qualtrics. In the console, it works just fine.
Also, no update of the bar (or slider with similar code) happens, neither with the correct value nor with the 0 that is produced by Qualtrics.
I search for two things: either a solution to the Javascript problem as described, basically how I can update the bar or slider with embedded data. Or another solution how to directly get embedded data into one of those two question formats as a starting value for each respondent individually.
Thanks for your help or ideas!
Try this:
Qualtrics.SurveyEngine.addOnload(function()
{
var qid = this.questionId;
var result = parseFloat("${e://Field/result}");
var qwidth = $(qid+'~1~track').offsetWidth;
var resrec = ((qwidth*result)/100);
$(qid).select('.bar').each(function(name, index) {
name.style.width = resrec + "px";
});
});
Notes:
It is best not to use a hardcoded QID
In a pipe use e: to refer to an embedded variable. q: is for questions.
Use parseFloat to convert the string to a number
No need to use setStyle if you are only setting one value
One solution proposed by Qualtrics support: when you use bars and/or sliders, piped values are actually possible.
The trick is to have the value of the bar/slider shown (a thing we do not use in the whole survey elsewhere). Then, you can access over the Advanced Question Options > Add Default Choices the blue arrow for piping text behind the value. Through this, the value is individually set to either embedded data or another answer.
Note, however, to tick "Show value" before accessing the default choices, else you will only be able to drag around the bar and set it for all simultaneously.
Here is a solution using the Qualtrics Question API method setChoiceValue that does not require you to compute the ratio and update the length of the bars manually.
Below is an example code for the result of ten respondents saved in embedded data from previous questions.
Qualtrics.SurveyEngine.addOnload(function()
{
var embedded = ["${e://Field/r1}", "${e://Field/r2}",
"${e://Field/r3}", "${e://Field/r4}", "${e://Field/r5}",
"${e://Field/r6}", "${e://Field/r7}", "${e://Field/r8}",
"${e://Field/r9}", "${e://Field/r10}"];
for (var i = 0; i < 11; i++) {
var index = i + 1;
var choiceInput = embedded[i];
this.setChoiceValue(index, choiceInput);
}
});
For one respondent:
Qualtrics.SurveyEngine.addOnload(function()
{
var value = "${e://Field/r1}";
this.setChoiceValue(1, value);
});
This is probably really simple, but for the life of me I can't work out how to do it. So here goes: I have a large form with lots of text boxes, which are all currency based and so need to be rounded off to 2 decimal places. The values of these textboxes are all generated dynamically by some JavaScript functions I wrote, and I can use .toFixed(2); to round them up/down to 2 decimal places. However, it gets tiring and repetitive to have to put this after working out each value of each textbox. How could I write a simple piece of JavaScript (can be jQuery) to target all the textboxes and round them ALL to 2 decimal places?
Thanks for any help :)
P.S Sorry for the lack of any code, but there isn't really any to show, as its all locked up in big functions. But here's what I'm essentially doing:
function workOutSomeVal() {
// lots of code to work out values and stuff
var finalValue = some mathematical equation to work out value;
var anotherValue = a different value;
$(".some-textbox").val((finalValue).toFixed(2));
$(".another-textbox").val((anotherValue).toFixed(2));
} // my question is, how could I get rid of .toFixed(2) and put in a generic statement somewhere to target all the textboxes?
You can have a function you call that does this:
function roundTextBoxes() {
$("input[type=text]").val(function() {
return (+this.value).toFixed(2);
});
}
...and then call that any time any of them changes. Live Example: http://jsbin.com/toyoc/1
It will probably mean that sometimes, a user looking at the page who does the mental arithmetic will find that it doesn't quite add up...
You can give a common class to all the textboxes which you want to be "roundable", and then select then using that class and apply your rounding logic to each of them.
// let's say all the roundable textboxes have the class "roundable"
$('.roundable').each(function() {
var value = // some mathematical equation to work out value
$(this).val((value).toFixed(2));
});
Another appoach:
Why don't you put value.toFixed(2) at the end of your calculation ?
var finalValue = function(){
// var value = some calculation
return value.toFixed();
}
Or - if you need the full value elsewhere, create a new function:
var finalValueView = function(){
finalValue().toFixed(2);
}
function workOutSomeVal() {
// ...
$(".some-textbox").val(finalValueView);
}
Use Math.round(num * 100) / 100
I have a function to limit the number of characters that a user can type into an input field for my game. It works, except that if it goes down by 1 or more in length, the user can still enter 1 or more characters than they should be able to.
I check the inspector, and it even shows maxlength changing correctly. However, for whatever reason, it still lets the user enter in a length equal to the max number of characters that the variable was equal to during the same session. Is it a bug? Any way to get it working correctly?
my_var = 150000; //this var changes often, can go down to 0 or up to 1000000000
function limitNumberOfCharacters() {
x = my_var.toString().length;
$('.my_input_class').attr('maxlength', x);
}
limitNumberOfCharacters(); //this gets called often
EDIT: http://jsfiddle.net/mDw6f/
EDITTTT:
You are using x as a global variable and is probably getting changed from something else in your code. Use var x = my_var.toString().length; (emphasis on var)
Honestly after seeing this code I was afraid there would be many more underlying problems but all I did was add var before the xyz and it works just as you want it to.
Also fixed the issue of the previous bet amount returning to the input field. It now results to a blank field.
Cheers
Real Fiddle Example
Try using this fiddle:
Working Demo
Use the html input like I did in the code, no need to specify the maxlength attribute to it.
<input type="text" class="my_input_class"/>
and the script
my_var = 25; //this var changes often, can go down to 0 or up to 1000000000
function limitNumberOfCharacters() {
x = my_var.toString().length;
$('.my_input_class').attr('maxlength', x);
}
limitNumberOfCharacters();
Please check:
http://jsfiddle.net/LdWHH/
Obviously it does not make sense to set it to toFixed(1) first and then to toFixed(2). The point is that the .slider("refresh") seems to have its own internal conversion and thus it ignores or overrides the toFixed method. I don't know.
In my german browser it also displays the . correctly as ,
How can I adjust this manually?
$("#plus3").on("mousedown taphold", function () {
var sv4 = $('#slider-vertical4').val();
var sv4fixed = Number(sv4).toFixed(1);
var total = (Number(sv4fixed) + 0.1).toFixed(2);
$('#slider-vertical4').val(total).slider("refresh");
});
I don't really understand what you're trying to achieve.
If your problem is that using +/- : 5.0 will appear as 5.
You can try doing it in two times, set&refresh then set
$('#slider-vertical4').val(total.toFixed(1)).slider("refresh")
$('#slider-vertical4').val(total.toFixed(1));