3

I have a function which takes an array as an argument and later process it and change values of this array. The problem is that the array was made of JQuery nodes(usual span), and I access this span value by calling .text() JQuery method. Here's how it looks:

var array= 
[
    $('*[id$=id1]'),
    $('*[id$=id2]'),
    $('*[id$=id3]'),
    $('*[id$=id4]'),
    $('*[id$=id5]')
] // Ignore the weird way of the selectors. It's just a feature of back-end technology I use

function removeZeros(arr) 
{
  var map = arr.map(function(a) {
   //logic to perform...
  }
  arr.forEach(function(value, index, arr) 
  {
  arr[index] = Number.parseFloat(value).toFixed(maxNum);
  });
  //Rewriting the values..
  }
}

removeZeros(array)

In the example above I get an exception since the values which are stored in the array are just plain HTML code. The real value I access using .text() as I mentioned earlier. So I need to make the a in the function call this method. I've tried (function($(a).text(), (function($(a.text()) and (function($a.text()) so far, but nothing seems to work, it throws a nasty exception of unexcepted literal. How do I access text() anyway?

Whole function:

function removeZeros(arr) 
{
  var map = arr.map(function(a)
  {
  if (a % 1 === 0) 
  {
  var res = "1";
  } 
  else 
  {
      var lastNumman = a.toString().split('').pop();
      if (lastNumman == 0)
      {
        var m = parseFloat(a);
        var res = (m + "").split(".")[1].length;
      } 
      else 
      {
        var m = a.split(".")[1].length;
        var res = m;
      }
  }
  return res;

  });

  var maxNum = map.reduce(function(a, b) {
    return Math.max(a, b);
  });

  arr.forEach(function(value, index, arr) {
  arr[index] = Number.parseFloat(value.text()).toFixed(maxNum);
  });

}

1 Answers1

3

In the example above I get an exception since the values which are stored in the array are just plain HTML code.

No, they're jQuery instances. Calling Number.parseFloat on a jQuery instance is going to return NaN*.

You don't need to do anything special if you want to access the text, the entry is a jQuery object, just call .text() on it directly:

arr[index] = Number.parseFloat(value.text()).toFixed(maxNum);
// ---------------------------------^^^^^^^

* (because parseFloat will coerce the object to string, getting "[object Object]", and "[object Object]" cannot be parsed to a float)


Having seen the full function, as you said in a comment, you'll want to use .text on a as well. Here's that and some other notes:

function removeZeros(arr) {
    var map = arr.map(function(a) {
        var res, astNumman, m;

        // *** Get the text of the entry
        a = a.text();

        if (a % 1 === 0) { // *** ? `a` is a string. This will coerce it to number and then do % on it.
            res = "1";
        } else {
            lastNumman = a[a.length-1];              // *** Much more efficient than `a.split('').pop();`
            if (lastNumman == 0) {                   // *** Again using a string as a number
                m = parseFloat(a);
                res = (m + "").split(".")[1].length; // *** The *length* of the fractional portion?
            } else {
                m = a.split(".")[1].length;
                res = m;
            }
        }
        return res;
    });

    var maxNum = map.reduce(function(a, b) {
        return Math.max(a, b);
    });

    // ***
    arr.forEach(function(value, index, arr) {
        arr[index] = Number.parseFloat(value.text()).toFixed(maxNum);
    });
}

Running Example:

var array= 
[
    $('*[id$=id1]'),
    $('*[id$=id2]'),
    $('*[id$=id3]'),
    $('*[id$=id4]'),
    $('*[id$=id5]')
];

function removeZeros(arr) {
    var map = arr.map(function(a) {
        var res, astNumman, m;

        // *** Get the text of the entry
        a = a.text();

        if (a % 1 === 0) { // *** ? `a` is a string. This will coerce it to number and then do % on it.
            res = "1";
        } else {
            lastNumman = a[a.length-1];              // *** Much more efficient than `a.split('').pop();`
            if (lastNumman == 0) {                   // *** Again using a string as a number
                m = parseFloat(a);
                res = (m + "").split(".")[1].length; // *** The *length* of the fractional portion?
            } else {
                m = a.split(".")[1].length;
                res = m;
            }
        }
        return res;
    });

    var maxNum = map.reduce(function(a, b) {
        return Math.max(a, b);
    });

    // ***
    arr.forEach(function(value, index, arr) {
        arr[index] = Number.parseFloat(value.text()).toFixed(maxNum);
    });
}

removeZeros(array);
console.log(array);
<div id="id1">7</div>
<div id="id2">6.4324</div>
<div id="id3">8.24</div>
<div id="id4">8998.3</div>
<div id="id5">0</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

It seems like the goal of removeZeroes is to convert the array of jQuery objects into an array of strings with the text of the object converted to number and then to string where they all have the same number of digits after the decimal (the longest one). If so, we can be a bit more efficient about it:

function removeZeros(arr) {
    // Find longest decimal portion, convert jQuery objects to numbers
    var longest = -Infinity;
    arr.forEach(function(entry, index) {
        var num = parseFloat(entry.text());
        var str = String(num);
        var decimal = str.indexOf(".");
        var thisLength;
        if (decimal === -1) {
            thisLength = 1;
        } else {
            thisLength = str.length - decimal - 1;
        }
        if (thisLength > longest) {
            longest = thisLength;
        }
        arr[index] = num;
    });

    // Format numbers as strings
    arr.forEach(function(num, index) {
        arr[index] = num.toFixed(longest);
    });
}

Running Example:

var array= 
[
    $('*[id$=id1]'),
    $('*[id$=id2]'),
    $('*[id$=id3]'),
    $('*[id$=id4]'),
    $('*[id$=id5]')
];

function removeZeros(arr) {
    // Find longest decimal portion, convert jQuery objects to numbers
    var longest = -Infinity;
    arr.forEach(function(entry, index) {
        var num = parseFloat(entry.text());
        var str = String(num);
        var decimal = str.indexOf(".");
        var thisLength;
        if (decimal === -1) {
            thisLength = 1;
        } else {
            thisLength = str.length - decimal - 1;
        }
        if (thisLength > longest) {
            longest = thisLength;
        }
        arr[index] = num;
    });

    // Format numbers as strings
    arr.forEach(function(num, index) {
        arr[index] = num.toFixed(longest);
    });
}

removeZeros(array);
console.log(array);
<div id="id1">7</div>
<div id="id2">6.4324</div>
<div id="id3">8.24</div>
<div id="id4">8998.3</div>
<div id="id5">0</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

There I've used your arr.forEach-assign-to-arr[index] pattern rather than map as you seemed to prefer it (and it does avoid creating two unnecessary arrays).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Yep, I have to call `text()` on value as well. But I also care about the **a**, cause I use these JQuery instances to perform the logic... If I try to just do like this **(function(a.text()** I get Uncaught SyntaxError: Unexpected token . – Robert Baratheon Feb 02 '18 at 07:40
  • 1
    @RobertBaratheon: You wouldn't put `.text()` on the parameter declaration like that. You'd use it on `a` in the function body. (You haven't shown code using `a`, so it's hard to tell you quite where to put it...) – T.J. Crowder Feb 02 '18 at 07:48
  • I've just posted the entire function. Please take a look – Robert Baratheon Feb 02 '18 at 07:52
  • If you just want the text from `a`, make this the first line of your `map` callback: `a = a.text();` (and later there's no reason to call `.toString()` on `a`). (Note you have a syntax error in that function, extra `)` on the first `if`. Also, you need declare a variable only **once** in any given scope; putting `var` in front of every use of a variable is unnecessary and difficult to read.) – T.J. Crowder Feb 02 '18 at 07:54
  • @RobertBaratheon: It's also suspicious that you're using `a % 1` when `a` is a string... – T.J. Crowder Feb 02 '18 at 07:59
  • Well, it's considered to always be a number – Robert Baratheon Feb 02 '18 at 08:00
  • @RobertBaratheon: Then convert it to number up-front using unary `+`, `parseFloat`, `Number.parseFloat`, etc. (whichever you prefer). Is the end goal of `removeZeros` to convert the array of jQuery objects into an array of strings, all with the same number of digits after the decimal? – T.J. Crowder Feb 02 '18 at 08:05
  • @RobertBaratheon: Updated the answer to apply `.text` to the whole function, and to suggest a possible replacement for it. – T.J. Crowder Feb 02 '18 at 08:14
  • You could take a look at the question on what this method does.. https://stackoverflow.com/questions/48561779/removing-zeros-after-comma-based-on-maximum-consequent-zeros – Robert Baratheon Feb 02 '18 at 08:20
  • Unfortunalety I still get the exception **value.text** is not a function :( – Robert Baratheon Feb 02 '18 at 08:24
  • @RobertBaratheon: Not with the code from the answer and the array from the question, see the running examples I just added. – T.J. Crowder Feb 02 '18 at 08:30
  • Yes, the error occured in another part of the code. Thank you very much for helping out! :) – Robert Baratheon Feb 02 '18 at 08:36
  • Well, now I can exaclty locate the problem - after invoking the function array of JQuery objects becomes an array of just plain numbers.. Since that later I cannot change it's value by invoking text()... cause it cannot be invoked on a number... – Robert Baratheon Feb 02 '18 at 08:48
  • So can I make something like `arr[index].text() = `? – Robert Baratheon Feb 02 '18 at 08:58
  • @RobertBaratheon: Well yes, obviously, once you've filled the array with numbers it's filled with numbers. If you don't want to do that, leave the original array alone and put the numbers in a new array (`map` is good for that). Separately: If you want to set the text of an element, [the documentation addresses doing that](http://api.jquery.com/text/#text2). – T.J. Crowder Feb 02 '18 at 08:59
  • 1
    Well, I finally have done it. `arr[index].text(Number.parseFloat(value.text()).toFixed(maxNum));` helped me. I don't need to change type of an object, instead I only needed to change property of an object – Robert Baratheon Feb 02 '18 at 09:05