Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add HTML elements to DOM with JQuery nicely

At the moment, I add elements to the DOM with append with html inside of double quotes, this can become incredibly messy and very hard to read especially if you have variables inside of it, in React you would use JSX which is clean, is there a way to use JSX in an normal JQuery script or something like JSX?

like image 641
Elliott Coe Avatar asked Oct 17 '22 12:10

Elliott Coe


1 Answers

Yes, two options:

  1. Template literals

  2. JSX

Template literals

In modern JavaScript, you can use template literals rather than string literals, and they can include placeholders with JavaScript expressions in them:

let counter = 0;

$(`<table class="main">
    <tbody>
        <tr>
            <td>Cell ${counter++}</td>
            <td>Cell ${counter++}</td>
        </tr>
        <tr>
            <td>Cell ${counter++}</td>
            <td>Cell ${counter++}</td>
        </tr>
    </tbody>
</table>`).appendTo(document.body);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

There's still some awkwardness, definitely, but it's a lot better than string literals.

More on template literals on MDN.

JSX

JSX is not limited to React. It has its own specification and multiple implementations, such as jsx-transform.

For instance, here's a simple Node.js wrapper that uses it to transpile a file:

var jsx = require('jsx-transform');

console.log(jsx.fromFile("input.jsx", {
  factory: 'be'
}));

If input.jsx were:

let counter = 0;
let table =
    <table class="main">
        <tbody>
            <tr>
                <td>Cell {counter++}</td>
                <td>Cell {counter++}</td>
            </tr>
            <tr>
                <td>Cell {counter++}</td>
                <td>Cell {counter++}</td>
            </tr>
        </tbody>
    </table>;
table.appendTo(document.body);

(Note that that's class="main", not className="main". Using className instead is a React thing, to avoid an issue that hasn't been a problem since ES5 came out in 2009.)

The output would be:

let counter = 0;
let table =
    be('table', {class: "main"}, [
        be('tbody', null, [
            be('tr', null, [
                be('td', null, ["Cell ", counter++]),
                be('td', null, ["Cell ", counter++])
            ]),
            be('tr', null, [
                be('td', null, ["Cell ", counter++]),
                be('td', null, ["Cell ", counter++])
            ])
        ])
    ]);
table.appendTo(document.body);

Notice how the JSX expressions have been converted into calls to the factory function (be in that example; React's factory function is React.createElement). All you have to do is supply the be function and integrate the transformer into your build chain (jsx-transform comes prebaked with the ability to plug into Browserify).

Your be using jQuery might look something like this:

function be(tagName, attributes, children) {
    const result = $("<" + tagName + "/>");
    if (attributes) {
        result.attr(attributes);
    }
    if (children) {
        if (Array.isArray(children)) {
            for (const child of children) {
                result.append(child);
            }
        } else {
            result.append(child);
        }
    }
    return result;
}

Live Example of the be function using the transformed result:

let counter = 0;
let table =
    be('table', {class: "main"}, [
        be('tbody', null, [
            be('tr', null, [
                be('td', null, ["Cell ", counter++]),
                be('td', null, ["Cell ", counter++])
            ]),
            be('tr', null, [
                be('td', null, ["Cell ", counter++]),
                be('td', null, ["Cell ", counter++])
            ])
        ])
    ]);
table.appendTo(document.body);

function be(tagName, attributes, children) {
    const result = $("<" + tagName + "/>");
    if (attributes) {
        result.attr(attributes);
    }
    if (children) {
        if (Array.isArray(children)) {
            for (const child of children) {
                result.append(child);
            }
        } else {
            result.append(child);
        }
    }
    return result;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Surprisingly, it really is about that simple.

like image 122
T.J. Crowder Avatar answered Oct 21 '22 00:10

T.J. Crowder