B4J Question [ABMaterial] ousEvUnexpected event (missing RaiseSynchronents): abmcomp_build

Joan Paz

Member
Hello Everyone!

I'm creating a new ABM Component (ABMaterial Custom Component) with select2.js, it works fine, but sometimes when i refresh the browser (F5), i get the error "Unexpected event (missing RaiseSynchronousEvents): abmcomp_build".

If somebody know the reason, i will apreciate the shared knowledge :).

Thanks in advance, and I hope everyone had a happy holiday.


PD: Thats the component:

B4X:
' Class module
Sub Class_Globals
    'Dim ABM As ABMaterial
    Dim ABMComp As ABMCustomComponent
    Private ztags, zallowClear As Boolean
    Private zplaceholder As String
    Private zdata As String
    Private zid As String
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(InternalPage As ABMPage, id As String,tags As Boolean, allowclear As Boolean, placeholder As String, data As Map )
    ABMComp.Initialize("ABMComp", Me, InternalPage, id, "")
    ' the automatic events will be raised on the page e.g. if the id = "mycomp" then the event will be mycomp_Click(params as Map)
    ' future: we'll see if some other mechanisme is needed for non automatic events
 
    ztags = tags
    zplaceholder = placeholder
    zallowClear = allowclear
   
    If data.Size > 0 Then
        For Each k As String In data.Keys  
            zdata = zdata & $"{id:"${k}",text:"${data.Get(k)}"},"$
        Next
        zdata = zdata.SubString2(0,zdata.Length-1)
        zdata = $"[${zdata}]"$  
    End If

End Sub

' runs when an object is created for the first time. Expects a valid html string
' will get surrounded by a div automatically
' in the html file:
'<div ID="mycomp" class="">
'    <h1 ID="testh1">This Is a test</h1>
'</div>
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String
 
    zid= internalID&"s2"
 
    Return $"
    <select id="${zid}" style="width: 100%"></select>
    "$
 
End Sub

' Is useful to run some initalisation script.
Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String)
    'Dim script As String = $""$
 
    'InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
    ' flush not needed, it's done in the refresh method in the lib
 
    ''${booleanjs(ztags)}
    Dim script As String = $"

    $('#${zid}').select2({
 
      allowClear: ${booleanjs(zallowClear)},
      placeholder: "${zplaceholder}",
      tags: ${booleanjs(ztags)},
      data:${zdata}
    });

    $('#${zid}').on('select2:select', function (e) {
        b4j_raiseEvent('${internalID}_onchange', {'id':e.params.data.id,'text':e.params.data.text});
    });

    $('#${zid}').val(null).trigger("change");

    "$
 
    InternalPage.ws.Eval(script,Null)
   
End Sub

' runs when a refresh is called
Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)
    ' use these methods to adjust the object
    ' ABM.HasClass
    ' ABM.AddClass
    ' ABM.RemoveClass
 
    ' ABM.AddHTML
    ' ABM.InsertHTMLAfter
    ' ABM.RemoveHTML
 
    ' ABM.GetProperty
    ' ABM.SetProperty
    ' ABM.RemoveProperty
 
    ' ABM.GetStyleProperty
    ' ABM.SetStyleProperty
 
    ' do some script stuff like you do in RunJavaScript
 
    Dim script As String = $"$('#${zid}').trigger("change");"$
    InternalPage.ws.Eval(script, Null)
End Sub

' do the stuff needed when the object is removed
Sub ABMComp_CleanUp(InternalPage As ABMPage, internalID As String)
 
    Dim script As String = $"
    $('#${zid}').select2('destroy');
    $('#${zid}').off('select2:select');
    "$
    InternalPage.ws.Eval(script, Null)
 
End Sub

Sub setactiveitem(InternalPage As ABMPage,active_id As String)
 
    Dim script As String = $"
        $('#${zid}').val("${active_id}").trigger("change");
    "$
    InternalPage.ws.Eval(script, Null)
 
End Sub

Sub getactiveitem(InternalPage As ABMPage) As String
 
    Dim script As String = $"
        return $('#${zid}').val();
    "$
    Dim valor As Future =  InternalPage.ws.EvalWithResult(script, Null)
    InternalPage.ws.Flush
 
    Dim retornar As String = valor.Value
 
    Return retornar
 
End Sub

Sub additem(InternalPage As ABMPage, id As String, value As String)
 
    Dim script As String = $"
        var data = {
        id: "${id}",
        text: "${value}"
        };
 
        var newOption = new Option(data.text, data.id, false, false );
        $('#${zid}').append(newOption).value("").trigger('change');          
    "$
    InternalPage.ws.Eval(script, Null)
 
End Sub

Sub visibility(InternalPage As ABMPage, visible As Boolean)
 
    If Not(visible) Then
        Dim script As String = $" $('#${ABMComp.ID}').hide();"$
    Else
        Dim script As String = $" $('#${ABMComp.ID}').show();"$
    End If
 
    InternalPage.ws.Eval(script, Null)
 
End Sub

Sub enabled(InternalPage As ABMPage, enable As Boolean)
 
    If enable Then
        Dim script As String = $" $('#${zid}').prop("disabled", false);"$
    Else
        Dim script As String = $" $('#${zid}').prop("disabled", true);"$
    End If
 
    InternalPage.ws.Eval(script, Null)
 
End Sub

Private Sub booleanjs(valor As Boolean) As String
 
    If valor Then
        Return "true"
    Else
        Return "false"
    End If

End Sub

Sub setwidth(InternalPage As ABMPage, width As String)
 
    Dim script As String = $"
        $('#${ABMComp.ID}').css("width","${width}");
    "$
    InternalPage.ws.Eval(script, Null)
 
End Sub

Libraries:

B4X:
page.AddExtraCSSFile("https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css")
page.AddExtraJavaScriptFile("https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js")

Example:

B4X:
Dim combo001 As customselect2
 
   Dim values As Map
   values.Initialize
   values.Put("1t","Toyota")
   values.Put("2b","BMW")
   values.Put("3f","Fiat")
 
   combo001.Initialize(page,"cmb1",False,False,"Cars",values)
   page.Cell(1,1).MarginTop = "5%"
   page.Cell(1,1).SetOffsetSize(0,0,0,5,5,5)
   page.Cell(1,1).AddComponent(combo001.ABMComp)
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

Joan Paz

Member
Component update: works in modal.

B4X:
' Class module
Sub Class_Globals
    'Dim ABM As ABMaterial
    Dim ABMComp As ABMCustomComponent
    Private ztags, zallowClear As Boolean
    Private zplaceholder As String
    Private zdata As String
    Public zid As String
    Public zids2 As String
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(InternalPage As ABMPage, id As String,tags As Boolean, allowclear As Boolean, placeholder As String, data As Map)
    ABMComp.Initialize("ABMComp", Me, InternalPage, id, "")
    ' the automatic events will be raised on the page e.g. if the id = "mycomp" then the event will be mycomp_Click(params as Map)
    ' future: we'll see if some other mechanisme is needed for non automatic events

    zid = id
    zids2= zid&"s2"
    ztags = tags
    zplaceholder = placeholder
    zallowClear = allowclear
        
    If data.Size > 0 Then   
        For Each k As String In data.Keys       
            zdata = zdata & $"{id:"${k}",text:"${data.Get(k)}"},"$
        Next
        zdata = zdata.SubString2(0,zdata.Length-1)
        zdata = $"[${zdata}]"$       
    End If

End Sub

' runs when an object is created for the first time. Expects a valid html string
' will get surrounded by a div automatically
' in the html file:
'<div ID="mycomp" class="">
'    <h1 ID="testh1">This Is a test</h1>
'</div>
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String   
    
    Return $"   
    <select id="${zids2}" style="width: 100%"></select>
    "$
    
End Sub

' Is useful to run some initalisation script.
Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String)
    'Dim script As String = $""$
    
    'InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
    ' flush not needed, it's done in the refresh method in the lib
    
    ''${booleanjs(ztags)}
    
    
