B4J Tutorial [ABMaterial]: Raising Events from Custom Components

Hi there

With the ability to create custom components for your ABMaterial WebApp, one is also able to raise and capture events when creating and running their webapp.

I have found it easier though to raise events at document level, but you can also create a component specific event with the component click/onchange etc event.

As an example, this code below, will add a click event to my component. The magic behind all of this is the b4j_raiseEvent method

B4X:
'add a click event to any element on the page
Sub AddClickEvent(compID As String,compText As String) As String
    Dim sb As StringBuilder
    sb.Initialize
    sb.Append($"$(function() {"$)
    sb.Append($"$('#${compID}').click(function(){"$)
    'sb.Append("event.stopPropagation();")
    sb.Append($"b4j_raiseEvent('${compID}_click', {'value':'${compText}'});"$)
    sb.Append("});")
    sb.Append("});")
    Return sb.ToString
End Sub

compID is the name of my component and compText is what I want to be returned when this click event is executed. So when your component is clicked in this case, the javascript call above will be executed, b4j_raiseEvent will ensure that your ABMaterial WebApp is able to execute the call.

How does the ABMaterial WebApp know?

What you need to do first is tell your app that we are expecting a call. For starters you create your control in your page and give it a name.

In Class_Globals

B4X:
Private ms1 as MashButtonGroup

In ConnectPage

B4X:
ms1.Initialize(page, "mybutton", myTheme)

Now, remember, you have given your component a name, and its not ms1, it is "mybutton", as an HTML element has been created on the page. So to tell ABMaterial that we are expecting an event, you need to add a method to the page.

B4X:
Sub mybutton_click(value As Map)
  dim valueX as string = value.getdefault("value","")
  if valueX = "doThis" then
    doThis
  else if valueX = "doThat" then
    doThat
  end if
End Sub

Now where do you add this click event when creating you control?

This should be inside this call

B4X:
Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)
Dim myEvent As String = AddClickEvent(internalID,"Mashy")
page.ws.Eval(myEvent, Array As String(internalID))
(this runs during Page.Refresh in ConnectPage

Do you like this tutorial?

PS: In the Refresh method above, when the click event happens in your WebApp via your custom component, nothing will happen? Why? The value that is passed to valueX from your component is "Mashy" and not "doThis" or "doThat", so be careful.
 
Last edited:

walterf25

Expert
Licensed User
Longtime User
Hi there

With the ability to create custom components for your ABMaterial WebApp, one is also able to raise and capture events when creating and running their webapp.

I have found it easier though to raise events at document level, but you can also create a component specific event with the component click/onchange etc event.

As an example, this code below, will add a click event to my component. The magic behind all of this is the b4j_raiseEvent method

B4X:
'add a click event to any element on the page
Sub AddClickEvent(compID As String,compText As String) As String
    Dim sb As StringBuilder
    sb.Initialize
    sb.Append($"$(function() {"$)
    sb.Append($"$('#${compID}').click(function(){"$)
    'sb.Append("event.stopPropagation();")
    sb.Append($"b4j_raiseEvent('${compID}_click', {'value':'${compText}'});"$)
    sb.Append("});")
    sb.Append("});")
    Return sb.ToString
End Sub

compID is the name of my component and compText is what I want to be returned when this click event is executed. So when your component is clicked in this case, the javascript call above will be executed, b4j_raiseEvent will ensure that your ABMaterial WebApp is able to execute the call.

How does the ABMaterial WebApp know?

What you need to do first is tell your app that we are expecting a call. For starters you create your control in your page and give it a name.

In Class_Globals

B4X:
Private ms1 as MashButtonGroup

In ConnectPage

B4X:
ms1.Initialize(page, "mybutton", myTheme)

Now, remember, you have given your component a name, and its not ms1, it is "mybutton", as an HTML element has been created on the page. So to tell ABMaterial that we are expecting an event, you need to add a method to the page.

B4X:
Sub mybutton_click(value As Map)
  dim valueX as string = value.getdefault("value","")
  if valueX = "doThis" then
    doThis
  else if valueX = "doThat" then
    doThat
  end if
End Sub

Now where do you add this click event when creating you control?

This should be inside this call

B4X:
Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)
Dim myEvent As String = AddClickEvent(internalID,"Mashy")
page.ws.Eval(myEvent, Array As String(internalID))
(this runs during Page.Refresh in ConnectPage

Do you like this tutorial?

PS: In the Refresh method above, when the click event happens in your WebApp via your custom component, nothing will happen? Why? The value that is passed to valueX from your component is "Mashy" and not "doThis" or "doThat", so be careful.
How can i pass an array of doubles in the click event, i am trying to add a callback function to a library i'm playing around with and I need to return an array of doubles, in this case, i see the signature of the "mybutton_click event you are returning a Map as a parameter, where does that Map type come from, and can it be any other type rather than a Map?

Walter
 

walterf25

Expert
Licensed User
Longtime User
The map variable comes from the definition of the b4j_raiseevent code. {value}.

In terms of passing an array, perhaps start a new thread about passing an array on b4j_raiseEvent in ABM as I honestly dun-no.
I actually figured it out, it is basically the same event signature, but I also had to add the following code which needs to be called from the WebSocket_Connected event, this code is to set the maximum message size, i was getting an error since the amount of data being passed was huge, in the order of 5000 datapoints in my case.

B4X:
Sub SetMaxTextMessage(size As Int)
    Dim jo As JavaObject = ws
    jo = jo.GetFieldJO("session").RunMethod("getPolicy", Null)
    jo.RunMethod("setMaxTextMessageSize", Array(size))
End Sub

in my case I call this function like this
B4X:
setMaxTextMessage(1024*1024)
instead of passing a String inside the Map, i am passing an array of doubles that is 5000 elements in size.

Thanks,
Walter
 
Top