Solve problems when use a file storage in more than one widget in the same dashboard

Hello,

I am trying to use one Widget in a dashboard with an HTML storage, which includes two files: an html and an angularJS.

I want to use that code in two different widgets (for two different devices) which are positioned in the same dashboard and in the same tab. One widget is for one device for tennis court 1, and the other widget is for another device for tennis court 2 (I just change these values for both widgets):

And both widgtes have the same file storage:

image

Here is when I have problems and it does not work well. Do you know if is possible to do that? How could I solve that?

Thank you so much!

Hi @EBA

What issues are you encountering?

It is possible to use the same widget files for two different widgets in the same dashboard without their values colliding.

However, depending on how it’s codified or if the HTML elements of the widgets have id properties, when duplicating the widgets this elements are loaded twice in the DOM, which must be unique, so you will encounter issues with things like getElementById or using id selectors in CSS. You may also encounter similar issues with class properties, depending on how it is used.

Hello @jaimebs !

Thank you for your answer!

My widget is like an interactive map. It has 3 images svg, and depending on a value of the property of the device it shows one or another svg, as well as it shows one container information or another (wich show some properties of the device) depending of which div the user click, etc.

So, you are right, I am using ID in HTML file and “getElementById” in the angularJS file.

Is there another way for solving it?

(maybe something that affects just to the widget. For example, I have tried to use the angular function “link”, so that each widget instance has its own independent $scope. But I do not have solved my problem yet).

Or should I do one file storage for every widget and change their IDs? ( Or another solution :slight_smile: )

Thank you far all! :slight_smile:

The best way would be to use angular.js directives. You can create the popup in the html part of the component and avoid creating any html element dynamically.

For example, I have created this simple widget with a button that will open a popup at the center of the window with the value of the device configured in the widget.

popupWidget.html:

<style>
    .popup-container {
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        padding: 20px;
        background-color: #fff;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        z-index: 1000;
    }

    .popup-container h2 {
        margin-top: 0;
    }

    .close-btn {
        cursor: pointer;
        color: #333;
        font-weight: bold;
        float: right;
    }
</style>

<div>
    <h3>Hello World from AngularJS directive!</h3>
    <button ng-click="openPopup()">Open Popup</button>
    
    <div class="popup-container" ng-show="isPopupVisible">
        <span class="close-btn" ng-click="closePopup()">&times;</span>
        <h2>AngularJS Popup</h2>
        <p>Value: {{value}}</p>
    </div>
</div>

popupWidget.js:

angular.module('popupWidget', [])
.directive('popupWidget', function () {
    return {
        restrict: 'EA',
        scope: {
            source : "=",
            ts:      "=",
            value:   "="
        },
        templateUrl: function(){
            let url = document.querySelector("script[src*='popupWidget.js']");
            return url.src.replace('.js','.html');
        },
        controller: ["$scope", function($scope){
            
            $scope.isPopupVisible = false;

            $scope.openPopup = function () {
                $scope.isPopupVisible = true;
            };

            $scope.closePopup = function () {
                $scope.isPopupVisible = false;
            };
            
        }]
    }
});

The code is pretty simple and often times more straightforward than using vanilla JS. As you can see, in the html we are creating the popup container with a ng-show directive based on the boolean value of $scope.isPopupVisible initialized in the controller. And the content of the popup is just {{value}}, which will make reference to the value passed to that widget.

When the button is clicked, using the ng-click directive we call the openPopup function which changes the value of isPopupVisible and displaying the popup as a result.

Thank you so much @jaimebs ! :slight_smile:
I have tried it and it works.

Now, I just have one problem. I have in the HTML three images in <svg>. Depending on a property device, It will show one or another <svg>.

It works well with two widgets, with different related devices and the same file storage: it shows the correct <svg> depending on this property device. The problem is that we loose the links funcionalities <a> which are into the <svg>.

It does not happend if we have just one widget (for one widget it works well: it shows the correct svg and all <a> functionalities into <svg> work). I have tried to do the same thing with <svg> by ng-show, but it does not work.

For solving these problems functionalities with <a> into <svg> I have tried to do the next items:

  1. Pointer-events,
  2. <a xlink:href="…,
  3. attribute style: {‘pointer-events’: ‘none’},
  4. by CSS with class ‘invisibleContainerWidgetImgCourtTenis’
  5. "style$scope.svgImg[idSvg] = { isVisible: false, class: ‘invisibleContainerWidgetImgCourtTenis’, style: {‘pointer-events’: ‘none’} };

When I create the object and I put into it if isVisible, the class or the style, it works well: both widgets have the correct class, isVisible, etc (both objects are created and filled well). But do not work the <a> into <svg>. Just work the <a> into <svg> in one of the widgets.

Thank you so much! :slight_smile:

Hello @EBA,

Not really sure what is causing this problem, but here are a couple of things to look at:

  • To retain interactivity inside the svg, use <object> or <iframe> tags.
  • Use ng-if instead of ng-show. The expression in ng-if would allow to just show one of the svg files, depending on the value of the property.

Lets see if by following this you are able to reach the desired functionality