Ui-template set httpstatic for dashboard 2

Hi all, I'm trying using dashboard2 and I would understand where locate the external javascript scripts

for dashboard 1 I set httpstatic path in the setting file adding the folder where my script are located in "/static/" and I call them from ui with the following line

{path: '/home/pi/.node-red/html/', root: "/static/"},

the same not works in the dashboard2 where the page is "https://myip:1880/dashboard/page"

can someone help me?
many thanks

lets say you have an image.jpg in your static folder
you place the image in /home/pi/.node-red/html/ and
it should be served at https://localhost:1880/static/image.jpg
If you visit the link directly can you see the asset / script ?

when it comes to loading the asset from dashboard .. since the dashboard is served from /dashboard
im guessing you should go one level back ../ in order to access /static ?

example : <script src="../static/myScript.js"></script>

many thanks for your help

if i do

<img src="../static/img.jpeg" alt="test">

it works correctly but if I do

<script type="text/javascript" src="../static/js/jsqrscanner.nocache.js"></script>

it not works
while in dashboard ver 1 if I do

<script type="text/javascript" src="/static/js/jsqrscanner.nocache.js"></script>

it works

  1. Do you have any errors in the browser console logs ?
  2. It could be the case that the script doesnt load in time before the Dashboard 2 ui-template component runs its code. If thats the case see this post how a timer can be used to wait for the script to load (link)

many thanks for your help
no error appears in web page console

if I try adding

export default {
       mounted() {
            let interval = setInterval(() => {
                if (window.jsqrscanner) {
                    clearInterval(interval);
                    // now it is loaded, we can initialise and use it
                }
            }, 100);
        }
   }

in the web console appears

index-CkQi99U4.js:236 errorCaptured SyntaxError: Unexpected token 'export'
    at Proxy.created (index-CkQi99U4.js:236:6486)
    at callWithErrorHandling (index-CkQi99U4.js:22:2165)
    at callWithAsyncErrorHandling (index-CkQi99U4.js:22:2273)
    at callWithAsyncErrorHandling (index-CkQi99U4.js:22:2412)
    at callHook$1 (index-CkQi99U4.js:22:35193)
    at applyOptions (index-CkQi99U4.js:22:34256)
    at finishComponentSetup (index-CkQi99U4.js:22:72406)
    at setupStatefulComponent (index-CkQi99U4.js:22:71538)
    at setupComponent (index-CkQi99U4.js:22:70927)
    at H (index-CkQi99U4.js:22:53467) Proxy(Object) {_: {…}, $socket: Socket, send: ƒ, submit: ƒ, …} https://vuejs.org/error-reference/#runtime-c

is your javascript enclosed between <script> tags ?

Dashboard 2 has some changes from 1 .. it now uses Vue Components so you need to adapt your old code.
You can read more about them here

yes I put the code in script tag as follow


<script src="../static/js/jsqrscanner.nocache.js"></script>
<script type="text/javascript">
    export default {
        mounted() {
            let interval = setInterval(() => {
                if (window.jsqrscanner) {
                    clearInterval(interval);
                    console.log("init")
                }
            }, 100);
        }
    }
    function onQRCodeScanned(scannedText)
    {   
        var scannedTextMemo = document.getElementById("scannedTextMemo");
        if(scannedTextMemo)
        {    
            scannedTextMemo.value = scannedText;
            console.log({payload: scannedText});
        }
    }

    function provideVideo()
    {
        var n = navigator;
        if (n.mediaDevices && n.mediaDevices.getUserMedia)
        {
        return n.mediaDevices.getUserMedia({
            video: {
            facingMode: "environment"
            },
            audio: false
        });
        }    
        return Promise.reject('Your browser does not support getUserMedia');
    }

    function provideVideoQQ()
    {
        return navigator.mediaDevices.enumerateDevices()
        .then(function(devices) {
            console.log(devices);
            var exCameras = [];
            devices.forEach(function(device) {
                if (device.kind === 'videoinput') {
                    console.log(device.deviceId)
                    exCameras.push(device.deviceId)
            }
        });  
            return Promise.resolve(exCameras);
        }).then(function(ids){
            if(ids.length === 0)
            {
                console.log("error find camera")
                return Promise.reject('Could not find a webcam');
            }
            
            return navigator.mediaDevices.getUserMedia({
                video: {
                'optional': [{
                    'sourceId': ids.length === 1 ? ids[0] : ids[1]//this way QQ browser opens the rear camera
                    }]
                }
            });        
        });                
    }

    function JsQRScannerReady()
    { 
        var jbScanner = new JsQRScanner(onQRCodeScanned);
        jbScanner.setSnapImageMaxSize(300);
        var scannerParentElement = document.getElementById("scanner");
        if(scannerParentElement)
        {
            jbScanner.appendTo(scannerParentElement);
        }        
    }

</script>

Try this code .. its partly based on the section of the D2 docs for Loading External Dependencies

<template>
  <div>
    <div class="qrscanner" id="scanner">
      <div><video class="qrPreviewVideo" autoplay="" src=""></video></div>
    </div>
    <textarea id="scannedTextMemo" class="textInput form-memo form-field-input textInput-readonly" rows="3" readonly=""></textarea>
  </div>
</template>
<script src="../static/js/jsqrscanner.nocache.js"></script>
<script>
  let interval = setInterval(() => {
    if (window.JsQRScanner) {
      clearInterval(interval);
      console.log("init");
      init();
    }
  }, 100);

  // init - jsqrscanner loaded
  function init() {

    function onQRCodeScanned(scannedText) {
      var scannedTextMemo = document.getElementById("scannedTextMemo");
      if (scannedTextMemo) {
        scannedTextMemo.value = scannedText;
        console.log({ payload: scannedText });
      }
    }

    function provideVideo() {
      var n = navigator;
      if (n.mediaDevices && n.mediaDevices.getUserMedia) {
        return n.mediaDevices.getUserMedia({
          video: {
            facingMode: "environment",
          },
          audio: false,
        });
      }
      return Promise.reject("Your browser does not support getUserMedia");
    }

    function provideVideoQQ() {
      return navigator.mediaDevices
        .enumerateDevices()
        .then(function (devices) {
          console.log(devices);
          var exCameras = [];
          devices.forEach(function (device) {
            if (device.kind === "videoinput") {
              console.log(device.deviceId);
              exCameras.push(device.deviceId);
            }
          });
          return Promise.resolve(exCameras);
        })
        .then(function (ids) {
          if (ids.length === 0) {
            console.log("error find camera");
            return Promise.reject("Could not find a webcam");
          }

          return navigator.mediaDevices.getUserMedia({
            video: {
              optional: [
                {
                  sourceId: ids.length === 1 ? ids[0] : ids[1], //this way QQ browser opens the rear camera
                },
              ],
            },
          });
        });
    }

    function JsQRScannerReady() {
      var jbScanner = new JsQRScanner(onQRCodeScanned);
      jbScanner.setSnapImageMaxSize(300);
      var scannerParentElement = document.getElementById("scanner");
      if (scannerParentElement) {
        jbScanner.appendTo(scannerParentElement);
      }
    }
  }
</script>