'    $.when($('#${zids2}')).then((self) => { console.log(self);
'    builds2();
'   
'    });
    
    
    Dim script As String = $"
    
        function crears2${zids2}() {
        
        console.log('funcion crear select2');
        
        $('#${zids2}').select2({
          dropdownParent: $('#${ABMComp.ID}'),
          allowClear: ${booleanjs(zallowClear)},
          placeholder: "${zplaceholder}",
          tags: ${booleanjs(ztags)},   
          data:${zdata}
        });

        $('#${zids2}').on('select2:select', function (e) {
            $('#${ABMComp.ID}label').remove();
            $('#${ABMComp.ID}').prepend('<label style="cursor: pointer;color: #444;" id="${ABMComp.ID}label" for="${ABMComp.ID}" class="" activecolor="#03a9f4" inactivecolor="#616161">&nbsp;&nbsp;${zplaceholder}<span class="caret">&nbsp;</span></label>');
            b4j_raiseEvent('${zid}_onchange', {'id':e.params.data.id,'text':e.params.data.text});
        });
        
        $('#${zids2}').on('select2:unselect', function (e) {
            $('#${ABMComp.ID}label').remove();
            b4j_raiseEvent('${zid}_onclear', {'id':e.params.data.id,'text':e.params.data.text});
        });
        

        $('#${zids2}').val(null).trigger("change");
    
        }
        
        
        function waitForElementToDisplay(selector, time) {
            if(document.querySelector(selector)!=null) {
                crears2${zids2}();
                return;
            }
            else {
                setTimeout(function() {
                    waitForElementToDisplay(selector, time);
                }, time);
            }
        }
    
        waitForElementToDisplay('#${zids2}', 100);
    
        
    "$
    
    InternalPage.ws.Eval(script,Null)
        
End Sub

' runs when a refresh is called
Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)
    ' use these methods to adjust the object
    ' ABM.HasClass
    ' ABM.AddClass
    ' ABM.RemoveClass
    
    ' ABM.AddHTML
    ' ABM.InsertHTMLAfter
    ' ABM.RemoveHTML
    
    ' ABM.GetProperty
    ' ABM.SetProperty
    ' ABM.RemoveProperty
    
    ' ABM.GetStyleProperty
    ' ABM.SetStyleProperty
    
    ' do some script stuff like you do in RunJavaScript
    
    Dim script As String = $"$('#${zids2}').trigger("change");"$
    InternalPage.ws.Eval(script, Null)
End Sub

' do the stuff needed when the object is removed
Sub ABMComp_CleanUp(InternalPage As ABMPage, internalID As String)
    
    Dim script As String = $"
    $('#${zids2}').select2('destroy');
    $('#${zids2}').off('select2:select');
    "$
    InternalPage.ws.Eval(script, Null)
    
End Sub

Sub setactiveitem(InternalPage As ABMPage,active_id As String)
    
    Dim script As String = $"
        $('#${zids2}').val("${active_id}").trigger("change");
        $('#${ABMComp.ID}label').remove();
        $('#${ABMComp.ID}').prepend('<label style="cursor: pointer;color: #444;" id="${ABMComp.ID}label" for="${ABMComp.ID}" class="" activecolor="#03a9f4" inactivecolor="#616161">&nbsp;&nbsp;${zplaceholder}<span class="caret">&nbsp;</span></label>');   
    "$
    InternalPage.ws.Eval(script, Null)
    
End Sub

Sub getactiveitem(InternalPage As ABMPage) As String
    
    Dim script As String = $"
        return $('#${zids2}').val();
    "$
    Dim valor As Future =  InternalPage.ws.EvalWithResult(script, Null)
    InternalPage.ws.Flush
    
    Dim retornar As String = valor.Value
    
    Return retornar
    
End Sub

Sub additem(InternalPage As ABMPage, id As String, value As String)
    
    Dim script As String = $"   
        var data = {
        id: "${id}",
        text: "${value}"
        };
    
        var newOption = new Option(data.text, data.id, false, false );
        $('#${zids2}').append(newOption);
        $('#${zids2}').val(null)
        $('#${zids2}').trigger('change');               
    "$
    InternalPage.ws.Eval(script, Null)
    
End Sub

Sub visibility(InternalPage As ABMPage, visible As Boolean)
    
    If Not(visible) Then
        Dim script As String = $" $('#${ABMComp.ID}').hide();"$
    Else
        Dim script As String = $" $('#${ABMComp.ID}').show();"$
    End If
    
    InternalPage.ws.Eval(script, Null)
    
End Sub

Sub enabled(InternalPage As ABMPage, enable As Boolean)
    
    If enable Then
        Dim script As String = $" $('#${zids2}').prop("disabled", false);"$
    Else
        Dim script As String = $" $('#${zids2}').prop("disabled", true);"$
    End If
    
    InternalPage.ws.Eval(script, Null)
    
End Sub

Private Sub booleanjs(valor As Boolean) As String
    
    If valor Then
        Return "true"
    Else   
        Return "false"
    End If

End Sub

Sub setwidth(InternalPage As ABMPage, width As String)
    
    Dim script As String = $"
        $('#${ABMComp.ID}').css("width","${width}");
    "$
    InternalPage.ws.Eval(script, Null)
    
End Sub
 
Last edited:
Upvote 0

Joan Paz

Member
Work waiting the object, checking if available:

B4X:
' Class module
Sub Class_Globals
    'Dim ABM As ABMaterial
    Dim ABMComp As ABMCustomComponent
    Private ztags, zallowClear As Boolean
    Private zplaceholder As String
    Private zdata As String
    Public zid As String
    Public zids2 As String
    Private waitinterval As String = 100
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(InternalPage As ABMPage, id As String,tags As Boolean, allowclear As Boolean, placeholder As String, data As Map)
    ABMComp.Initialize("ABMComp", Me, InternalPage, id, "")
    ' the automatic events will be raised on the page e.g. if the id = "mycomp" then the event will be mycomp_Click(params as Map)
    ' future: we'll see if some other mechanisme is needed for non automatic events

    zid = id
    zids2= zid&"s2"
    ztags = tags
    zplaceholder = placeholder
    zallowClear = allowclear
        
    If data.Size > 0 Then   
        For Each k As String In data.Keys       
            zdata = zdata & $"{id:"${k}",text:"${data.Get(k)}"},"$
        Next
        zdata = zdata.SubString2(0,zdata.Length-1)
        zdata = $"[${zdata}]"$       
    End If

End Sub

' runs when an object is created for the first time. Expects a valid html string
' will get surrounded by a div automatically
' in the html file:
'<div ID="mycomp" class="">
'    <h1 ID="testh1">This Is a test</h1>
'</div>
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String   
    
    Return $"   
    <select id="${zids2}" style="width: 100%"></select>

    "$
    
End Sub

' Is useful to run some initalisation script.
Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String)
    'Dim script As String = $""$
    
    'InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
    ' flush not needed, it's done in the refresh method in the lib
    
    ''${booleanjs(ztags)}
    
    
'    $.when($('#${zids2}')).then((self) => { console.log(self);
'    builds2();
'   
'    });
    
    
    Dim script As String = $"
    
        function crears2() {
        
        console.log('funcion crear select2');
        
        $('#${zids2}').select2({
          dropdownParent: $('#${ABMComp.ID}'),
          allowClear: ${booleanjs(zallowClear)},
          placeholder: "${zplaceholder}",
          tags: ${booleanjs(ztags)},   
          data:${zdata}
        });

        $('#${zids2}').on('select2:select', function (e) {
            $('#${ABMComp.ID}label').remove();
            $('#${ABMComp.ID}').prepend('<label style="cursor: pointer;color: #444;" id="${ABMComp.ID}label" for="${ABMComp.ID}" class="" activecolor="#03a9f4" inactivecolor="#616161">&nbsp;&nbsp;${zplaceholder}<span class="caret">&nbsp;</span></label>');
            b4j_raiseEvent('${zid}_onchange', {'id':e.params.data.id,'text':e.params.data.text});
        });
        
        $('#${zids2}').on('select2:unselect', function (e) {
            $('#${ABMComp.ID}label').remove();
            b4j_raiseEvent('${zid}_onclear', {'id':e.params.data.id,'text':e.params.data.text});
        });
        

        $('#${zids2}').val("null").trigger("change");
    
        }
            
        function waitForElementToDisplay(selector, time) {
            if(document.querySelector(selector)!=null) {
                crears2();
                return;
            }
            else {
                setTimeout(function() {
                    waitForElementToDisplay(selector, time);
                }, time);
            }
        }
    
        waitForElementToDisplay('#${zids2}', ${waitinterval});
    
    "$
    
    InternalPage.ws.Eval(script,Null)
        
End Sub

' runs when a refresh is called
Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)
    ' use these methods to adjust the object
    ' ABM.HasClass
    ' ABM.AddClass
    ' ABM.RemoveClass
    
    ' ABM.AddHTML
    ' ABM.InsertHTMLAfter
    ' ABM.RemoveHTML
    
    ' ABM.GetProperty
    ' ABM.SetProperty
    ' ABM.RemoveProperty
    
    ' ABM.GetStyleProperty
    ' ABM.SetStyleProperty
    
    ' do some script stuff like you do in RunJavaScript
    
    Dim script As String = $"$('#${zids2}').trigger("change");"$
    InternalPage.ws.Eval(script, Null)
