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

Advice on moving components / controllers / services out of userModule


  • To make the userModule slimmer, would like to move components, controllers etc out into their own .js files / modules in a directory structure (in public, probably). Is there a recommended module / require syntax for doing so?


  • Of course!

    Have userModule.js in your base directory under /overrides/web/modules/mangoUI/web/userModule.js
    I like to then have directories set up into views/components/directives/services etc in the same place the userModule file is stored.

    Just ensure you have

    define(['angular','require'],function(angular,require)
    {
    
    ///code in here
    //thrn:
    
    return {
            bindings: {
    			xid: '<',
    			username:'<'
            },
            scope: {},
            templateUrl: "/modules/mangoUI/web/views/myComponenty.html",
            // you can inject services into the controller
            controller:('componentController',componentController)
    	};
    });
    

    for each file excluding views of course...

    In the user module simply add them in as part of the definitions for the usermodule to add as components... etc.

    define(['angular', 'require','./components/myComponent.js'],function(angular,require,myComponent)
    {
    var userModule = angular.module('userModule', ['maUiApp']);
    
    try 
    {
    //add to custom modules..
    	userModule.component('myComponent', myComponent);
    }catch(e){console.log(e);}
    });
    

  • thanks, @MattFox - I'll give it a go.


  • Hi @MattFox; apparently need a little Mango 101 here. My userModule works fine in the public folder - but isn't even found (no error) in /overrides/web/modules/mangoUI/web. Do I need to add a base path somewhere to tell the app to look somewhere other than public? Couldn't find any mention of such...

    also assume views/components/controllers, etc. directories would be siblings to userModule.js in the last child .../web folder?

    thanks for the amateur questions...


  • No such thing as a stupid question if you learn something from it!

    This is a forum post I helped with a while ago. Sorry I should have been more explicit with my answer before

    https://forum.infiniteautomation.com/topic/3720/pop-up-window-face-plate/18

    It explains the directory structure I like to use and why.

    @bobday said in Advice on moving components / controllers / services out of userModule:

    also assume views/components/controllers, etc. directories would be siblings to userModule.js in the last child .../web folder

    Correct!


  • Thanks. still missing something...

    My userModule.js file is located at:
    '.../modules/mangoUI/web/dev/userModule.js,
    my userModule URL (in UI settings) changed to:
    /modules/mangoUI/web/dev/userModule.js, (from /rest/v2/file-stores/public...)
    and templateUrl at:
    templateUrl: '/modules/mangoUI/web/dev/views/push.html'

    How do I inform my app what my "base directory" is?


  • If you've stored your userModule.js in /opt/mango/overrides/web/modules/mangoUI/web
    your usermodule under UI Settings will be

    modules/mangoUI/web/userModule.js
    

    base directory is stated in the app.js and /ui/index.html for mango which is compressed into the webpack that Jared compiled.

    Can you show me what you have now and I can likely assist with helping you getting one component working.

    Fox


  • sure...
    with my userModule.js stored at opt/Mango36/filestore/public/userModule.js, and its UI location set at /rest/v2/file-stores/public/userModule.js,
    all works well.

    when stored at /opt/mango/overrides/web/modules/mangoUI/web/dev/userModule.js,

    and UI location set at /modules/mangoUI/web/dev/userModule.js,

    the component is not found.

    js:

    define(['angular', 'require'], function (angular, require) {
    
      pushCtrl.$inject = ['$scope','$timeout'];
    
      function pushCtrl($scope,$timeout) {
        const $ctrl = this;
        $ctrl.$onChanges = function (changes) {
          if (changes.points && Array.isArray($ctrl.points)) {
    
            $ctrl.point = $ctrl.points.find(p => p.xid === 'DP_ind_' + $ctrl.target);
            $ctrl.switchPoint = $ctrl.points.find(p => p.xid === 'DP_sw_' + $ctrl.target);
    
            $ctrl.ptCSS = { // point css values for color and blink; ex, ng-class=""
              get color(){
                if ($ctrl.point.color < 10) {
                  return 0;
                }
                return Math.floor($ctrl.point.value / 10)},
              get blink(){return 'blink' + $ctrl.point.value % 10},
              get colStyle(){return 'color'+this.color}
            };
    
            $timeout(function() {
              console.log('color:', $ctrl.ptCSS.colStyle, 'blink:', $ctrl.ptCSS.blink );
            },1000);
          }
        };
    
        $ctrl.pushed = function() {
          console.log($ctrl.switchPoint.value);
            if ($ctrl.switchPoint) {
                $ctrl.switchPoint.toggleValue();
              console.log('switch ' + $ctrl.target + ' was switched.' );
           }
        };
      }
      const template = '<div class="inner-circle" ng-class="[$ctrl.ptCSS.colStyle, $ctrl.ptCSS.blink]" ng-click="$ctrl.pushed()"><span class="buttonText" ng-bind-html="$ctrl.point.tags.indText | unsafe"></span> </div>'; // using $sce here to get pass <br>'s in text; flex-wrap also on
    // (used single quotes instead of backticks for post...)
    
    
      var userModule = angular.module('userModule', ['maUiApp'])
    
        .filter('unsafe', ['$sce', function($sce) {
          return $sce.trustAsHtml;
        }])
    
        .component('pushLamp', {
          template: template,
          bindings: {
            points: '<',
            target: '@'
          },
          controller: pushCtrl
        });
        return userModule;
    
    }); //define
    

    html:

    <style>
    html {
        font-size: 16px;
    }
    @keyframes blink {
        80% {
            background-color: #000;
            color: #000;
            text-shadow: none;
        }
    
        100% {
            background-color: #000;
            color: #000;
            text-shadow: none;
            /*border: 5px solid #6565f2;*/
        }
    }
    * {
        box-sizing:border-box;
    }
    .holder {
        height: 140px;
        width: 250px;
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        
    }
    
    .ring {
        position: relative;
        width: 104px;
        height: 104px;
        border-radius: 50%;
        /*background: #888;*/
        background: linear-gradient(#dadada, #7a7a7a);
        
    }
    
    .inner-circle {
        position: relative;
        display: flex;
        flex-wrap: wrap;
      justify-content: center;
      align-items: center;
        top: 5px;
        left: 5px;
        width: 94px;
        height: 94px;
        /*background: green;*/
        border-radius: 50%;
        /*border: 5px solid rgba(255,255,255,0.1);*/
        
        
    }
    span.buttonText {
        width: 80%;
        text-align:center; /*flex doesn't center all lines...*/
        overflow:none;
        text-decoration: none;
        font-size: 1.15rem;
        line-height: 1em;
        font-weight: 600;
        letter-spacing: -.065em;
        font-family: "Hammersmith One", sans-serif;
    }
    
    .no-color,
    .color0 {
        background-color: #4a4a4a;
        color: #777;
        border: 4px solid rgba(255, 255, 255, 0.15);
    }
    
    .red,
    .color1 {
        background-color: #ef3932;
        color: #faf9c3;
        text-shadow: 1px 1px 0 rgba(0, 0, 0, .15);
        border: 4px solid rgba(0, 0, 0, 0.15);
    }
    
    .green,
    .color2 {
        background-color: #01c826;
        color: #faf697;
        text-shadow: 1px 1px 0 rgba(0, 0, 0, .15);
        border: 4px solid rgba(0, 0, 0, 0.15);
    }
    
    .yellow,
    .color3 {
        background-color: rgba(252, 227, 1, 2);
        color: #8c1c00;
        text-shadow: 1px 1px 0 rgba(255, 255, 255, .9);
        border: 4px solid rgba(0, 0, 0, 0.15);
    }
    
    .blue,
    .color4 {
        background: #00c8ff;
        color: #faf9c3;
        border: 4px solid rgba(0, 0, 0, 0.15);
        text-shadow: 1px 1px 0 rgba(0, 0, 0, .15);
    }
    
    .white,
    .color5 {
        background: #fafafa;
        color: #8c1c00;
        text-shadow: 1px 1px 0 rgba(0, 0, 0, .1);
        border: 4px solid rgba(0, 0, 0, 0.1);
    
    }
    
    .blink0 {
        animation: none;
    }
    
    .blink1 {
        animation: none;
        /*animation: blink 2s infinite;*/
    }
    
    .blink2 {
        animation: none;
        /*animation: blink 2s step-end infinite;*/
    }
    
    .blink3 {
        animation: none;
        /*animation: blink 2s infinite;*/
    }
    
    
    </style>
    
    <div ng-init="page = {}"></div>
    
    <ma-watch-list-get ng-model="indicatorWl.watchlist" parameters="indicatorWl.parameters" on-points-change="page.points = $points" id="wl-indicator-id" watch-list-xid="WL_Indicator"></ma-watch-list-get>
    <ma-get-point-value points="page.points"></ma-get-point-value>
    
    <div>
        <div class="holder">
            
            <div class="ring">
                <push-lamp points="page.points" target="H2OT1"></push-lamp>
            </div>
            
            <ma-point-value id="bf63d154-4359-4780-8440-e75ab17179c2" enable-popup="hide" point="page.points | filter:{name:'T1-Water-Valve'}:true | maFirst"></ma-point-value>
            
        </div>
        <div class="holder">
    
            <div class="ring">
                <push-lamp points="page.points" target="H2OT2"></push-lamp>
            </div>
            
            <ma-point-value id="bf63d154-4359-4780-8440-e75ab17179c2" enable-popup="hide" point="page.points | filter:{name:'T2-Water-Valve'}:true | maFirst"></ma-point-value> <!-- _sw_ values for toggle testing -->
            
        </div>
        <div class="holder">
            
            <div class="ring">
                <push-lamp points="page.points" target="H2OT3"></push-lamp>
            </div>
            
            <ma-point-value id="bf63d154-4359-4780-8440-e75ab17179c2" enable-popup="hide" point="page.points | filter:{name:'T3-Water-Valve'}:true | maFirst"></ma-point-value>
            
        </div>
        <div class="holder">
            
            <div class="ring">
                <push-lamp points="page.points" target="H2OMX"></push-lamp>
            </div>
            
            <ma-point-value id="bf63d154-4359-4780-8440-e75ab17179c2" enable-popup="hide" point="page.points | filter:{name:'MX-Water-Valve'}:true | maFirst"></ma-point-value>
            
        </div>
    </div>
    

    do you need some points?


  • Cool, if you're copying my structure, this is my advice:

    /opt/mango/overrides/web/modules/mangoUI/web/dev/userModule.js

    define(['angular', 'require','./components/pushLamp.js'], 
    function (angular, require,pushLamp) {
    var userModule = angular.module('userModule', ['maUiApp']);
    userModule.filter('unsafe', ['$sce', function($sce) {
          return $sce.trustAsHtml;
        }]);
    try
    {
    userModule.component('pushLamp',pushLamp);
    }
    catch(e)
    {
    console.log(e);
    }
    });
    

    /opt/mango/overrides/web/modules/mangoUI/web/dev/components/pushLamp.js

    define(['angular', 'require'], function (angular, require) {
    pushCtrl.$inject = ['$scope','$timeout'];
    
      function pushCtrl($scope,$timeout) {
    
     
    
        const $ctrl = this;
        $ctrl.$onChanges = function (changes) {
          if (changes.points && Array.isArray($ctrl.points)) {
    
            $ctrl.point = $ctrl.points.find(p => p.xid === 'DP_ind_' + $ctrl.target);
            $ctrl.switchPoint = $ctrl.points.find(p => p.xid === 'DP_sw_' + $ctrl.target);
    
            $ctrl.ptCSS = { // point css values for color and blink; ex, ng-class=""
              get color(){
                if ($ctrl.point.color < 10) {
                  return 0;
                }
                return Math.floor($ctrl.point.value / 10)},
              get blink(){return 'blink' + $ctrl.point.value % 10},
              get colStyle(){return 'color'+this.color}
            };
    
            $timeout(function() {
              console.log('color:', $ctrl.ptCSS.colStyle, 'blink:', $ctrl.ptCSS.blink );
            },1000);
          }
        };
    
        $ctrl.pushed = function() {
          console.log($ctrl.switchPoint.value);
            if ($ctrl.switchPoint) {
                $ctrl.switchPoint.toggleValue();
              console.log('switch ' + $ctrl.target + ' was switched.' );
           }
        };
      }
     const template = '<div class="inner-circle" ng-class="[$ctrl.ptCSS.colStyle, $ctrl.ptCSS.blink]" ng-click="$ctrl.pushed()"><span class="buttonText" ng-bind-html="$ctrl.point.tags.indText | unsafe"></span> </div>'; // using $sce here to get pass <br>'s in text; flex-wrap also on
    // (used single quotes instead of backticks for post...)
    return {
          template: template,
          bindings: {
            points: '<',
            target: '@'
          },
          controller: pushCtrl
        };
    
    });
    

    If you use try-catches you can identify errors that don't result in your usermodule breaking and thus losing all components in it.


  • ok - do I need to change the base directory?


  • @bobday said in Advice on moving components / controllers / services out of userModule:

    ok - do I need to change the base directory?

    Nope, userModule extends the mangoUI


  • well, doing exactly that, and setting the location to /modules/mangoUI/web/dev/userModule.js,
    left me with:
    "Failed to load AMD module modules/mangoUI/web/dev/userModule.js Error: Script error for "modules/mangoUI/web/dev/userModule.js" in Chrome console - no component error logged.

    and this file is there:

    define(['angular', 'require','./components/pushLamp.js'],
      function (angular, require, pushLamp) {
        var userModule = angular.module('userModule', ['maUiApp']);
    
        userModule.filter('unsafe', ['$sce', function($sce) {
           return $sce.trustAsHtml;
        }]);
    
        try
        {
          userModule.component('pushLamp',pushLamp);
        }
        catch(e)
        {
          console.log('error: ', e);
        }
    
    });
    

  • You've got the right idea, the first thing I suggest is to see if you can even manually load the userModule from your web browser

    [mangoURL]/modules/mangoUI/web/dev/userModule.js

    if you can pull that, then try with the components directory


  • Hang on, your mango install is in /opt/mango36 ?
    Not in /opt/mango ?


  • yes, but using Mango36 in the url... as in /opt/mango36/overrides/web/modules/mangoUI/web/dev/userModule.js

    hmmm... does it need to live in /mango?


  • nope, just wanted to make sure you did have the files inside the mango's installation directory regardless of how it is named.

    Did the http requests from your browser work?

    If the mango is on localhost it'd be localhost/modules/mangoUI/web/dev/userModule.js


  • nope. clearly have a path issue here...


  • if you're in linux, can you navigate to the directory where your usermodule is and enter

    pwd
    

    otherwise if in windows, open a command prompt in the location and enter

    DIR
    

    to print the path


  • (osx)
    pwd
    /opt/mango36/overrides/web/modules/mangoUI/web/dev


  • nope that's definitely correct, check your directory permissions and the owner.
    I'll wager mango itself may not have access to the file.
    Whatever the user runs as in mango set that as your modules etc directories for a start.
    up to web. everything inside that shouldn't matter.

    We'll start with that and work our way up from there...

    sudo chown [user]:[user] /opt/mango36/overrides -R
    
    sudo find /opt/mango36/overrides -type d -exec chmod 755 {} \;