Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website

Problem with ma-objects with the 3.2.0 mango version


  • Hi,
    I copy from the version 3.0.1 to the version 3.2.0 my dashboard to the overrides folder and I have serveral errors. The most important error is a loop in which I read json with all the datapoints that I want to show. It works with version 3.0.2.

    <div  ng-repeat="value in objects" ng-click="selectLum(value)" class="{{value.type}}">
    	 <div ng-if="'LUM' == value.type">
    		<a href="#" ng-click="show()">
    			<span  class="tooltiptext" title="{{value.name}}"> 
    				<ma-switch-img id="{{value.name}}" style="position: absolute; left: {{value.left}}; top: {{value.top}}; width: 46px; height: 35px;"  	src-0="/img/{{value.type}}_off.png" default-src="/img/{{value.type}}_on.png" point-xid="{{value.xid}}">   
    				</ma-switch-img>
    			</span>
    		</a> 
    	 </div>
    </div>
    

    The var objects is this JSON:

    {
    "xid" : "Lum_D_1",
    "name" : "LUMINARIA D_1",
    "left" : "300px",
    "top" : "310px",
    "type" : "LUM"
    },
    {
    "xid" : "Lum_D_2",
    "name" : "LUMINARIA D_2",
    "left" : "450px",
    "top" : "310px",
    "type" : "LUM"
    }
    ]
    

    When I create the ma-object (in this case 'ma-switch-img id'), it create this result after compile:

    <div ng-if="'LUM' == value.type">
    		<a href="#" ng-click="show()">
    			<span class="tooltiptext" title="LUMINARIA I_2"> 
    <ma-switch-img id="{{value.name}}" style="position: absolute; left: {{value.left}}; top: {{value.top}}; width: 46px; height: 35px;" src-0="/img/{{value.type}}_off.png" default-src="/img/{{value.type}}_on.png" point-xid="{{value.xid}}"><img ng-src="{{$ctrl.src}}"></ma-switch-img>
    			</span>
    		</a> 
    	 </div>
    

    Instead of this:

    		<a href="#" ng-click="show()">
    			<span class="tooltiptext" title="LUMINARIA I_2"> 
    				<ma-switch-img id="LUMINARIA I_2" style="position: absolute; left: 310px; top: 310px; width: 46px; height: 35px;" src-0="/img/LUM_off.png" default-src="/img/LUM_on.png" point-xid="Lum_D_1"><img ng-src="{{$ctrl.src}}"></ma-switch-img>
    			</span>
    		</a> 
    	 </div>
    

    if I print {{value.name}} then you can see the value "LUMINARIA D_1", moreover with the span label it works but not with ma-objects.

    Thank you in advance


    • Are you using the dashboards module or the UI module?
    • Are there any errors in the developer console?
    • Please post your app.js file, its possible you are not loading the correct angular module
    • ma-switch-img (display: block) should not be inside a span (display: inline)
    • ma-switch-img should not contain any other elements
    • class="{{value.type}}" should be ng-class="value.type"

  • /**
     * @copyright 2016 {@link http://infiniteautomation.com|Infinite Automation Systems, Inc.} All rights reserved.
     * @author Jared Wiltshire
     */
    
    define([
        'angular',
        './directives/menu/dashboardMenu', // load directives from the directives folder
        './directives/menu/menuLink',
        './directives/menu/menuToggle',
        './directives/login/login',
        'ngMango/ngMangoMaterial', // load ngMango angular modules
        'angular-ui-router', // load external angular modules
        'angular-loading-bar'
    ], function(angular, dashboardMenu, menuLink, menuToggle, login, ngMangoMaterial) {
    'use strict';
    
    // create an angular app with our desired dependencies
    var myAdminApp = angular.module('myAdminApp', [
        'ui.router',
        'angular-loading-bar',
        'ngMangoMaterial',
        'ngMessages'
    ]);
    	
    var $stateProviderRef = null;
    
    // add our directives to the app
    myAdminApp
        .component('dashboardMenu', dashboardMenu)
        .component('menuLink', menuLink)
        .component('menuToggle', menuToggle)
        .directive('login', login);
    
    // define our menu items, these are added to the $stateProvider in the config block below
    myAdminApp.constant('MENU_ITEMS', [
        {
            name: 'dashboard',
            templateUrl: 'views/dashboard/main.html',
            abstract: true,
            menuHidden: true,
            resolve: {
                auth: ['maTranslate', 'ADMIN_SETTINGS', function(Translate, ADMIN_SETTINGS) {
                    // thow an error if no user so the $stateChangeError listener redirects to the login page
                    if (!ADMIN_SETTINGS.user) {
                        throw 'No user';
                    }
                    // load any translation namespaces you want to use in your app up-front
                    // so they can be used by the 'tr' filter
                    return Translate.loadNamespaces(['dashboards', 'common', 'login']);
                }]
            }
        },
        {
            name: 'login',
            url: '/login',
            templateUrl: 'views/login.html',
            menuHidden: true,
            menuIcon: 'exit_to_app',
            menuTr: 'header.login',
            resolve: {
                loginTranslations: ['maTranslate', function(Translate) {
                    return Translate.loadNamespaces('login');
                }]
            }
        },
        {
            name: 'logout',
            url: '/logout',
            menuHidden: true,
            menuIcon: 'power_settings_new', // material icon name
            menuTr: 'header.logout',
            template: '<div></div>'
        },
        {
            name: 'dashboard.home',
            url: '/home',
            templateUrl: 'views/dashboard/home.html',
            menuTr: 'ui.dox.home',
            menuIcon: 'home'
        },
        {
            name: 'dashboard.apiErrors',
            url: '/api-errors',
            templateUrl: 'views/dashboard/errors.html',
            menuTr: 'ui.dox.apiErrors',
            menuIcon: 'warning',
            menuHidden: true
        },
         {
            name: 'dashboard.section1', // define some nested pages
            url: '/tuneles',
            menuText: 'tuneles',
            menuIcon: 'fa-building',
            children: [
                {
                    name: 'dashboard.section1.page1',
                    templateUrl: 'views/section1/page1.html', // html file to display
                    url: '/calahonda',
                    menuText: 'calahonda'
                },
                {
                    name: 'dashboard.section1.page2',
                    templateUrl: 'views/section1/page2.html',
                    url: '/corominas',
                    menuText: 'corominas'
                }
            ]
        },
        {
            name: 'dashboard.section2',
            url: '/section-2',
            menuText: 'Section 2',
            menuIcon: 'fa-bolt',
            children: [
                {
                    name: 'dashboard.section2.page1',
                    templateUrl: 'views/section2/page1.html',
                    url: '/page-1',
                    menuText: 'Page 1'
                },
                {
                    name: 'dashboard.section2.page2',
                    templateUrl: 'views/section2/page2.html',
                    url: '/page-2',
                    menuText: 'Page 2'
                }
            ]
        }
    ]);
    
    myAdminApp.config([
        'MENU_ITEMS',
        '$stateProvider',
        '$urlRouterProvider',
        '$httpProvider',
        '$mdThemingProvider',
        '$compileProvider',
        '$locationProvider',
        '$mdAriaProvider',
    function(MENU_ITEMS, $stateProvider, $urlRouterProvider, $httpProvider, $mdThemingProvider, $compileProvider, $locationProvider, $mdAriaProvider) {
    
        // disable angular debug info to speed up app
        $compileProvider.debugInfoEnabled(false);
        // disable aria warnings
        $mdAriaProvider.disableWarnings();
        
        // configure the angular material colors
        $mdThemingProvider
            .theme('default')
            .primaryPalette('yellow')
            .accentPalette('red');
    
        $httpProvider.useApplyAsync(true);
    
        // set the default state
        $urlRouterProvider.otherwise('/home');
        
        // enable html5 mode URLs (i.e. no /#/... urls)
        $locationProvider.html5Mode(true);
    
        // add the menu items to $stateProvider
        var nextId = 1;
        addStates(MENU_ITEMS);
    
        function addStates(menuItems, parent) {
            angular.forEach(menuItems, function(menuItem, parent) {
                menuItem.id = nextId++;
                if (menuItem.name || menuItem.state) {
                    if (menuItem.templateUrl) {
                        delete menuItem.template;
                    }
                    if (!menuItem.templateUrl && !menuItem.template) {
                        menuItem.template = '<div ui-view></div>';
                        menuItem.abstract = true;
                    }
                    
                    if (!menuItem.name) {
                        menuItem.name = menuItem.state;
                    }
                    
                    if (!menuItem.resolve && menuItem.name.indexOf('.') < 0) {
                        menuItem.resolve = {
                            loginTranslations: ['maTranslate', function(Translate) {
                                return Translate.loadNamespaces('login');
                            }]
                        };
                    }
                    
                    $stateProvider.state(menuItem);
                }
                
                addStates(menuItem.children, menuItem);
            });
        }
    	//modificado   
    	$stateProviderRef = $stateProvider;
    }]);
    
    	
    	
    myAdminApp.controller("dinamicMaswitchController", function($scope, ){
            $scope.mensaje="tunel de corominas";
            //esta variable de alcance la usamos con dynamicDir en la variable scope nombre
            $scope.tunel = $scope.global.valor;
         
            $scope.show = function(tunel){
                //alert("Hola " + tunel);
               
            }
          
            
    });
    	
     myAdminApp.directive("dinamicMaswitch", function ($http){
            return {
            restrict: 'E',
            templateUrl: 'elements.html',
            //template: "<div  ng-repeat=\"value in objects\" ng-click=\"selectLum(value)\" class=\"{{value.type}}\"  ><a href=\"#\" ng-click=\"show()\"><span  class=\"tooltiptext\" title=\"{{value.name}}\"> <ma-switch-img id=\"{{value.name}}\" style=\"position: absolute; left: {{value.lefgt}}; top: {{value.top}}; width: 46px; height: 35px;\"   src-0=\"/img/{{value.type}}_off.png\" default-src=\"/img/{{value.type}}_on.png\" point-xid=\"{{value.xid}}\">   </ma-switch-img></span></a> </div>",
            scope: {
                tunel: "@", //variables de alcance($scope) o por valor
                clickOn: "&", //útiles para llamar a funciones
                show: "&", //útiles para llamar a funciones
                link: "@"
            },
            link: function (scope)
    
                {
                 var idtunel = scope.tunel;
                 if (idtunel == '') {
                       idtunel = "calahonda";
                    } 
    
     		$http.get(idtunel+'.json').then(function success(response) {
    					 scope.objects = response.data;
    			console.log(response.data);
    				  }, function errorCallback(response) {
                          console.log(response.data);
    				  });
              //obtenemos la información del archivo data.json
    			/*	$http({
    				  method: 'GET',
    				  url: 'city.json'
    				}).then(function success(response) {
    					 scope.objects = response;
    					 //$scope.objects = response;
    					 //$scope.objects = response;
    					console.log( scope.objects);
    				  }, function errorCallback(response) {
                          console.log(response);
    				  });
                 */
                  scope.selectLum = function (value) {
                        scope.xid = value.xid;
    			  };
                 }
            };
    });
    
         myAdminApp.controller('MapCtrl3', function ($scope, $http) {
    		  var cities;
    		 		$http({
    				  method: 'GET',
    				  url: 'tunnels.json'
    				}).then(function success(response) {
    					cities = response.data;
                              console.log(response);
    				  }, function errorCallback(response) {
    					
                              console.log(response);
    			
                 var mapOptions = {
                       zoom: 10,
                      center: new google.maps.LatLng(36.523960, -4.854180),
                      mapTypeId: google.maps.MapTypeId.TERRAIN
                  }
    
                  $scope.map = new google.maps.Map(document.getElementById('map'), mapOptions);
    
                  $scope.markers = [];
                  
                  var infoWindow = new google.maps.InfoWindow();
                  
                  var createMarker = function (info){
                      
                      var marker = new google.maps.Marker({
                          map: $scope.map,
                          position: new google.maps.LatLng(info.lat, info.long),
                          title: info.city
                      });
                      marker.content = '<div class="infoWindowContent">' + info.desc + '</div>';
                      
                      google.maps.event.addListener(marker, 'click', function(){
                          infoWindow.setContent('<h2>' + marker.title + '</h2>' + marker.content);
                          infoWindow.open($scope.map, marker);
                      });
                      
                      $scope.markers.push(marker);
                      
                  }  
                  var numT;
                  for (numT = 0; numT < cities.length; numT++){
                      createMarker(cities[numT]);
                  }
    
                  $scope.openInfoWindow = function(e, selectedMarker){
                      e.preventDefault();
                      google.maps.event.trigger(selectedMarker, 'click');
                  }
    
              });
    
    
    
    myAdminApp.run([
        'MENU_ITEMS',
        '$rootScope',
        '$state',
        '$timeout',
        '$mdSidenav',
        '$mdMedia',
        '$mdColors',
        '$MD_THEME_CSS',
        'maCssInjector',
        '$mdToast',
        'maUser',
        'ADMIN_SETTINGS',
        'maTranslate',
    function(MENU_ITEMS, $rootScope, $state, $timeout, $mdSidenav, $mdMedia, $mdColors, $MD_THEME_CSS, cssInjector,
            $mdToast, User, ADMIN_SETTINGS, Translate) {
    
        // add the current user to the root scope
        $rootScope.user = ADMIN_SETTINGS.user;
        // add menu items to the root scope so we can use them in the template
        $rootScope.menuItems = MENU_ITEMS;
        // enables use of Javascript Math functions in the templates
        $rootScope.Math = Math;
        //modificado
    	$rootScope.global = {};
    
        // inserts a style tag to style <a> tags with accent color
        if ($MD_THEME_CSS) {
            var acc = $mdColors.getThemeColor('accent-500-1.0');
            var accT = $mdColors.getThemeColor('accent-500-0.2');
            var accD = $mdColors.getThemeColor('accent-700-1.0');
            var styleContent =
                'a:not(.md-button) {color: ' + acc +'; border-bottom-color: ' + accT + ';}\n' +
                'a:not(.md-button):hover, a:not(.md-button):focus {color: ' + accD + '; border-bottom-color: ' + accD + ';}\n';
            
            cssInjector.injectStyle(styleContent, null, '[md-theme-style]');
        }
    
        // redirect to login page if we can't retrieve the current user when changing state
        $rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
            if (error && (error === 'No user' || error.status === 401 || error.status === 403)) {
                event.preventDefault();
                $state.loginRedirectUrl = $state.href(toState, toParams);
                $state.go('login');
            } else {
                $state.go('dashboard.home');
            }
        });
    
        // change the bread-crumbs on the toolbar when we change state
        $rootScope.$on("$stateChangeSuccess", function(event, toState, toParams, fromState, fromParams) {
            var crumbs = [];
            var state = $state.$current;
            do {
                if (state.menuTr) {
                    crumbs.unshift({stateName: state.name, maTr: state.menuTr});
                } else if (state.menuText) {
                    crumbs.unshift({stateName: state.name, text: state.menuText});
                }
            } while ((state = state.parent));
            $rootScope.crumbs = crumbs;
        });
        
        // close the menu when we change state
        $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams) {
            if ($state.includes('dashboard') && !$rootScope.navLockedOpen) {
                $rootScope.closeMenu();
            }
            if (toState.name === 'logout') {
                event.preventDefault();
                User.logout().$promise.then(null, function() {
                    // consume error
                }).then(function() {
                    $rootScope.user = null;
                    ADMIN_SETTINGS.user = null;
                    $state.go('login');
                });
            }
        });
    
        // wait for the dashboard view to be loaded then set it to open if the
        // screen is a large one. By default the internal state of the sidenav thinks
        // it is closed even if it is locked open
        $rootScope.$on('$viewContentLoaded', function(event, view) {
            if (view === '@dashboard') {
                if ($mdMedia('gt-sm')) {
                    $rootScope.openMenu();
                }
                
                // the closeMenu() function already does this but we need this for when the ESC key is pressed
                // which just calls $mdSidenav(..).close();
                $mdSidenav('left').onClose(function () {
                    $rootScope.navLockedOpen = false;
                });
            }
        });
    
        // automatically open or close the menu when the screen size is changed
        $rootScope.$watch($mdMedia.bind($mdMedia, 'gt-sm'), function(gtSm, prev) {
            if (gtSm === prev) return; // ignore first "change"
            
            var sideNav = $mdSidenav('left');
            if (gtSm && !sideNav.isOpen()) {
                sideNav.open();
            }
            if (!gtSm && sideNav.isOpen()) {
                sideNav.close();
            }
            $rootScope.navLockedOpen = gtSm;
        });
        
        $rootScope.toggleMenu = function() {
            var sideNav = $mdSidenav('left');
            if (sideNav.isOpen()) {
                this.closeMenu();
            } else {
                this.openMenu();
            }
        };
    
        $rootScope.closeMenu = function() {
            angular.element('#menu-button').blur();
            $rootScope.navLockedOpen = false;
            $mdSidenav('left').close();
        };
    
        $rootScope.openMenu = function() {
            angular.element('#menu-button').blur();
            if ($mdMedia('gt-sm')) {
                $rootScope.navLockedOpen = true;
            }
            $mdSidenav('left').open();
        };
    
        /**
         * Watchdog timer alert and re-connect/re-login code
         */
    
        $rootScope.$on('maWatchdog', function(event, current, previous) {
            var message;
            var hideDelay = 0; // dont auto hide message
    
            if (current.status === previous.status)
                return;
            
            switch(current.status) {
            case 'API_DOWN':
                message = Translate.trSync('login.ui.app.apiDown');
                ADMIN_SETTINGS.user = null;
                break;
            case 'STARTING_UP':
                message = Translate.trSync('login.ui.app.startingUp');
                ADMIN_SETTINGS.user = null;
                break;
            case 'API_ERROR':
                message = Translate.trSync('login.ui.app.returningErrors');
                ADMIN_SETTINGS.user = null;
                break;
            case 'API_UP':
                if (previous.status && previous.status !== 'LOGGED_IN')
                    message = Translate.trSync('login.ui.app.connectivityRestored');
                hideDelay = 5000;
                ADMIN_SETTINGS.user = null;
    
                // do automatic re-login if we are not on the login page
                if (!$state.includes('login')) {
                    User.autoLogin().then(function(user) {
                        ADMIN_SETTINGS.user = user;
                        $rootScope.user = user;
                    }, function() {
                        // redirect to the login page if auto-login fails
                        window.location = $state.href('login');
                    });
                }
                break;
            case 'LOGGED_IN':
                // occurs almost simultaneously with API_UP message, only display if we didn't hit API_UP state
                if (previous.status && previous.status !== 'API_UP')
                    message = Translate.trSync('login.ui.app.connectivityRestored');
                if (!ADMIN_SETTINGS.user) {
                    // user logged in elsewhere
                    User.getCurrent().$promise.then(function(user) {
                        ADMIN_SETTINGS.user = user;
                        $rootScope.user = user;
                    });
                }
                break;
            }
            $rootScope.user = ADMIN_SETTINGS.user;
    
            if (message) {
                var toast = $mdToast.simple()
                    .textContent(message)
                    .action('OK')
                    .highlightAction(true)
                    .position('bottom center')
                    .hideDelay(hideDelay);
                $mdToast.show(toast);
            }
        });
    
    
    }]);
    
    // get an injector to retrieve the User service
    var servicesInjector = angular.injector(['ngMangoServices'], true);
    var User = servicesInjector.get('maUser');
    
    var adminSettings = {};
    
    // get the current user or do auto login
    User.getCurrent().$promise.then(null, function() {
        return User.autoLogin();
    }).then(function(user) {
        adminSettings.user = user;
    }).then(null, function() {
        // consume error
    }).then(function() {
        servicesInjector.get('$rootScope').$destroy();
        myAdminApp.constant('ADMIN_SETTINGS', adminSettings);
        
        // bootstrap the angular application
        angular.element(document).ready(function() {
            angular.bootstrap(document.documentElement, ['myAdminApp']);
        });
    });
    
    }); // define
    

  • @jared-wiltshire In the version 3.0.1 It is works but it does not work in the version 3.2.0. I imagine that the object ma-switch-img change because it does not detect the {{var}} of angular.


  • @jared-wiltshire In this new version ''ngMango/ngMangoComponents',' does not exist, like the previous version(3.0.1). Is it posible that it does not work properly?


  • @jared-wiltshire I have just installed the version 3.2.1. I copied in the folder overrides the original folder of adminTemplate an I added in the file page1.html this code from DasboarDesigner:

    <div class="ma-designer-root" id="7108c8d0-7a5e-4bdd-9178-e706da4afcb3" style="width: 1024px; height: 768px; position: relative;"><ma-switch-img id="b0526d8b-5035-4673-b6da-462953e5b2e3" style="position: absolute; left: 151px; top: 66px;" point-xid="VE_1_Izq_SC_Estado_Control" src-false="/rest/v2/file-stores/default/img/LUM_off.png" src-true="/rest/v2/file-stores/default/img/LUM_on.png"></ma-switch-img></div>
    

    And it give me this error:
    [$injector:unpr] http://errors.angularjs.org/1.6.4/$injector/unpr?p0=maUiDateBarProvider%20%3C-%20maUiDateBar%20%3C-%20maStatsDialog

    Please, could you check the adminTemplate?


  • @srubio you didn't answer this question, please let me help you by answering my questions.

    • Are there any errors in the developer console?

    Can you also please also check and tell me

    • Have you overriden loaderConfig.js?
    • Please post your index.html file (please when posting code, surround the code with 3 backticks, you can use the code button on the toolbar)

    @srubio said in Problem with ma-objects with the 3.2.0 mango version:

    In the version 3.0.1 It is works but it does not work in the version 3.2.0. I imagine that the object ma-switch-img change because it does not detect the {{var}} of angular.

    Yes, that directive most likely did change but this does not seem to be the cause of your problem. You have a created a custom app which will need to be updated as our Angular directives and services are updated. It is much easier for you if you just create custom pages within the UI module.

    @srubio said in Problem with ma-objects with the 3.2.0 mango version:

    @jared-wiltshire In this new version ''ngMango/ngMangoComponents',' does not exist, like the previous version(3.0.1). Is it posible that it does not work properly?

    That is correct ngMangoComponents has been removed, it is not needed any more.


  • @srubio Thanks for that last post. The error output let me know what was wrong, I've found the cause of the problem and will put out a UI module fix today.


  • @srubio Please update your UI module to version 3.2.2 and test. Sorry for the inconvenience.


  • @jared-wiltshire I download download the zip file of the module mangoUI 3.2.2 into the <MA_HOME>/web/modules directory, and restart Mango Automation but the dashboard designer and my adminTemplate project does not load.
    In module opcion say:
    mangoUI 3.2.2 - Module unloaded due to missing dependency.
    dashboardDesigner 3.2.0 - Module unloaded due to missing dependency.
    deviceConfig 3.2.0 - Module unloaded due to missing dependency.
    snmp 3.2.0 - Module unloaded due to missing dependency.


  • Hi susana,

    I suspect you do not have the mangoAPI module installed. Or it's not loading? Check the log output when Mango started, when its loading modules at the very beginning. Install the latest to resolve.


  • @phildunlap As you say, I needed to upgrade mangoApi from 3.2.0 to 3.2.1(because of in the free-m2m2-core-3.2.1 mangoApi is the 3.2.0 version) too and mangoUI to 3.2.2 and everything is working now. Thank you