Pivottable implementation in Node-RED-Dashboard

Hello people,

I'm currently trying to implement a pivot table into my Node-RED-Dashboard. I searched for some examples and found this one. I want to import a CSV so the user can edit the table and export it in the end.

I've wrote everything inside the dashboard-template-node:

<script src="/jquery/dist/jquery.min.js"></script>
<script src="/jquery-ui/dist/jquery-ui.min.js"></script>
<script src="/pivottable/dist/pivot.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>

<link rel="stylesheet" href="/pivottable/dist/pivot.css"/>
<div id="pivot"></div>

<script>
    table = d3.csvParseRows(
        await FileAttachment('/tmp/Messungen.csv').text(),
        d3.autoType
    );
    

    displayTable = function(sample) {
        console.log(sample);
        const { title, ui, data, params } = sample;
        const app = document.getElementById('pivot');
        app.innerHTML = '';

        const e1 = document.createElement('div');
        e1.setAttribute('id', 'pivot');
        app.appendChild(e1);

        const e2 = document.createElement('div');
        e2.innerHTML = `<i>${title}</i>`;
        app.appendChild(e2);

        if(ui) window.$('#pivot').pivotUI(data, params);
        else window.$('#pivot').pivot(data, params);

        return true;
    }    

    csv = {
        const sortAs = util.sortAs;

        return {
            title: 'Messwerte',
            ui: true,
            data: table,
            params: {
                derivedAttributes: {
                    "Register",
                    "Zeitstempel"
                },
                rows: ["Zeitstempel"],
                cols: ["Register"],
                renderers: window.$.extend(util.renderers, util.export_renderers),
                rendererName: "Heatmap",
                rendererOptions: {
                    heatmap: {
                        colorScaleGenerator: function(values) {
                            return d3
                                .scaleLinear()
                                .domain([-35, 0, 35])
                                .range(["#77F", "#FFF", "#F77"]);
                        }
                    }
                }
            }
        };
    }

    util = {
        console.log(deps);
        return window.$.pivotUtilities;
    }

    deps = {
        const $ = await require("/node-red-static/jquery/dist/jquery.min.js");
        const jqui = await require("/node-red-static/jquery-ui/dist/jquery-ui.min.js");
        const pt = await require("/node-red-static/pivottable/dist/pivot.js");
        return { $, jqui, pt };
    }

    displayTable(csv);

</script>

But nothing is getting displayed. Please help.

Thanks in advice

Justin

Have you verified that these are actually loading?

@TotallyInformation What do you mean? I've loaded the libraries into my static folder.

I'm getting an error which I dont understand:

image

Because for me it makes no sence to set another ) right there:

image

@TotallyInformation Okay, I've fixed the error by adding some brackets:
table = d3.csvParseRows(await(FileAttachment('/tmp/Messungen.csv').text()), d3.autoType);

But now I'm getting Uncaught SyntaxError: Unexpected identifier '$':

image

You can only use require with node.is or using a build step to translate to something the browser understands.

Also, not sure whether it still does but Dashboard used to already load jQuery.

I've also tried to require it inside the settings.js and do a global.get(jquery) inside the template-node.

I also tried it with commenting deps out but always throws the error.

Hi Justin, I think you need to take a step back and understand a bit more about how Dashboard and Node-RED work togeter. You seem to be conflating the front-end (browser) and back-end (node-red server).

Anything in a ui_template is run at the front-end in the browser under the AngularJS v1 framework. Dashboard lets you send data to/from the front-end but code is provided to the front-end by dashboard nodes including the ui_template node.

A require function is not valid front-end javascript and so will never work. You can, however load scripts via a ui_template node simply by adding a script tag. Or you can set the ui_template to load to the head section and include scripts, css links, etc:

As I did right here?

I found this post but the example isnt available anymore..

The other link shows how validation works and as I can see he is using jquery right there.

I dont exactly understand how this is done.

So now open your browser's dev tools when viewing the dashboard.

First look at the network tab and make sure all of those libraries were successfully loaded (status of 304 or 200).

Then check the dev tools console tab to look for errors.

@TotallyInformation Everything is loading, seems good so far:

