B4J Tutorial [ABMaterial] Custom components and ABMModalSheet

Discussion in 'B4J Tutorials' started by OliverA, Jun 14, 2019 at 8:15 PM.

  1. OliverA

    OliverA Well-Known Member Licensed User

    This is not a tutorial on how to create custom components for ABMaterial. It is more a "what to watch out for when creating custom components that need to work with an ABMModalSheet". This is also not a definitive guide on this subject, just a sharing of issues/resolutions I came across while 1) implementing my own version of a JustGage custom component based on the one already found in the source of the Demo and 2) trying to build a new custom component on Leaflet.

    Issue #1: Neither the JustGage component, nor the Leaflet component would show up the modal sheet. Doing some research, this seems to be a common problem (graphical items not properly showing up on a modal sheet) and there seem to be resolutions for both JustGage (set width and height of the DIV that contains the JustGage component) and Leaflet (call invalidateSize() AFTER the modal is up, with various solutions on how to approach the issue found). I tried and tried to get the suggested resolutions working. And it was never going to work with using the standard "ABM Custom Component" found under Project -> Add New Module -> Class Module, which is issue #2.

    Issue #2: Let me explain. When adding this class module, the following method is used to "build" your component
    Code:
    Sub ABMComp_Build(InternalPage As ABMPage, internalID As StringAs String
       
    Return $"<div id="${internalID}"></div><script>var _${internalID};</script>"$
    End Sub
    So if you have a custom component and you give it the id "MyFirstGauge", then this will spit out
    Code:
    <div id="myfirstgauge"></div><script>var _myfirstgauge;<script>
    Note that the internalid is your id lowercased. This generated code works great for components that you add at the page level but breaks down totally when you add a component to a modal sheet. You have three areas that you can add components to in a modal sheet: header, content, and footer section. Let's say you've created a modal sheet with the id "MyFirstModal", then the id's for those sections are: myfirstmodal-header, myfirstmodal-content and myfirstmodal-footer. Depending on where you add your "MyFirstGauge" component, your component's internal id will either be myfirstmodal-header-myfirstgauge, myfirstmodal-content-myfirstgauge, and myfirstmodal-footer-myfirstgauge. Anyone notice the issue with this? I did not at first, since I was working hard on issue#1. After being unsuccessful for hours, I finally happened to see this (I placed my component in the content section):
    Code:
    <script>var _myfirstmodal-content-myfirstgauge;<script>
    See the issue here? Ok, in order to display the gauge, I had the following code in ABMComp_FirstRun
    Code:
    Dim script As String = $"_${internalID} = new JustGage(${optionsJSON});"$
    InternalPage.ws.Eval(script, 
    Null)
    Where optionsJSON is just a JSON string with options to pass on to JustGage. See the issue? Anyone with JavaScript experience should. The variable uses a non-allowed character, the dash (-). Therefore, nothing works. So my solution for this showstopper is this SmartString fragment instead for the variable name:
    Code:
    _${internalID.Replace("-","_")}
    Issue#2 sub-issue:
    Now we have:
    Code:
    Sub ABMComp_Build(InternalPage As ABMPage, internalID As StringAs String
       
    Return $"<div id="${internalID}"></div><script>var _${internalID.Replace("-","_")};</script>"$
    End Sub
    This introduces another subtle issue. When looking at the resulting DOM, you'll notice that there are two DIV's with the same id. So, if you used MyFirstGauge as your id, you'll actually get two DIV's with that id.
    Code:
    <div id="myfirstmodal-content-myfirstgauge" style="" class="  only-print  ">
    <div 
    id="myfirstmodal-content-myfirstgauge">
    </div>
    <script>var _myfirstmodal_content_myfirstgauge;</script>
    </div>
    One is for the ABMComp component that is initialized in the Initialize method of your custom component
    Code:
    Public Sub Initialize(InternalPage As ABMPage, ID As String)
       
    Dim CSS As String = $""$
       ABMComp.Initialize(
    "ABMComp", Me, InternalPage, ID, CSS)       
    End Sub
    and one is for the DIV that is set up in the ABMComp_Build method. To properly set up your JavaScript components, you will most likely pass on the internalID to a JavaScript method. Here's an edited version of my JustGage code
    Code:
    Sub ABMComp_Build(InternalPage As ABMPage, internalID As StringAs String
       options.Put(
    "id"$"${internalID}"$)
       
    Return $"<div id="${internalID}"></div><script>var _${internalID.Replace("-","_")};</script>"$
    End Sub

    Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String)   Dim JSON As JSONGenerator
       JSON.Initialize(options)
       
    Dim optionsJSON As String = JSON.ToPrettyString(2)

       
    Dim script As String = $"_${internalID.Replace("-","_")} = new JustGage(${optionsJSON});"$
       InternalPage.ws.Eval(script, 
    Null)End Sub
    [code]
    The (may 
    not be a) problem is that the Gauge is "bound" to the first DIV, not the DIV that you set up in the Build method above.
    So you get
    [code]
    <div 
    id="myfirstmodal-content-myfirstgauge" style="" class="  only-print  ">
       <
    svg ....>
       //all the JustGage DOM stuff added here
       <div 
    id="myfirstmodal-content-myfirstgauge">
       </div>
       <script>var _myfirstmodal_content_myfirstgauge;</script>
    </div>
    instead of
    Code:
    <div id="myfirstmodal-content-myfirstgauge" style="" class="  only-print  ">
       <div 
    id="myfirstmodal-content-myfirstgauge">
          <
    svg....>
          //all the JustGage DOM stuff added here
       </div>
       <script>var _myfirstmodal_content_myfirstgauge;</script>
    </div>
    The workaround for this is that I just append a "-internal" to the internalID to create a new DIV id. Update code
    Code:
    Sub ABMComp_Build(InternalPage As ABMPage, internalID As StringAs String
       options.Put(
    "id"$"${internalID}-internal"$)
       
    Return $"<div id="${internalID}-internal"></div><script>var _${internalID.Replace("-","_")};</script>"$
    End Sub
    Which results in
    Code:
    <div id="myfirstmodal-content-myfirstgauge" style="" class="  only-print  ">
       <div 
    id="myfirstmodal-content-myfirstgauge-internal">
          <
    svg....>
          //all the JustGage DOM stuff added here
       </div>
       <script>var _myfirstmodal_content_myfirstgauge;</script>
    </div>
    Now back to issue#1: (continued in another post)

    Links:
    JustGage: https://github.com/toorshia/justgage
    Leaflet: https://leafletjs.com/
     
    Johan Hormaza and Cableguy like this.
  2. OliverA

    OliverA Well-Known Member Licensed User

    Last edited: Jun 15, 2019 at 3:28 AM
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice