How to create lists with icons in a simpler or better way?

I am trying to create ul / li dynamically. And set an icon based on the value of data.

Static approach
Symbol is used here https://css-tricks.com/svg-symbol-good-choice-icons/

fiddle: https://jsfiddle.net/6xtvz3r5/

Dynamic approach
The list data is stored in a SQL table and the id of the icon as well. The icons are stored as “symbols” as above

fiddle: https://jsfiddle.net/bLthaxu7/

As a Javascript newbie I find this solution a bit clumsy. Is there a better solution?

It might be a silly question but could this be done in php?

If you are sticking to JS, a more optimized alternative would be to use documentFragment.

Another method to consider is template literals

Here is an example using template literals and the fetch api instead.

const fillTable = function (data) {
  const ul = document.getElementById('list')
  const list = data.map((listItem) => {
  	return `
    	<li data-id="${listItem.status_id}">
    		<svg class="icon"> <use xlink:href="#status${listItem.status_id}"/></svg>
            ${listItem.status_en}
        </li>
    `
  }).join(`\n`)
  
  ul.insertAdjacentHTML('afterbegin', list)
}


fetch('https://api3.go4webdev.org/status/all')
  .then((response) => response.json())
  .then(fillTable)
  .catch(error => console.log(error))
2 Likes

First of all you should use fetch() instead of XMLHttpRequest() (This looks much more nice as well :slight_smile: )

Why do you use start and end variable? They do nothing. So you can also put the strings directly into the creation which makes the code easier to read.

Using ul as a global variable is a not a good idea. You should declare it in your filltable() function.
Also please take care of camelCase. the function name should by filterTable() instead.

All other things I would like to write was done by rpg while I was still writing. He is too fast for me :slight_smile:

3 Likes

I’m glad we’re on the same page :biggrin:

2 Likes

Being a backward bitch sort of, I do not know anything about PHP. But I am sure it can be done using Go and Go Templates :-). I will consider this as an option.

I have done some tests with fragments and I find it more logical and maybe faster. As I understand it, you write to memory before you update the page? Correct?

api3get();

var t0 = performance.now();

function api3get() {
  fetch('https://api3.go4webdev.org/status/all')
    .then((response) => response.json())
    .then(filltable)
    .catch(error => console.log(error))
}

var list = document.getElementById("list");
var start = `<svg class="icon"> <use xlink:href="#status`
var end = `"/></svg>`
var fragment = new DocumentFragment()

function filltable(data) {
  data.forEach(function(element) {
    var li = document.createElement('li')
    li.innerHTML = (start + element.status_id + end + element.status_en)
    fragment.appendChild(li)
  })
  list.appendChild(fragment)
}
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(0), 'milliseconds to generate');

fiddle: https://jsfiddle.net/8j947ey2/1/

I have used this in the past. What are the benefits? Speed?

I agree. Simpler and cleaner. Thank you for pulling me in the right direction.

It is just an old habit. I avoid long lines of code if I can. Any disadvantages using start and end variables?

If I declare the “list” variable as global, I may be able to use it later for hiding and positioning in another function? Or?

I did make a huge mistake some decade ago to use UPPERCASE column names in a database instead of lowercase. Besides SQL, working with Linux it have become a habit to use lowercase everywhere. And I have done many misspelling thanks to the camelCases.

And I have found many questions why it do not work because of misspelling camelcase on several forums. So I wonder what the benefits of camelCase are besides it is a common practice in Javascript?

And Thank You for your tips both of you. They were really helpful!

AS they are global yes there are some big disadvantages. If you, for example, use some third party script (library, framework whatever) and this script is also defining a global variable start or end and change the value of it, you might have some behavior which is super hard to debug.

Avoid global variables wherever possible. Also avoid using var at all. Use let or const to clearly define the scope it has.
If you really need global variables, which is in 99% of the cases not the case, you should attach them to your own namespace. In javascript this is done by adding your namespace to the window like

let window.myNameSpace = {};

where myNameSpace is something unique as your applications name. Then you can add your global vars with

window.nyNameSpace.start = ....

and of course retrieve everywhere else.

It doesn’t matter if you use Uppercase, Lowercase, Camelcase or whatever. You need to take care of the case anytime and everywhere. This is super important to become a good programmer.
So if you have to take care anyways, Why not use something easy to read? camelCase is not only common in javascript but in all programming languages I know. In the very long past you have used underscores to avoid upper case characters in your source code. so the functions were named like

delete_the_first_char_in_given_string()

for me that was the best readable but today it is recommended to use camelCase like

deleteTheFirstCharInGivenString()

what is also ok. But using lowercase its completely unreadable

deletethefirstcharingivenstring()

So yes, it makes sense to use camel Case.

Btw. You can use upper case column names in SQL. There is absolute no problem even on linux.

1 Like

Thank you for your explanation about the camelCases.

Of course I can use UPPERCASE in SQL, but you have to put every column within double quotes as “camelCase”. Lowercase makes it simpler in SQL using only camelcase (without quotes). Countless times I have missed the double quotes causing SQL errors (using Postgresql).

Yes so only one update/reflow of the page as opposed to many.

The speeds I believe are close to equivalent. The main benefit is instant readability — you don’t have to mentally process the javascript first.

Furthermore you can store these templates in modules and even wrap them in functions a bit like React components e.g.

listItem.js

export const listItem = ({status_ud, status_en}) => (`
  <li data-id="${status_id}">
    <svg class="icon"> <use xlink:href="#status${status_id}"/></svg>
    ${status_en}
  </li>
`)

Note: For the arguments ({status_ud, status_en}) I have used destructuring.

import { listItem } from 'templates/listItem.js'

...
// Can then just pass the listItem in as a callback to array.map
const list = data.map(listItem).join(`\n`)

Just to add regarding camelCase and Javascript, I would say it is also about consistency. For instance in css you would use background-color: red;, in javascript that translates to element.style.backgroundColor = 'red'.

The same applies to datasets <div data-date-of-birth='01/01/1982'>Joe Bloggs</div> in javascript would be read as element.dataset.dateOfBirth

I have to say I quite like that distinct separation of conventions between coding formats.

1 Like