Going from ui-template 1.0 vs 2.0 fails

I have used this flow ex. flow (ui-template) in Dashboard 1.0, but can't get it to work in 2.0

  • It loads the map, butif you refresh the page it goes black.
  • Also need to remove the "scope", but then I can't find out to format the code in template so I can use "this.send"

Any help that I can get.

I have seen the YT videos over and over to see if I have missed out something.
Need more explaning of all the new stuff in ui-template 2.0

[{"id":"fd704f60baed6544","type":"ui_template","z":"0aaef064838ae5d3","group":"7e85723e91f540b8","name":"Leaflet","order":3,"width":12,"height":7,"format":"<link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.css\"\n    integrity=\"sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=\" crossorigin=\"\" />\n<!-- Make sure you put this AFTER Leaflet's CSS -->\n<script src=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.js\"\n    integrity=\"sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=\" crossorigin=\"\"></script>\n    <style>\n        #map {\n            /*from www.java2s.com*/\n            height: 500px;\n        }\n    \n        .leaflet-grab {\n            cursor: auto;\n        }\n    \n        .leaflet-dragging .leaflet-grab {\n            cursor: move;\n        }\n    </style>\n\n<script>\n    (function() {\n        const cScope = this.scope;\n        setTimeout(function () {\n            \n        \tvar map = L.map('map').setView([48, 11], 10);\n            let marker;\n            \n        \tL.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {\n        \t\tmaxZoom: 20,\n                attribution: '© OpenStreetMap'\n        \t}).addTo(map);\n        \t\n        \tmap.on('click', function(e) {\n                cScope.send(e.latlng);\n                if (marker) {\n                    map.removeLayer(marker);\n                };\n                marker = L.marker(e.latlng).addTo(map);\n            });\n            \n            setTimeout(function () {\n                map.invalidateSize();\n            }, 100);\n        }, 300);\n    })();\n</script>\n<div id=\"map\"></div>\n<!-- <div id=\"map\" style=\"width: 100%; height: 400px;\"></div> -->","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","className":"","x":650,"y":440,"wires":[["6dcbe4e3a0dd9739"]]},{"id":"7e85723e91f540b8","type":"ui_group","name":"iFrame","tab":"7ca1e2ce075bc580","order":3,"disp":true,"width":12,"collapse":false,"className":""},{"id":"7ca1e2ce075bc580","type":"ui_tab","name":"Home","icon":"dashboard","order":3,"disabled":false,"hidden":false}]

/ Ivan

Can you share your progress with the Dashboard 2.0 equivalent so I can take a look please? The flow you've included is the Dashboard 1.0 node

I have tried this, have an console.log, that works.
But if I refresh goes blank.
Also when using this it goes from pointer to hand when hover over map.

Here is my 2.0 so far

[{"id":"2fad9a3f33204169","type":"ui-template","z":"e005ff7061ee2417","group":"c72c76e21d82b7d1","page":"","ui":"","name":"Geo","order":1,"width":0,"height":0,"head":"","format":"<template>\n    <link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.css\"\n        integrity=\"sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=\" crossorigin=\"\" />\n\n    <div id=\"map\"></div>\n    <!-- <div id=\"map\" style=\"width: 100%; height: 400px;\"></div> -->\n</template>\n\n<!-- Make sure you put this AFTER Leaflet's CSS -->\n<script src=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.js\"\n    integrity=\"sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=\" crossorigin=\"\"></script>\n   \n\n<script>\n    var map = L.map('map').setView([48, 11], 10);\n    let marker;\n\n    map.on('click', function(e) {\n    //cScope.send(e.latlng);\n    //this.send(e.latlng);\n    console.log(e.latlng);\n        if (marker) {\n            map.removeLayer(marker);\n            };\n        marker = L.marker(e.latlng).addTo(map);\n        });\n\n    L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {\n    maxZoom: 20,\n    attribution: '© OpenStreetMap'\n    }).addTo(map);\n\n        \n</script>\n<style>\n        #map {\n            /*from www.java2s.com*/\n            height: 500px;\n        }\n    \n        .leaflet-grab {\n            cursor: auto;\n        }\n    \n        .leaflet-dragging .leaflet-grab {\n            cursor: move;\n        }\n    </style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":110,"y":620,"wires":[["72d4d1e46ee3745d"]]},{"id":"c72c76e21d82b7d1","type":"ui-group","name":"My Group","page":"9d4bc1caffe751ab","width":"12","height":"10","order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"9d4bc1caffe751ab","type":"ui-page","name":"My Geo","ui":"a171c8195c1b8e57","path":"/ui-button-example","icon":"button-pointer","layout":"grid","theme":"9d8bfd7e0d216779","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"","visible":"true","disabled":"false"},{"id":"a171c8195c1b8e57","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-control","ui-gauge","ui-chart","ui-form","ui-text-input","ui-file-input","ui-button","ui-button-group","ui-dropdown","ui-radio-group","ui-slider","ui-switch","ui-text","ui-table","ui-markdown","ui-notification","ui-template"],"showPathInSidebar":false,"showPageTitle":true,"navigationStyle":"icon","titleBarStyle":"default","showReconnectNotification":false,"notificationDisplayTime":5,"showDisconnectNotification":false},{"id":"9d8bfd7e0d216779","type":"ui-theme","name":"Default Theme","colors":{"surface":"#ffffff","primary":"#15617e","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]

I believe the problem is that you are trying to execute code before the leaflet.js script has loaded.
There is an example in the Dashboard ui_template docs about Loading External Dependencies that uses a timer to wait for the script to load.

Adapted code :

<template>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
        integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />

    <div id="map"></div>
    <!-- <div id="map" style="width: 100%; height: 400px;"></div> -->
</template>

<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
    integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
   

<script>
    function init () {
        var map = L.map('map').setView([48, 11], 10);
        let marker;
    
        map.on('click', function(e) {
            //cScope.send(e.latlng);
            //this.send(e.latlng);
            console.log(e.latlng);
            if (marker) {
            map.removeLayer(marker);
            };
            marker = L.marker(e.latlng).addTo(map);
        });
        
        L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
            maxZoom: 20,
            attribution: '© OpenStreetMap'
        }).addTo(map);
    }

    // run this code when the widget is built
    let interval = setInterval(() => {
        if (window.L) {
            // call an init() to use leaflet
            init();
            // leaflet.js is loaded, so we can now use it
            clearInterval(interval);
        }
    }, 100);