Console show one error:

The code:

Without seeing the full context of that code, I can't tell why it is complaining. My guess would be that line 67 is not in the context you think it is and so for some reason does not have access to the window object that should generally be always available in client code.

You shouldn't really need window.$ anyway, $ should already be in the global scope (which IS window for browser code).

Here is what I've just put in a ui_template node. Note that I have NOT added a script link to jQuery, it isn't needed as it is already loaded and active in one of the Dashboard bundles as I intimated previously:

<script>
    console.log('window',window)
    console.log('$',$)
</script>

With the browser console output of:

jQuery UI is not loaded however. Changing the template code to the following loaded it successfully:

<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
<script>
    console.log('window',window)
    console.log('$',$)
</script>

And this ui_template code worked just fine:

<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/pivottable/2.23.0/pivot.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pivottable/2.23.0/pivot.min.js"></script>
<div id="output" style="margin: 30px;"></div>
<script>
    console.log('window',window)
    console.log('$',$)

    $(function(){
        $("#output").pivot(
            [
                {color: "blue", shape: "circle"},
                {color: "red", shape: "triangle"}
            ],
            {
                rows: ["color"],
                cols: ["shape"]
            }
        );
    });
</script>
1 Like

Why are you doing it in the browser rather than in node red itself?

What do you mean?

@TotallyInformation Thank you! Going to try it out.

To everybody who is interested.

I finally got it to work. Now the user is able to import a CSV and create new tables or charts.

How it looks like:

And the working code:

<script src="/jquery-ui/dist/jquery-ui.min.js"></script>
<script src="/pivottable/dist/pivot.min.js"></script>
<script src="/papaparse/papaparse.min.js"></script>
<script src="https://cdn.plot.ly/plotly-basic-latest.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script>
<script src="/plotly.js-dist/plotly.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script type="text/javascript" src="/pivottable/dist/d3_renderers.js"></script>
<script type="text/javascript" src="/pivottable/dist/plotly_renderers.js"></script>
<script type="text/javascript" src="/pivottable/dist/export_renderers.js"></script>
<style id="plotly.js-style-global"></style>
<link rel="stylesheet" href="/pivottable/dist/pivot.css" />

<script>
$(function(){
    var renderers = $.extend(
        $.pivotUtilities.renderers,
        $.pivotUtilities.plotly_renderers,
        $.pivotUtilities.d3_renderers,
        $.pivotUtilities.export_renderers
    );

    var parseAndPivot = function(f) {
        $("#output").html("<p align='center' style='color:grey;'>(processing...)</p>")
        Papa.parse(f, {
            skipEmptyLines: true,
            error: function(e){ alert(e) },
            complete: function(parsed){
                $("#output").pivotUI(parsed.data, { renderers: renderers }, true);
            }
        });
    };

    $("#csv").bind("change", function(event){
        parseAndPivot(event.target.files[0]);
    });

    $("#textarea").bind("input change", function(){
        parseAndPivot($("#textarea").val());
    });

    var dragging = function(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        evt.originalEvent.dataTransfer.dropEffect = 'copy';
        $("body").removeClass("whiteborder").addClass("greyborder");
    };

    var endDrag = function(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        evt.originalEvent.dataTransfer.dropEffect = 'copy';
        $("body").removeClass("greyborder").addClass("whiteborder");
    };

    var dropped = function(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        $("body").removeClass("greyborder").addClass("whiteborder");
        parseAndPivot(evt.originalEvent.dataTransfer.files[0]);
    };

    $("html")
    .on("dragover", dragging)
    .on("dragend", endDrag)
    .on("dragexit", endDrag)
    .on("dragleave", endDrag)
    .on("drop", dropped);
});
</script>
<p align="center" style="line-height: 1.5">
     Ziehe eine CSV-Datei in dieses Fenster,  
    <label id="filechooser">
        <b>klicke hier um eine auszuwählen</b>
        <input id="csv" type="file" style="display:none">
    </label>
    <br>
    <br>
    <textarea placeholder="oder fĂĽge hier CSV ein" style="width: 300px;" id="textarea"></textarea>
</p>
<div id="output" style="margin: 10px;"></div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.