3

I am stuck on a problem. I am using code that looks something like the following to populate a select with data but I am not getting the expected result.

let data = await response.json();
let result = data.checks.map((check) => {
  return {
    name: check.name,
    tag: check.tags,
  };
});
let hcList = document.getElementById("hclist");
Object.keys(result).map((key) => hcList.add(new Option(result[key], key)));
return result;
}
getHcList().then((result) => console.log(result));

The select populates but looks like this enter image description here

Here is what the result data looks like in console:

0: {name: "some name", tag: "some tag"}
1: {name: "some name1", tag: "some tag1"}
2: {name: "some name2", tag: "some tag2"}

I would like for just the name to populate this select. - Must use vanilla JS.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Aib Syed
  • 3,118
  • 2
  • 19
  • 30
  • do you want to just keep what's in the attribute `name` ? If so, wouldn't it suffice to not include the part with `tag: check.tags` ? – casenonsensitive Jul 07 '20 at 22:28
  • @casenonsensitive I plan to use tag later in another function. Would you say that I should fetch tag in a separate call even though the data is coming from the same endpoint? Also, I've tried using just name and the output within the select still populates as [object Object]. – Aib Syed Jul 07 '20 at 22:35
  • 1
    The output will populate as object because you're using the { } brackets. That creates an object (in this case containing the attributes name and tag). If you just want the string, change the return { ... } to return check.name; – casenonsensitive Jul 07 '20 at 22:37

1 Answers1

3

Your issue lies within your map() call, when you invoke new Option().

According to the Option() syntax on MDN, the first argument in the Option constructor is the text to display, and the second is the data the select option should point to when a given option is chosen. Since your key is really just an array index, what your current code is doing is displaying the object as "text" ([object Object]), and passing the index as data when selected.

Change

hcList.add(new Option(result[key], key))

to

hcList.add(new Option(result[key].name, JSON.stringify(result[key])))

to fix your problem. The JSON.stringify() is required because the value attribute only supports strings (Without it, the string [object Object] will be stored as your value!).

let result = [
  {name: "some name", tag: "some tag"},
  {name: "some name1", tag: "some tag1"},
  {name: "some name2", tag: "some tag2"}
];

let hcList = document.getElementById("hclist");
Object.keys(result).map((key) => hcList.add(new Option(result[key].name, JSON.stringify(result[key]))));

//Event listener to display value attribute for clarity
hcList.addEventListener("input", () => document.getElementById("optionData").innerHTML = hcList.value);
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
</head>
<body>
  <select id="hclist"></select>
  <p>Selected:</p>
  <p id="optionData"></p>
</body>
</html>

A side note: If you know that the data coming in is in array format, which it seems yours is since the console log you provided lists indexes in front of your objects, you can simplify your Object.keys(result).map() call to result.map(), like so:

result.map((key) => hcList.add(new Option(key.name, JSON.stringify(key))));
// 'key' is now each object element, rather than an index
zcoop98
  • 2,590
  • 1
  • 18
  • 31
  • BOOM this worked! Thank you for taking the time and looking into this issue. These things seem so much easier in React where you can map directly to JSX elements. That being said, do you believe there is a more elegant solution to this in vanilla JS, or is this route feasible as is? – Aib Syed Jul 08 '20 at 03:03
  • 2
    @Dr.Tenma That's a great question! As is, I'm not super experienced with DOM manipulation in vanilla JS, so I don't really have a great answer for you. My hunch is that it's very possible, though I do think that `JSON.stringify(. . .)` (and `JSON.parse(. . .)` on the output side) are a qualified solution, especially for simple objects. One possible issue is object complexity, if your object is too large or complex I suppose it could potentially cause performance issues with the JSON methods, but [string length itself wouldn't be an issue](https://stackoverflow.com/q/1496096/11047824). – zcoop98 Jul 08 '20 at 22:50
  • 1
    Give it a go, and if you have any specific obstacles that you run into, feel free to open up another question. Good luck! – zcoop98 Jul 16 '20 at 18:38