</script>
<style>
    #map {
    /*from www.java2s.com*/
    height: 500px;
    }
    
    .leaflet-grab {
    cursor: auto;
    }
    
    .leaflet-dragging .leaflet-grab {
    cursor: move;
    }
</style>

@UnborN
Great showing how that was solved, now I just need to get the feedback to show up in NR.
map.on('click........
I have console.log and it returns fine, but this.send(e.latlng); gives an error in console "Uncaught TypeError: this.send is not a function" and stops.

I'm sure it needs to be configured in another way.
Really need to learn some more stuff.

I dont know how to explain it very well but .. when you call this inside a function .. as we did ...
this is not anymore the original this .. you can read more about it here (link)

So to solve it you can assign this (that has the send function attached to it) to another variable
let cScope = this; at the beginning of you script or maybe use arrow functions everywhere.

Example of 1st method

<script>

    let cScope = this;

    function init () {
        var map = L.map('map').setView([48, 11], 10);
        let marker;
    
        map.on('click', function(e) {
            //cScope.send(e.latlng);
            cScope.send({payload : e.latlng});
            console.log(e.latlng);
            if (marker) {
            map.removeLayer(marker);
            };
            marker = L.marker(e.latlng).addTo(map);
        });
        
        L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
            maxZoom: 20,
            attribution: '© OpenStreetMap'
        }).addTo(map);
    }

    // run this code when the widget is built
    let interval = setInterval(() => {
        if (window.L) {
            // call an init() to use leaflet
            init();
            // leaflet.js is loaded, so we can now use it
            clearInterval(interval);
        }
    }, 100);


</script>
1 Like

This is just what I needed, you saved my day..
And learned something new

1 Like

Arrow functions are generally better.

1 Like

This is something I don't know what means :thinking:, maybe when I see it.
Could you explain?

here is the code example using Arrow Functions

<script>

    let init = () => {
        var map = L.map('map').setView([48, 11], 10);
        let marker;
    
        map.on('click', (e) => {
            this.send({payload : e.latlng});
            if (marker) {
            map.removeLayer(marker);
            };
            marker = L.marker(e.latlng).addTo(map);
        });
        
        L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
            maxZoom: 20,
            attribution: '© OpenStreetMap'
        }).addTo(map);
    }

    // run this code when the widget is built
    let interval = setInterval(() => {
        if (window.L) {
            // call an init() to use leaflet
            init();
            // leaflet.js is loaded, so we can now use it
            clearInterval(interval);
        }
    }, 100);


</script>

Both init and the map.on callback are defined with arrow function syntax.
This way you can use this.send inside of it because this is unaffected since arrow functions dont create a new this binding.

Here you go.

Though UnborN has already provided a brief explanation.

It took me a while to get my head around them to be honest.

The most important aspect is that arrow fns do not create a new this context. They inherit the outer context.

The other thing to remember is that they are "anonymous" functions by default - they don't have a name. This actually makes them good for callbacks like you are seeing in the above examples. If you need to give them a name, you can do like this:

const bob2 = (bob) => bob * 2;

You can also see from the above that they can be a lot more terse than standard functions, this example does not have an explicit return statement for example but it absolutely does return a value. That only works for single statement functions though.