Skip to content

Pure JS modern version of this library #29

Description

@sgd2z

When I installed this, it added React 16 to my dependency list. So I decided to rewrite it in JS. No building, no dependencies other than the CSS file in the project:

import "./JsonToTable.css";

const toTitleCase = (str) => {
    return str.split(' ')
        .map(w => `${w[0]?.toUpperCase() || ''}${w.substring(1)?.toLowerCase() || ''}`)
        .join(' ');
}

const JSONObjectType = {
    Array: 'Array',
    ObjectWithNonNumericKeys: 'ObjectWithNonNumericKeys',
    Object: 'Object',
    Primitive: 'Primitive'
}

const JSONToTableUtils = {
    /**
     * Get object type
     */
    getObjectType: (obj) => {
        if (obj !== null && typeof obj === "object") {
            if (Array.isArray(obj)) {
                return JSONObjectType.Array;
            } else {
                if (Object.keys(obj).length) {
                    return JSONObjectType.ObjectWithNonNumericKeys;
                } else {
                    return JSONObjectType.Object;
                }
            }
        } else {
            return JSONObjectType.Primitive;
        }
    },

    checkLabelTypes: (labels) => {
        const reduced = labels.reduce(
            (accumulator, value) =>
                accumulator + (isNaN(Number(value)) ? value : Number(value)),
            0
        );
        return typeof reduced === "number" ? "number" : "string";
    },

    getUniqueObjectKeys: (anArray) => {
        let labels = [];
        const objectType = JSONObjectType.Object;
        anArray.forEach(item => {
            labels = labels.concat(Object.keys(item)).filter((elem, pos, arr) => {
                return arr.indexOf(elem) === pos;
            });
        });

        return { labels, type: objectType };
    }
}

export const JsonToTable = ({ jsonData }) => {
    const renderRowHeader = (label) => {
        return (
            <div key={`__j2t_rw${label}`}>
                <strong>{toTitleCase(label)}</strong>
            </div>
        );
    };

    const renderRows = (obj) => {
        return Object.keys(obj).map((k, idx) => {
            const value = obj[k];
            const isValuePrimitive =
                JSONToTableUtils.getObjectType(value) === JSONObjectType.Primitive;
            // render row when value is primitive otherwise inspect the value and make the key as header
            const retval = isValuePrimitive
                ? renderRow(k, value, idx)
                : renderObject(value, k, idx);

            return retval;
        });
    };

    const parseArray = (anArray) => {
        const phrase = [];
        const labels = JSONToTableUtils.getUniqueObjectKeys(
            anArray
        );
        if (JSONToTableUtils.checkLabelTypes(labels.labels) !== "number") {
            phrase.push(renderHeader(labels.labels));
            phrase.push(renderRowValues(anArray, labels.labels));
        } else {
            phrase.push(renderValues(anArray));
        }
        return phrase;
    };

    const renderObject = (obj, header, idx) => {
        const phrase = [];
        let tmp;
        if (header) {
            phrase.push(renderRowHeader(header));
        }

        const objType = JSONToTableUtils.getObjectType(obj);

        switch (objType) {
            case JSONObjectType.ObjectWithNonNumericKeys:
                tmp = header ? (
                    <table key={`__j2t_tableObj${idx}`}>
                        <tbody
                            key={`__j2t_bObj${idx}`}
                        >
                            {renderRows(obj)}
                        </tbody>
                    </table>
                ) : (
                    renderRows(obj)
                );
                break;
            case JSONObjectType.Array:
                tmp = header ? (
                    <table key={`__j2t_tableArr${idx}`}>
                        <tbody key={`__j2t_bArr${idx}`}>
                            {parseArray(obj)}
                        </tbody>
                    </table>
                ) : (
                    parseArray(obj)
                );
                break;
        }
        phrase.push(tmp);
        const retval = phrase.map(p => p);
        return header ? (
            <tr key={`__j2t_trObj${idx}`}>{renderCell({ content: retval, colspan: 2 })}</tr>
        ) : (
            retval
        );
    };

    const getCellValue = (content) => {
        const valueDisplay = content === true || content === false ? content.toString() : content;
        return valueDisplay;
    };

    const renderCell = ({
        content,
        colspan,
        isHeader
    }) => {
        const valueDisplay = isHeader ? <strong>{getCellValue(toTitleCase(content))}</strong> : getCellValue(content);
        return <td colSpan={colspan ? colspan : 0} key={`__j2t_trObj${valueDisplay}`}>{valueDisplay}</td>;
    };

    const renderHeader = (labels) => {
        return (
            <tr key={`__j2t_trHeader`}>
                {labels.map((v) => {
                    return renderCell({ content: v, isHeader: true });
                })}
            </tr>
        );
    };

    const renderValues = (values) => {
        return (
            <tr key={`__j2t_trArrString`}>
                {values.map(k => {
                    return renderCell({ content: k });
                })}
            </tr>
        );
    };

    const renderRowValues = (anArray, labels) => {
        return anArray.map((item, idx) => {
            return (
                <tr key={`__j2t_Arr${idx.toString()}`}>
                    {labels.map(k => {
                        const isValuePrimitive =
                            JSONToTableUtils.getObjectType(item[k]) === JSONObjectType.Primitive;
                        return isValuePrimitive
                            ? renderCell({ content: item[k] })
                            : renderObject(item[k], k, idx);
                    })}
                </tr>
            );
        });
    };

    const renderRow = (k, v, idx) => {
        return (
            <tr key={`__j2t_tr${idx}`}>
                <td key={`__j2t_tdk${idx}`}>
                    <strong>{k}</strong>
                </td>
                <td key={`__j2t_tdv${idx}`}>{v}</td>
            </tr>
        );
    };

    return (
        <div className={'json-to-table'}>
            <table key={`__j2t_root_table`}>
                <tbody key={`__j2t_root_tbody`}>{renderObject(jsonData, undefined, 0)}</tbody>
            </table>
        </div>
    );
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions