Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List element value returns wrong values when accessing attribute

I have a React component that I am trying to implement so that it can pass the particular value of the list item that a user clicks to a handle method.

var React = require('react');
var {connect} = require('react-redux');

export var Keyboard = React.createClass({
    handleKeyClick: function(keyClicked)
      {
          console.log(keyClicked.target.value);       
      },  
    render: function () {
        return (
            <ul onClick={(e) => this.handleKeyClick(e)}>
                <li value="1">1</li>
                <li value="2">2</li>
                <li value="3">3</li>
                <li value="4">4</li>
                <li value="5">5</li>
                <li value="6">6</li>
                <li value="7">7</li>
                <li value="8">8</li>
                <li value="9">9</li>
                <li value="0">0</li>
                <li value="B">B</li>
             </ul>  
        );
    }

 });
 export default connect()(Keyboard);

This works properly for all of the integer valued list items, but when I click the list item with the value of B, I receive 0 as my value, rather than B. Am I unaware of a restriction that only allows integers to be passed through onClick methods? Or perhaps I configured the onClick method incorrectly. Other examples of this situation:

  • value="3f" returns 3
  • value="H5" returns 0
  • value="35" returns 35

It seems apparent this is an issue with the String, but I don't know why. I'm using React version "^0.14.7"

like image 243
Trent Miller Avatar asked Feb 27 '17 23:02

Trent Miller


People also ask

What is the return value when I specify a range?

When specifying a range, the return value will be a new list with the specified items. Note: The search will start at index 2 (included) and end at index 5 (not included).

How to access index and value in a list in Java?

Let’s see all the different way of accessing both index and value in a list. Method #1 : Naive method This is the most generic method that can be possibly employed to perform this task of accessing the index along with the value of the list elements. This is done using a loop.

How to get the index along with its value?

This method enumerates for index along with its value. Another method that is basically used to bind the index with the corresponding value, zip () can also be possibly used to get index along with its value. Writing code in comment? Please use ide.geeksforgeeks.org , generate link and share the link here.


1 Answers

Explanation

This isn't React's fault. This is defined in the HTML5 Specification to behave this way. Per the link:

4.4.7 The li element

[...]

Content attributes:

 Global attributes
 If the element is a child of an ol element: value - Ordinal value of the list item

Where value is defined as such:

The value attribute, if present, must be a valid integer giving the ordinal value of the list item.

And a "valid integer" is defined as such:

A string is a valid integer if it consists of one or more ASCII digits, optionally prefixed with a "-" (U+002D) character

[...]

The rules for parsing integers are as given in the following algorithm. When invoked, the steps must be followed in the order given, aborting at the first step that returns a value. This algorithm will return either an integer or an error.

  1. Let input be the string being parsed.

  2. Let position be a pointer into input, initially pointing at the start of the string.

  3. Let sign have the value "positive".

  4. Skip whitespace.

  5. If position is past the end of input, return an error.

  6. If the character indicated by position (the first character) is a "-" (U+002D) character:
    a. Let sign be "negative".
    b. Advance position to the next character.
    c. If position is past the end of input, return an error.

  7. Otherwise, if the character indicated by position (the first character) is a "+" (U+002B) character:
    a. Advance position to the next character. (The "+" is ignored, but it is not conforming.)
    b. If position is past the end of input, return an error.

  8. If the character indicated by position is not an ASCII digit, then return an error.

  9. Collect a sequence of characters that are ASCII digits, and interpret the resulting sequence as a base-ten integer. Let value be that integer.

  10. If sign is "positive", return value, otherwise return the result of subtracting value from zero.

In steps 8 and 9, it describes the behavior you see. The following examples:

  • "3f" returns 3
  • "H5" returns 0
  • "35" returns 35

The first returns 3 because of step 9. It collects all the ASCII digits present if the first character is an integer, which is just 3, and interprets as an integer. In the second example, it returns 0 because of this:

If the value attribute is present, user agents must parse it as an integer, in order to determine the attribute's value. If the attribute's value cannot be converted to a number, the attribute must be treated as if it was absent. The attribute has no default value.

Parsing fails on H5 because the first character is not +, -, or an ASCII digit. Since the attribute is treated as absent as it's invalid, it's just 0, because value still needs to be a valid integer. If you pass an invalid integer that can't be parsed, the result of access attribute value is just 0, which is per the HTML Living Standard, in the applicable paragraph:

If a reflecting IDL attribute has a signed integer type (long) then, on getting, the content attribute must be parsed according to the rules for parsing signed integers, and if that is successful, and the value is in the range of the IDL attribute's type, the resulting value must be returned. If, on the other hand, it fails or returns an out of range value, or if the attribute is absent, then the default value must be returned instead, or 0 if there is no default value. On setting, the given value must be converted to the shortest possible string representing the number as a valid integer and then that string must be used as the new content attribute value.

Here, the value attribute is not defined to have a default value, and in this case H5 isn't a valid integer so parsing fails and 0 is returned by specification. The last example returns 35 because it's a completely valid integer for value.

Solution

So instead, you can use Element.getAttribute. Per the link:

getAttribute() returns the value of a specified attribute on the element

No conversion happens in the method. It just gets the value as it does not need to convert to integer to figure out ordering as HTML does to determine where to place the lis. The HTML Living Standard outlines the internal workings of this method. It just accesses a NamedNodeMap containing attributes and does not to any conversion. Thus:

console.log(document.getElementById("test").getAttribute("value"));
<ul>
  <li value="Foobar" id="test">Test</li>
</ul>

This can be applied to your situation by doing this:

keyClicked.target.getAttribute("value");
like image 71
Andrew Li Avatar answered Oct 19 '22 18:10

Andrew Li