I have code that converts pixels into inches. But the result is a decimal.
How can I have the result return a fraction for the inch, example: 1/4 instead of .25
Here is the HTML:
<label>Pixels</label>
<input class="calcd" id="calc3" type="text" />
<input class="calcd" id="calc4" type="hidden" value="96" />
<br />Inches <span id="result2"></span>
Here is the Jquery:
$(document).ready(function(){
$(".calcd").keyup(function(){
var val1 = parseInt($("#calc3").val());
var val2 = parseInt($("#calc4").val());
if ( ! isNaN(val1) && ! isNaN(val2))
{
$("#result2").text((val1 / val2).toFixed(2));
}
});
});
I see this here on stackoverflow:
where using the var decimal = eval(fraction); will work, but am confused on it.
Here is the JsFiddle
2 options you got:
Working demo =>: http://jsfiddle.net/Nn2yq/ -- Convert a decimal number to a fraction / rational number
you can use this: https://github.com/ekg/fraction.js
Also you only need one $(document).ready(function () {
hope this helps. :)
COde
$(document).ready(function () {
$(".calc").keyup(function () {
var val1 = parseInt($("#calc1").val());
var val2 = parseInt($("#calc2").val());
if (!isNaN(val1) && !isNaN(val2)) {
$("#result").text(val1 * val2);
}
});
$(".calcd").keyup(function () {
var val1 = parseInt($("#calc3").val());
var val2 = parseInt($("#calc4").val());
if (!isNaN(val1) && !isNaN(val2)) {
$("#result2").text(fraction((val1 / val2).toFixed(2)));
}
});
});
//convert a decimal into a fraction
function fraction(decimal) {
if (!decimal) {
decimal = this;
}
whole = String(decimal).split('.')[0];
decimal = parseFloat("." + String(decimal).split('.')[1]);
num = "1";
for (z = 0; z < String(decimal).length - 2; z++) {
num += "0";
}
decimal = decimal * num;
num = parseInt(num);
for (z = 2; z < decimal + 1; z++) {
if (decimal % z == 0 && num % z == 0) {
decimal = decimal / z;
num = num / z;
z = 2;
}
}
//if format of fraction is xx/xxx
if (decimal.toString().length == 2 && num.toString().length == 3) {
//reduce by removing trailing 0's
decimal = Math.round(Math.round(decimal) / 10);
num = Math.round(Math.round(num) / 10);
}
//if format of fraction is xx/xx
else if (decimal.toString().length == 2 && num.toString().length == 2) {
decimal = Math.round(decimal / 10);
num = Math.round(num / 10);
}
//get highest common factor to simplify
var t = HCF(decimal, num);
//return the fraction after simplifying it
return ((whole == 0) ? "" : whole + " ") + decimal / t + "/" + num / t;
}
function HCF(u, v) {
var U = u,
V = v
while (true) {
if (!(U %= V)) return V
if (!(V %= U)) return U
}
}
working screenshot
Related
How would I go about changing this code so that the number 7 can be replaced with any number between 7 and 16?
var lvalue = $( ".leave-input" ).val();
if (lvalue <= 7.29) {
lvalue = roundDown();
} else if (lvalue >= 7.3) {
lvalue = roundUp();
}
I am trying to round the time the user input ups the nearest hour. I had trouble using time so am now just using the number they input.
To clarify rather then having an if statement for each number, 7, 8, 9 etc. Is there a way to rewrite the current code so "7" can be any number between 7 and 16?
If you add 0.2 to the value, you can use Math.round():
input.oninput = function() {
let lvalue = +document.getElementById('input').value + 0.2;
document.getElementById('output').innerHTML = Math.round(lvalue);
}
<input id="input" type="text">
<div id="output"></div>
You can make it so that the number is smaller than 1, then it should work for all cases:
let lvalue = $(".leave-input").val();
const baseValue = Math.round((lvalue - Math.floor(lvalue)) * 100) / 100;
if (baseValue<= 0.29) {
lvalue = roundDown();
} else if (baseValue>= 0.3) {
lvalue = roundUp();
}
Here is a working example:
function calculate() {
let lvalue = Number(document.getElementById('input').value)
const baseValue = Math.round((lvalue - Math.floor(lvalue)) * 100) / 100;
if (baseValue <= 0.29) {
lvalue = Math.floor(lvalue);
} else if (baseValue >= 0.3) {
lvalue = Math.ceil(lvalue);
}
document.getElementById('output').innerHTML = lvalue;
}
<input id="input" type="text" />
<button onClick="calculate()">Round</button>
<div id="output"></div>
let lvalue = $(".leave-input").val();
const integer = Math.trunc(lvalue);
const decimal = lvalue % 1;// or you could do lvalue - interger
if (integer >= 7 && integer <= 16) {
if (decimal <= 0.29) {
lvalue = roundDown();
} else if (decimal >= 0.3) {
lvalue = roundUp();
}
}
$(".leave-input").change(function(){
let lvalue = parseFloat($(".leave-input").val());
const val = lvalue * 100 % 100 ;
if (val <= 29) {
lvalue = Math.floor(lvalue);//roundDown();
} else {//your condition will skip anything between .29 and .30
lvalue = Math.ceil(lvalue);//roundUp();
}
$(".result").html(lvalue);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="leave-input" />
<div class="result"></div>
I have a signed value given as a hex number, by example 0xffeb and want convert it into -21 as a "normal" Javascript integer.
I have written some code so far:
function toBinary(a) { //: String
var r = '';
var binCounter = 0;
while (a > 0) {
r = a%2 + r;
a = Math.floor(a/2);
}
return r;
}
function twoscompl(a) { //: int
var l = toBinaryFill(a).length;
var msb = a >>> (l-1);
if (msb == 0) {
return a;
}
a = a-1;
var str = toBinary(a);
var nstr = '';
for (var i = 0; i < str.length; i++) {
nstr += str.charAt(i) == '1' ? '0' : '1';
}
return (-1)*parseInt(nstr);
}
The problem is, that my function returns 1 as MSB for both numbers because only at the MSB of the binary representation "string" is looked. And for this case both numbers are 1:
-21 => 0xffeb => 1111 1111 1110 1011
21 => 0x15 => 1 0101
Have you any idea to implement this more efficient and nicer?
Greetings,
mythbu
Use parseInt() to convert (which just accepts your hex string):
parseInt(a);
Then use a mask to figure out if the MSB is set:
a & 0x8000
If that returns a nonzero value, you know it is negative.
To wrap it all up:
a = "0xffeb";
a = parseInt(a, 16);
if ((a & 0x8000) > 0) {
a = a - 0x10000;
}
Note that this only works for 16-bit integers (short in C). If you have a 32-bit integer, you'll need a different mask and subtraction.
I came up with this
function hexToInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
And usage:
var res = hexToInt("FF"); // -1
res = hexToInt("A"); // same as "0A", 10
res = hexToInt("FFF"); // same as "0FFF", 4095
res = hexToInt("FFFF"); // -1
So basically the hex conversion range depends on hex's length, ant this is what I was looking for. Hope it helps.
Based on #Bart Friederichs I've come with:
function HexToSignedInt(num, numSize) {
var val = {
mask: 0x8 * Math.pow(16, numSize-1), // 0x8000 if numSize = 4
sub: -0x1 * Math.pow(16, numSize) //-0x10000 if numSize = 4
}
if((parseInt(num, 16) & val.mask) > 0) { //negative
return (val.sub + parseInt(num, 16))
}else { //positive
return (parseInt(num,16))
}
}
so now you can specify the exact length (in nibbles).
var numberToConvert = "CB8";
HexToSignedInt(numberToConvert, 3);
//expected output: -840
function hexToSignedInt(hex) {
if (hex.length % 2 != 0) {
hex = "0" + hex;
}
var num = parseInt(hex, 16);
var maxVal = Math.pow(2, hex.length / 2 * 8);
if (num > maxVal / 2 - 1) {
num = num - maxVal
}
return num;
}
function hexToUnsignedInt(hex){
return parseInt(hex,16);
}
the first for signed integer and
the second for unsigned integer
As I had to turn absolute numeric values to int32 values that range from -2^24 to 2^24-1,
I came up with this solution, you just have to change your input into a number through parseInt(hex, 16), in your case, nBytes is 2.
function toSignedInt(value, nBytes) { // 0 <= value < 2^nbytes*4, nBytes >= 1,
var hexMask = '0x80' + '00'.repeat(nBytes - 1);
var intMask = parseInt(hexMask, 16);
if (value >= intMask) {
value = value - intMask * 2;
}
return value;
}
var vals = [ // expected output
'0x00', // 0
'0xFF', // 255
'0xFFFFFF', // 2^24 - 1 = 16777215
'0x7FFFFFFF', // 2^31 -1 = 2147483647
'0x80000000', // -2^31 = -2147483648
'0x80000001', // -2^31 + 1 = -2147483647
'0xFFFFFFFF', // -1
];
for (var hex of vals) {
var num = parseInt(hex, 16);
var result = toSignedInt(num, 4);
console.log(hex, num, result);
}
var sampleInput = '0xffeb';
var sampleResult = toSignedInt(parseInt(sampleInput, 16), 2);
console.log(sampleInput, sampleResult); // "0xffeb", -21
Based on the accepted answer, expand to longer number types:
function parseSignedShort(str) {
const i = parseInt(str, 16);
return i >= 0x8000 ? i - 0x10000 : i;
}
parseSignedShort("0xffeb"); // -21
function parseSignedInt(str) {
const i = parseInt(str, 16);
return i >= 0x80000000 ? i - 0x100000000 : i;
}
parseSignedInt("0xffffffeb"); // -21
// Depends on new JS feature. Only supported after ES2020
function parseSignedLong(str) {
if (!str.toLowerCase().startsWith("0x"))
str = "0x" + str;
const i = BigInt(str);
return Number(i >= 0x8000000000000000n ? i - 0x10000000000000000n : i);
}
parseSignedLong("0xffffffffffffffeb"); // -21
I have a code that is inserting the total value into a textbox, however, the math that is performed does not round the number. Based on the code below how can I make this happen?
function calculate(){
var mrc = document.getElementById('box1');
var days = document.getElementById('box2');
var total = document.getElementById('box3');
var reason = document.getElementById('box4');
var approver = document.getElementById('box5');
var approvalreason = document.getElementById('box6');
var custname = document.getElementById('box7');
var caseid = document.getElementById('box8');
var intermitent = document.getElementById('rb1');
var outage = document.getElementById('rb2');
if (outage.checked === true) {
if (days.value * 5 > mrc.value){
total.value = (mrc.value / 30) * days.value;
} else if (days.value > 14) {
total.value = (mrc.value / 30) * days.value;
} else {
total.value = days.value * 5;
}
} else if (intermitent.checked === true){
if (days.value * 3 > mrc.value)
{
total.value = (mrc.value / 30) * days.value;
} else if (days.value > 14) {
total.value = (mrc.value / 30) * days.value;
} else {
total.value = days.value * 3;
}
}
}
Two things:
You're playing with fire by using implicit type conversion. element.value returns a string, not a number, so you should be using parseInt() or parseFloat() to convert your values to numbers. For instance, if your input has value 3, and you do element.value + 2, the result is 32.
Second, to your question, Math.ceil() rounds a float up to the near integer.
Use round() method to rounds a number to the nearest integer.
Example:
var a = Math.round(8.70);
Answer a = 9;
Try the following code:
function toFixed(value, precision) {
var precision = precision || 0,
power = Math.pow(10, precision),
absValue = Math.abs(Math.round(value * power)),
result = (value < 0 ? '-' : '') + String(Math.floor(absValue / power));
if (precision > 0) {
var fraction = String(absValue % power),
padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');
result += '.' + padding + fraction;
}
return result;
}
alert(toFixed(1.0000000,3));
Following is the fiddle link:
Demo
I'm using Angular "currency" filter to show price in a shopping cart. The prices are fetched from a back end server. So sometimes the price may not be available to show to the user. In that case I just want to show the user that the price is not available in the same field as of currency field. I can not show plain text in a currency filter. The only solution I found is to keep another text field to show/hide when a price is not available.But this is some what unnecessary I think. Is there any way to extend or override the built in "currency" filter of Angular js ?. Kindly appreciate some help.
<div class="large-12 medium-12 small-12 columns pad-none nzs-pro-list-item-price">
{{item.ItmPrice|currency}}
</div>
Create your custom filter which will internally use currency when value is present, otherwise it will return text which you want to show instead.
Markup
{{amount | customFormat:"USD$": "N/A"}}
Filter
.filter('customFormat', function($filter) {
return function(value, format, text) {
if (angular.isDefined(value) && value != null)
return $filter('currency')(value, format);
else
return text;
}
});
Working Plunkr
I feel the best way is to rewrite currency filter, so that you have fill control over Pattern, Grouping Separator, Decimal Separator & symbol position
<span>
{{26666662.5226 | fmtCurrency :"##.###,###" : "." : "," : "$" : "first"}}
</span>
Resluts in: $26.666.662,523
Filter:
app.filter("fmtCurrency", ['CurrencyService', function sasCurrency(CurrencyService) {
return function (amount, pattern, groupingSeparator, decimalSeparator, currencySymbol, symbolPosition) {
var patternInfo = CurrencyService.parsePattern(pattern, groupingSeparator, decimalSeparator);
var formattedCurrency = CurrencyService.formatCurrency(amount, patternInfo, groupingSeparator, decimalSeparator);
if (symbolPosition === 'last')
return formattedCurrency + currencySymbol;
else
return currencySymbol + formattedCurrency;
};
}])
Service: formatNumber which is the same function used in angular currency filter is being used here inside service
app.service("CurrencyService", function () {
var PATTERN_SEP = ';',
DECIMAL_SEP = '.',
GROUP_SEP = ',',
ZERO = '0',
DIGIT = "#";
var MAX_DIGITS = 22;
var ZERO_CHAR = '0';
return {
parsePattern: function (pattern, groupingSeparator, decimalSeparator) {
return parsePattern(pattern, groupingSeparator, decimalSeparator);
},
formatCurrency: function (amount, patternInfo, groupingSeparator, decimalSeparator) {
return formatNumber(amount, patternInfo, groupingSeparator, decimalSeparator);
}
}
/*
* Currency formatter utility
*/
function isUndefined(value) { return typeof value === 'undefined'; }
/**
* main function for parser
* #param str {string} pattern to be parsed (e.g. #,##0.###).
*/
function parsePattern(pattern, groupSep, decimalSep) {
DECIMAL_SEP = decimalSep;
GROUP_SEP = groupSep;
var p = {
minInt: 1,
minFrac: 0,
maxFrac: 0,
posPre: '',
posSuf: '',
negPre: '',
negSuf: '',
gSize: 0,
lgSize: 0
};
var ZERO = '0',
DIGIT = "#";
var parts = pattern.split(PATTERN_SEP),
positive = parts[0],
negative = parts[1];
var parts = positive.split(DECIMAL_SEP),
integer = parts[0],
fraction = parts[1];
console.log(parts);
p.posPre = integer.substr(0, integer.indexOf(DIGIT));
if (fraction) {
for (var i = 0; i < fraction.length; i++) {
var ch = fraction.charAt(i);
console.log(ch, ZERO, DIGIT);
if (ch == ZERO)
p.minFrac = p.maxFrac = i + 1;
else if (ch == DIGIT)
p.maxFrac = i + 1;
else
p.posSuf += ch;
}
}
var groups = integer.split(GROUP_SEP);
p.gSize = groups[1] ? groups[1].length : 0;
p.lgSize = (groups[2] || groups[1]) ? (groups[2] || groups[1]).length : 0;
if (negative) {
var trunkLen = positive.length - p.posPre.length - p.posSuf.length,
pos = negative.indexOf(DIGIT);
p.negPre = negative.substr(0, pos).replace(/\'/g, '');
p.negSuf = negative.substr(pos + trunkLen).replace(/\'/g, '');
} else {
// hardcoded '-' sign is fine as all locale use '-' as MINUS_SIGN. (\u2212 is the same as '-')
p.negPre = '-' + p.posPre;
p.negSuf = p.posSuf;
}
return p;
}
function isString(value) { return typeof value === 'string'; }
function isNumber(value) { return typeof value === 'number'; }
/**
* Format a number into a string
* #param {number} number The number to format
* #param {{
* minFrac, // the minimum number of digits required in the fraction part of the number
* maxFrac, // the maximum number of digits required in the fraction part of the number
* gSize, // number of digits in each group of separated digits
* lgSize, // number of digits in the last group of digits before the decimal separator
* negPre, // the string to go in front of a negative number (e.g. `-` or `(`))
* posPre, // the string to go in front of a positive number
* negSuf, // the string to go after a negative number (e.g. `)`)
* posSuf // the string to go after a positive number
* }} pattern
* #param {string} groupSep The string to separate groups of number (e.g. `,`)
* #param {string} decimalSep The string to act as the decimal separator (e.g. `.`)
* #param {[type]} fractionSize The size of the fractional part of the number
* #return {string} The number formatted as a string
*/
function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
var isInfinity = !isFinite(number);
var isZero = false;
var numStr = Math.abs(number) + '',
formattedText = '',
parsedNumber;
if (isInfinity) {
formattedText = '\u221e';
} else {
parsedNumber = parse(numStr, '.');
roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
var digits = parsedNumber.d;
var integerLen = parsedNumber.i;
var exponent = parsedNumber.e;
var decimals = [];
isZero = digits.reduce(function (isZero, d) { return isZero && !d; }, true);
// pad zeros for small numbers
while (integerLen < 0) {
digits.unshift(0);
integerLen++;
}
// extract decimals digits
if (integerLen > 0) {
decimals = digits.splice(integerLen, digits.length);
} else {
decimals = digits;
digits = [0];
}
// format the integer digits with grouping separators
var groups = [];
if (digits.length >= pattern.lgSize) {
groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));
}
while (digits.length > pattern.gSize) {
groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));
}
if (digits.length) {
groups.unshift(digits.join(''));
}
formattedText = groups.join(groupSep);
// append the decimal digits
if (decimals.length) {
formattedText += decimalSep + decimals.join('');
}
if (exponent) {
formattedText += 'e+' + exponent;
}
}
if (number < 0 && !isZero) {
return pattern.negPre + formattedText + pattern.negSuf;
} else {
return pattern.posPre + formattedText + pattern.posSuf;
}
}
function parse(numStr, decimalSep) {
var exponent = 0, digits, numberOfIntegerDigits;
var i, j, zeros;
DECIMAL_SEP = decimalSep;
// Decimal point?
if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
numStr = numStr.replace(DECIMAL_SEP, '');
}
// Exponential form?
if ((i = numStr.search(/e/i)) > 0) {
// Work out the exponent.
if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
numberOfIntegerDigits += +numStr.slice(i + 1);
numStr = numStr.substring(0, i);
} else if (numberOfIntegerDigits < 0) {
// There was no decimal point or exponent so it is an integer.
numberOfIntegerDigits = numStr.length;
}
// Count the number of leading zeros.
for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) {/* jshint noempty: false */ }
if (i === (zeros = numStr.length)) {
// The digits are all zero.
digits = [0];
numberOfIntegerDigits = 1;
} else {
// Count the number of trailing zeros
zeros--;
while (numStr.charAt(zeros) === ZERO_CHAR) zeros--;
// Trailing zeros are insignificant so ignore them
numberOfIntegerDigits -= i;
digits = [];
// Convert string to array of digits without leading/trailing zeros.
for (j = 0; i <= zeros; i++ , j++) {
digits[j] = +numStr.charAt(i);
}
}
// If the number overflows the maximum allowed digits then use an exponent.
if (numberOfIntegerDigits > MAX_DIGITS) {
digits = digits.splice(0, MAX_DIGITS - 1);
exponent = numberOfIntegerDigits - 1;
numberOfIntegerDigits = 1;
}
return { d: digits, e: exponent, i: numberOfIntegerDigits };
}
/**
* Round the parsed number to the specified number of decimal places
* This function changed the parsedNumber in-place
*/
function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
var digits = parsedNumber.d;
var fractionLen = digits.length - parsedNumber.i;
// determine fractionSize if it is not specified; `+fractionSize` converts it to a number
fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
// The index of the digit to where rounding is to occur
var roundAt = fractionSize + parsedNumber.i;
var digit = digits[roundAt];
if (roundAt > 0) {
// Drop fractional digits beyond `roundAt`
digits.splice(Math.max(parsedNumber.i, roundAt));
// Set non-fractional digits beyond `roundAt` to 0
for (var j = roundAt; j < digits.length; j++) {
digits[j] = 0;
}
} else {
// We rounded to zero so reset the parsedNumber
fractionLen = Math.max(0, fractionLen);
parsedNumber.i = 1;
digits.length = Math.max(1, roundAt = fractionSize + 1);
digits[0] = 0;
for (var i = 1; i < roundAt; i++) digits[i] = 0;
}
if (digit >= 5) {
if (roundAt - 1 < 0) {
for (var k = 0; k > roundAt; k--) {
digits.unshift(0);
parsedNumber.i++;
}
digits.unshift(1);
parsedNumber.i++;
} else {
digits[roundAt - 1]++;
}
}
// Pad out with zeros to get the required fraction length
for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
// Do any carrying, e.g. a digit was rounded up to 10
var carry = digits.reduceRight(function (carry, d, i, digits) {
d = d + carry;
digits[i] = d % 10;
return Math.floor(d / 10);
}, 0);
if (carry) {
digits.unshift(carry);
parsedNumber.i++;
}
}
})
$provide.decorator('currencyFilter', ['$delegate',
function ($delegate) {
var crncyFilter = $delegate;
var extendsFilter = function () {
var res = crncyFilter.apply(this, arguments);
if (arguments[2]) {
var digi1 = arguments[2] || 2;
return arguments[1] + Number(arguments[0]).toFixed(digi1);
}
else {
if (arguments[1] == "¥") {
return arguments[1] + Number(arguments[0]).toFixed(1);
}
}
};
return extendsFilter;
}]);
This is the way to Override Decimal digit
I am attempting to create a directive and filter to take a number input from a input type number and on blur display it as a fraction (if applicable) and then on focus display it as a decimal. The model will need to be stored as a decimal.
My current code works if the field is a text field as the model is a fraction, however if I change it to a number field it will not allow for a model update as the string is not a number. I do not have the on blur/on focus worked out yet but that should be less of an issue than this step.
Any help would be greatly appreciated!
My code so far is as follows:
.directive('fractionView', ['$filter', function($filter) {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function(inputValue) {
var transformedInput = $filter('fraction')(inputValue);
if (transformedInput != inputValue && transformedInput) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
};
}])
.filter('fraction', function() {
return function(input) {
function HCF(u, v) {
var U = u, V = v;
while (true) {
if (!(U %= V))
return V;
if (!(V %= U))
return U;
}
}
return fraction(input);
//convert a decimal into a fraction
function fraction(decimal) {
if (!decimal) {
decimal = this;
}
whole = String(decimal).split('.')[0];
decimal = parseFloat("." + String(decimal).split('.')[1]);
num = "1";
for (z = 0; z < String(decimal).length - 2; z++) {
num += "0";
}
decimal = decimal * num;
num = parseInt(num);
for (z = 2; z < decimal + 1; z++) {
if (decimal % z == 0 && num % z == 0) {
decimal = decimal / z;
num = num / z;
z = 2;
}
}
//if format of fraction is xx/xxx
if (decimal.toString().length == 2 &&
num.toString().length == 3) {
//reduce by removing trailing 0's
decimal = Math.round(Math.round(decimal) / 10);
num = Math.round(Math.round(num) / 10);
}
//if format of fraction is xx/xx
else if (decimal.toString().length == 2 &&
num.toString().length == 2) {
decimal = Math.round(decimal / 10);
num = Math.round(num / 10);
}
//get highest common factor to simplify
var t = HCF(decimal, num);
//return the fraction after simplifying it
if (isNaN((decimal / t)) || isNaN(t)) {
return;
} else {
return ((whole == 0) ? "" : whole + " ") + decimal / t + "/" + num / t;
}
}
}
});
I believe the problem is easier to conceptualize if we look at the the desired functionality on focus and on blur:
Focus: Display the decimal value.
Blur: Save the decimal value then compute and display the fractional representation.
Although it may be possible to do this using a single ngModel and $parsers by converting from decimal to a fraction and vice versa, I think it's simpler to solve if there is a separation between the exposed ngModel (the decimal value) and the displayed ngModel (the display/fractional value).
I took a shot at it here.