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
So if you have a custom component and you give it the id "MyFirstGauge", then this will spit out
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):
See the issue here? Ok, in order to display the gauge, I had the following code in ABMComp_FirstRun
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:
Issue#2 sub-issue:
Now we have:
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.
One is for the ABMComp component that is initialized in the Initialize method of your custom component
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
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
instead of
The workaround for this is that I just append a "-internal" to the internalID to create a new DIV id. Update code
Which results in
Now back to issue#1: (continued in another post)
Links:
JustGage: https://github.com/toorshia/justgage
Leaflet: https://leafletjs.com/
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
B4X:
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String
Return $"<div id="${internalID}"></div><script>var _${internalID};</script>"$
End Sub
B4X:
<div id="myfirstgauge"></div><script>var _myfirstgauge;<script>
B4X:
<script>var _myfirstmodal-content-myfirstgauge;<script>
B4X:
Dim script As String = $"_${internalID} = new JustGage(${optionsJSON});"$
InternalPage.ws.Eval(script, Null)
B4X:
_${internalID.Replace("-","_")}
Now we have:
B4X:
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String
Return $"<div id="${internalID}"></div><script>var _${internalID.Replace("-","_")};</script>"$
End Sub
B4X:
<div id="myfirstmodal-content-myfirstgauge" style="" class=" only-print ">
<div id="myfirstmodal-content-myfirstgauge">
</div>
<script>var _myfirstmodal_content_myfirstgauge;</script>
</div>
B4X:
Public Sub Initialize(InternalPage As ABMPage, ID As String)
Dim CSS As String = $""$
ABMComp.Initialize("ABMComp", Me, InternalPage, ID, CSS)
End Sub
B4X:
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As 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
So you get
B4X:
<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>
B4X:
<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>
B4X:
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String
options.Put("id", $"${internalID}-internal"$)
Return $"<div id="${internalID}-internal"></div><script>var _${internalID.Replace("-","_")};</script>"$
End Sub
B4X:
<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/
Last edited: