• Recent
    • Tags
    • Popular
    • Register
    • Login

    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 Mango 5 Documentation Website

    Styling a Custom Component in userModule

    Dashboard Designer & Custom AngularJS Pages
    4
    17
    4.1k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • P
      pyeager @MattFox
      last edited by

      @mattfox I'm brand new to angular. Where does the code you provided go?

      1 Reply Last reply Reply Quote 0
      • MattFoxM
        MattFox
        last edited by MattFox

        Ah right sorry,
        From what it looks like, you want a generic solution to provide users a drag and drop component I'll give you the bones of a component to fill in. The html should probably be in a separate template file.
        Is your userModule in the mango file store or on disk?

        Fox

        EDIT: Have you made a start? If so we can build from that.

        Do not follow where the path may lead; go instead where there is no path.
        And leave a trail - Muriel Strode

        P 1 Reply Last reply Reply Quote 0
        • P
          pyeager @MattFox
          last edited by

          @mattfox said in Styling a Custom Component in userModule:

          From what it looks like, you want a generic solution to provide users a drag and drop component I'll give you the bones of a component to fill in. The html should probably be in a separate template file.

          Yes, I need to build a drag and drop component. I have already figured out how to use a separate template file. Beyond that, the code is little changed from the example code.

          define(['angular', 'require'], function(angular, require) {
          'use strict';
          
          var userModule = angular.module('userModule', ['maUiApp']);
          
          userModule.component('stickGun', {
              bindings: {
                  name: '@?',
                  face: '@?'
              },
              templateUrl: '/rest/v2/file-stores/public/userModule.html',
              styleUrls: ['/rest/v2/file-stores/public/userModule.css']
          });
          
          return userModule;
          
          }); // define
          

          Is your userModule in the mango file store or on disk?

          It is in the public folder in the file store. That also appears to be on disk at /opt/mango/filestore/public

          1 Reply Last reply Reply Quote 0
          • MattFoxM
            MattFox
            last edited by MattFox

            Cool thanks Pyeager, I'll get something knocked together now. Secondly, you're best to use a separate template url per component. I'd strongly suggest creating a /rest/v2/file-stores/public/stickGun.html html file, so you know what the contents are without having to open it up.

            That also appears to be on disk at /opt/mango/filestore/public

            Sorry I meant outside of mango in the overrides or something. Just in case upgrades or something causes an errant spanner to be thrown... ;) - It also allows you to add source control so you can store your files in a git or svn based solution, very handy for versioning, and who to blame when something breaks (haha)

            Fox

            Do not follow where the path may lead; go instead where there is no path.
            And leave a trail - Muriel Strode

            1 Reply Last reply Reply Quote 0
            • MattFoxM
              MattFox
              last edited by

              Here's something to get you started, I'm not sure what the purpose of the ng-click is for your image, if you are able to explain i'll likely be able to assist with that part.
              I am not sure what name and face are for either.
              Basically with the component, you're bringing all of the dynamic variables to the surface as bindings for the component. From here you do all of your calcs and fancy doodads inside the component's controller.

              Your html:

              <section>
              <style>
              .idle { background-color: rgba( 255, 255, 255, 0.5); }
              .heat { background-color: rgba( 255, 255, 0, 0.5 ); }
              .air { background-color: rgba( 3, 186, 252, 0.5 ); }
              .heatair { background-image: url("/rest/v2/file-stores/default/HeatAir.png"); }
              .a0 { background-image: url("/rest/v2/file-stores/default/A0.png"); }
              .s1 { background-image: url("/rest/v2/file-stores/default/Stage1.png"); }
              .s2 { background-image: url("/rest/v2/file-stores/default/Stage2.png"); }
              .s3 { background-image: url("/rest/v2/file-stores/default/Stage3.png"); }
              .manual { background-color: rgba( 0, 0, 0, 0.5); }
              </style>
              <ma-get-point-value point="sequence1" point-xid="{{$ctrl.pointXid}}"></ma-get-point-value>
              <!-- ng-click="designer.parameters = {dn: 'sg-lsb-01v'}" What is this for?? -->
              <img id="{{$ctrl.pointXid}}_img" style="width: 30px; height: 28px;" src="/rest/v2/file-stores/default/HKDStickL.png" ng-click="designer.parameters = {dn: 'sg-lsb-01v'}" ng-class="{0:'idle', 1:'heat', 2:'air', 3:'heatair', 4:'a0', 5:'s1', 6:'s2', 7:'s3', 8:'manual'} [sequence1.value]">
              </section>
              

              Your component

              userModule.component('stickGun', {
                  bindings: {
                      name: '>?',  //1-way binding optional
                      face: '>?',
              		pointXid:'>' //required
                  },
                  templateUrl: '/rest/v2/file-stores/public/stickGun.html',
                  styleUrls: ['/rest/v2/file-stores/public/userModule.css'], //not hugely needed, especically if you use the user styles file to store all your css in. Unless you plan to take this component to other places...
              	controller:function(){
              		var ctrl = this;
              		this.$onChanges = function(e)
              		{
              			//binding checks are done in here. this is for an example of what I stated prior if you are using optional bindings
              			if(e.pointXid && e.pointXid.currentValue!=undefined)
              			{
              				ctrl.pointXid = e.pointXid.currentValue;
              			}
              		};
              		
              	}
              });
              

              Do not follow where the path may lead; go instead where there is no path.
              And leave a trail - Muriel Strode

              P 1 Reply Last reply Reply Quote 1
              • P
                pyeager @MattFox
                last edited by

                @mattfox Thanks!

                It's quitting time. so I'll play with it tomorrow.

                When the image is clicked, ng-click set which device's details are shown on a card.

                1 Reply Last reply Reply Quote 0
                • Jared WiltshireJ
                  Jared Wiltshire
                  last edited by

                  @pyeager This is what I would do, based off your code. Note that styleUrls seems to be Angular 2+ syntax, not AngularJS (1.x). Put your CSS in the user styles style sheet (under UI settings).

                  User module -

                  define(['angular', 'require'], function(angular, require) {
                  'use strict';
                  
                  var userModule = angular.module('userModule', ['maUiApp']);
                  
                  // doesn't do anything, but here for completeness
                  class StickGunController {
                  }
                  
                  userModule.component('stickGun', {
                      bindings: {
                          name: '@?', // dont know what these are for, but sure
                          face: '@?',
                          point: '<?'
                      },
                      templateUrl: '/rest/v2/file-stores/public/stickGun.html',
                      controller: StickGunController
                  });
                  
                  return userModule;
                  
                  }); // define
                  

                  Template file (/rest/v2/file-stores/public/stickGun.html) -

                  <ma-get-point-value point="$ctrl.point"></ma-get-point-value>
                  <img src="/rest/v2/file-stores/default/HKDStickL.png" ng-class="{0:'idle', 1:'heat', 2:'air', 3:'heatair', 4:'a0', 5:'s1', 6:'s2', 7:'s3', 8:'manual'}[$ctrl.point.value]">
                  

                  CSS file -

                  stick-gun {
                      display: block;
                  }
                  stick-gun > img {
                      width: 100%;
                      height: 100%;
                  }
                  stick-gun > img.idle { background-color: rgba( 255, 255, 255, 0.5); }
                  stick-gun > img.heat { background-color: rgba( 255, 255, 0, 0.5 ); }
                  stick-gun > img.air { background-color: rgba( 3, 186, 252, 0.5 ); }
                  stick-gun > img.heatair { background-image: url("/rest/v2/file-stores/default/HeatAir.png"); }
                  stick-gun > img.a0 { background-image: url("/rest/v2/file-stores/default/A0.png"); }
                  stick-gun > img.s1 { background-image: url("/rest/v2/file-stores/default/Stage1.png"); }
                  stick-gun > img.s2 { background-image: url("/rest/v2/file-stores/default/Stage2.png"); }
                  stick-gun > img.s3 { background-image: url("/rest/v2/file-stores/default/Stage3.png"); }
                  stick-gun > img.manual { background-color: rgba( 0, 0, 0, 0.5); }
                  

                  Developer at Radix IoT

                  1 Reply Last reply Reply Quote 0
                  • Jared WiltshireJ
                    Jared Wiltshire
                    last edited by

                    Oh, and to use, you just add this to your page -

                    <stick-gun point="myPoint"></stick-gun>
                    

                    Developer at Radix IoT

                    1 Reply Last reply Reply Quote 0
                    • MattFoxM
                      MattFox
                      last edited by

                      Thanks Jared, appreciate the support!

                      Do not follow where the path may lead; go instead where there is no path.
                      And leave a trail - Muriel Strode

                      1 Reply Last reply Reply Quote 0
                      • P
                        pyeager
                        last edited by

                        Thank you both for your help.

                        I might need just a little more.

                        Specifying a data point by xid, as both of your examples do, is a bit less than optimal for a couple of reasons.

                        For one thing, there are multiple data points with which the component needs to interact.

                        Also, specifying one or more data points by xid is less than user friendly. My preferred approach is to just name the component instance in such a way that queries can be constructed from the instance name, removing the need to specify an xid for each data point.

                        ...and additionally...

                        This may be asking a lot, but ideally adding this component to a dashboard would also create a few data sources, likely from a template. That would make the drag and drop addition of the component and definition of element-specific details pretty much all that is necessary to add a machine to the system.

                        Jared WiltshireJ MattFoxM 2 Replies Last reply Reply Quote 0
                        • Jared WiltshireJ
                          Jared Wiltshire @pyeager
                          last edited by

                          @pyeager said in Styling a Custom Component in userModule:

                          Specifying a data point by xid, as both of your examples do, is a bit less than optimal for a couple of reasons.

                          My example does not specify a data point by XID, it passes a single data point through.

                          @pyeager said in Styling a Custom Component in userModule:

                          For one thing, there are multiple data points with which the component needs to interact.

                          In this case you could pass a whole array of data points through (from a query or Watchlist) and filter the points out inside the component.

                          @pyeager said in Styling a Custom Component in userModule:

                          Also, specifying one or more data points by xid is less than user friendly. My preferred approach is to just name the component instance in such a way that queries can be constructed from the instance name, removing the need to specify an xid for each data point.

                          I agree you should not directly bind components to a specify XID. This is why our dashboard designer supports selecting a watchlist then binding components to data points using their name.

                          If you want to use a name attribute for your components this would work in a similar fashion. Like I said above, pass the whole points array through to the component and then find the point you want inside the component using the name attribute.

                          e.g. controller for your component

                          class StickGunController {
                            $onChanges(changes) {
                              if (changes.points && Array.isArray(this.points)) {
                                this.point = this.points.find(pt => pt.name === this.name);
                              }
                            }
                          }
                          

                          @pyeager said in Styling a Custom Component in userModule:

                          This may be asking a lot, but ideally adding this component to a dashboard would also create a few data sources, likely from a template. That would make the drag and drop addition of the component and definition of element-specific details pretty much all that is necessary to add a machine to the system.

                          Certainly possible, I don't have time to get right into this right now but you could use the maDataSource service to check for the existence of the DS and create it if one matching the name attribute doesn't exist.

                          Developer at Radix IoT

                          P 1 Reply Last reply Reply Quote 1
                          • P
                            pyeager @Jared Wiltshire
                            last edited by

                            @jared-wiltshire said in Styling a Custom Component in userModule:

                            Like I said above, pass the whole points array through to the component and then find the point you want inside the component using the name attribute.

                            How does one pass the whole points array to the component?

                            Jared WiltshireJ 1 Reply Last reply Reply Quote 0
                            • phildunlapP
                              phildunlap
                              last edited by

                              By defining "points" as an input of the component, as I did in this post: https://forum.infiniteautomation.com/topic/3503/how-to-chart-with-data-points-in-the-x-axis-instead-of-time/6

                              1 Reply Last reply Reply Quote 0
                              • Jared WiltshireJ
                                Jared Wiltshire @pyeager
                                last edited by

                                @pyeager said in Styling a Custom Component in userModule:

                                How does one pass the whole points array to the component?

                                Are you asking how to define the binding in the component or how to pass the points to the attribute when you are using it?

                                To define the binding, you literally just have to change point to points in the example I posted above. I gave you a controller that will locate the point from the array using the name attribute.

                                If you meant the latter, I suggest you peruse the examples that are built into Mango (enable the examples menu item using the menu editor if you have not already).

                                Developer at Radix IoT

                                1 Reply Last reply Reply Quote 0
                                • MattFoxM
                                  MattFox @pyeager
                                  last edited by

                                  @pyeager said in Styling a Custom Component in userModule:

                                  For one thing, there are multiple data points with which the component needs to interact.

                                  You never stated this initially

                                  @jared-wiltshire said in Styling a Custom Component in userModule:

                                  Certainly possible, I don't have time to get right into this right now but you could use the maDataSource service to check for the existence of the DS and create it if one matching the name attribute doesn't exist.

                                  If this is remotely similar to making a new point using the maPoint service perhaps I can be of assistance here

                                  Do not follow where the path may lead; go instead where there is no path.
                                  And leave a trail - Muriel Strode

                                  1 Reply Last reply Reply Quote 1
                                  • First post
                                    Last post