End Sub

' do the stuff needed when the object is removed
Sub ABMComp_CleanUp(InternalPage As ABMPage, internalID As String)
    
    Dim script As String = $"
    $('#${zids2}').select2('destroy');
    $('#${zids2}').off('select2:select');
    "$
    InternalPage.ws.Eval(script, Null)
    
End Sub

'            console.log('tiene data');
'            console.log($('#${zids2}').data('select2'));
'            console.log($('#select2-${zids2}-container'));

Sub setactiveitem(InternalPage As ABMPage,active_id As String)
    
    Dim script As String = $"
        
        ${waitfors2}
                
        function setValueS2(){
            console.log('colocando valor: ${active_id}');       
            $('#${zids2}').val("${active_id}").trigger("change");
            $('#${ABMComp.ID}label').remove();
            $('#${ABMComp.ID}').prepend('<label style="cursor: pointer;color: #444;" id="${ABMComp.ID}label" for="${ABMComp.ID}" class="" activecolor="#03a9f4" inactivecolor="#616161">&nbsp;&nbsp;${zplaceholder}<span class="caret">&nbsp;</span></label>');       
        }
        
        waitfors2('#${zids2}', ${waitinterval}, setValueS2);
        
    "$
    InternalPage.ws.Eval(script, Null)
    
End Sub

Sub getactiveitem(InternalPage As ABMPage) As String
    
    Dim script As String = $"
        return $('#${zids2}').val();
    "$
    Dim valor As Future =  InternalPage.ws.EvalWithResult(script, Null)
    InternalPage.ws.Flush
    
    Dim retornar As String = valor.Value
    
    Return retornar
    
End Sub

Sub additem(InternalPage As ABMPage, id As String, value As String)
    
    Dim script As String = $"
    
            ${waitfors2}
            
            function addValueS2(){       
                    var data = {
                    id: "${id}",
                    text: "${value}"
                    };
                
                    var newOption = new Option(data.text, data.id, false, false );
                    $('#${zids2}').append(newOption);
                    $('#${zids2}').val(null)
                    $('#${zids2}').trigger('change');   
            }
        
            waitfors2('#${zids2}', ${waitinterval}, addValueS2);
            
    "$
    InternalPage.ws.Eval(script, Null)
    
End Sub

Sub visibility(InternalPage As ABMPage, visible As Boolean)
    
    If Not(visible) Then
        Dim script As String = $"
        ${waitfors2}   
        waitfors2('#${zids2}', ${waitinterval}, function(){
            $('#${ABMComp.ID}').hide();
        });
        
        "$
    Else
        Dim script As String = $"         
        ${waitfors2}
        waitfors2('#${zids2}', ${waitinterval}, function(){
            $('#${ABMComp.ID}').show();
        });
        "$
    End If
    
    InternalPage.ws.Eval(script, Null)
    
End Sub

Sub enabled(InternalPage As ABMPage, enable As Boolean)
    
    If enable Then
        Dim script As String = $"
        ${waitfors2}   
        waitfors2('#${zids2}', ${waitinterval}, function(){
            $('#${zids2}').prop("disabled", false);
        });
        "$
    Else
        Dim script As String = $"
        ${waitfors2}   
        waitfors2('#${zids2}', ${waitinterval}, function(){
            $('#${zids2}').prop("disabled", true);
        });
        "$
    End If
    
    InternalPage.ws.Eval(script, Null)
    
End Sub

Private Sub booleanjs(valor As Boolean) As String
    
    If valor Then
        Return "true"
    Else   
        Return "false"
    End If

End Sub

Sub setwidth(InternalPage As ABMPage, width As String)
    
    Dim script As String = $"
        ${waitfors2}   
        waitfors2('#${zids2}', ${waitinterval}, function(){
        $('#${ABMComp.ID}').css("width","${width}");
        });
    "$
    InternalPage.ws.Eval(script, Null)
    
End Sub

Sub waitfors2 As String
    
    Return $"           
            function waitfors2(selector, time, funcionParametro) {
            if($(selector).data('select2')) {
                funcionParametro();
                return;
            }
            else {
                setTimeout(function() {
                    waitfors2(selector, time, funcionParametro);
                }, time);
            }
            }"$
    
End Sub
 
Upvote 0
Top