B4J Question [ABMaterial] Creating An Autocomplet/Typeahead search control?

Discussion in 'B4J Questions' started by keirS, Sep 13, 2019.

  1. keirS

    keirS Well-Known Member Licensed User

    I am newcomer to ABMaterial. I have previously used ASP.NET for Web App's. What I am looking to achieve is an autocomplete component that loads results from a database on the server side. For a small data set I could do this with ABMInput and use the AddAutoComplete. However i am not dealing with a small data set (100K + records)

    The functionality I am looking to achieve is the user enters the first letter of the search and a function is called on the ABMPage that gets the value of the control, runs a query on the DB and returns JSON to the calling Javascript to generate the list for the autocomplete. This JQuery control: http://www.runningcoder.org/jquerytypeahead/demo/ is the sort of functionality I am looking to achieve. In particular the User V1 demo.

    I pretty much understand how this sort of thing works using ASP.NET and AJAX but I can't really work out how this would work in ABM. Is there a JavaScript function in core.4.30.min.js that can call a B4J function in an ABMPage? If not how would be best to approach this?
     
  2. Harris

    Harris Well-Known Member Licensed User

    If the search is expected to be used often on the page, load the contents of the table in Connect() into list, map, whatever - and use it from there. That way you won't have to go back to the server on every new character.
    My 2 pesos...
     
    emexes likes this.
  3. OliverA

    OliverA Expert Licensed User

    b4j_raiseEvent(methodNameToCallInB4J, JSONStructureThatBecomesAMapParameterForTheMethodCalled)

    Two ways calling your method from JavaScript
    1) Just call your method directly
    b4j_raiseEvent('call_myownmethod', {"parameter1": "Hello World", "parameter2" : 42})
    2) Go through ABM's Page_ParseEvent method
    b4j_raiseEvent('Page_ParseEvent', {"eventname" : "call_myownmethod", "eventparams" : "parameter1,parameter2", "parameter1": "Hello World", "parameter2" : 42})

    In ABM
    Code:
    Public Sub call_myownmethod(Params as Map)
       
    Log(Params.Get("parameter1")
       
    Log(Params.Get("parameter2")
    End Sub
    Edit: Typo in JavaScript (missing ending parenthesis)
     
    keirS likes this.
  4. keirS

    keirS Well-Known Member Licensed User

    I am struggling with this. I have a BJS class with inline Javascript in it.
    Code:
    'Class module
    Sub Class_Globals
        
    ' use Public or Dim if you want to share this variable over ALL B4JS classes
        ' use Private if only within this class
        Public ABM As ABMaterial 'ignore, just to access the constants
        Public Page As ABMPage 'ignore, just to be able to run ABMPage B4JS functions
     
     
    End Sub
    Public Sub Initalize
        InitializeB4JS
    End Sub
    'Initializes the object. You can NOT add parameters to this method.
    'MUST be called InitializeB4JS is automatically called when using this class
    Public Sub InitializeB4JS
     
    End Sub
    #if JAVASCRIPT
    function bindkeyupToB4J(htmlElement, b4jSub) {
          $(htmlElement).keyup(function() {
              var elementValue = $(htmlElement).val();
              b4j_raiseEvent(b4jSub, {"inputValue": elementValue})
              });
     }
            
    #End If

    Then in my page I have.

    Code:
    Sub mykepress(M As Map)
        
    Log("M")
    End Sub

    public Sub ConnectPage()        
         
    Dim kp As testkeypress ' B4JS Class
         testkeypress.Initialize
      
        
    '    connecting the navigation bar
        ' ABMShared.ConnectNavigationBar(page)
        Dim testinput As ABMInput
        testinput.Initialize(
    page"testinput", ABM.INPUT_TEXT, "test"False"input")
        
    page.Cell(1,2).AddComponent(testinput)
      
     
        
    page.B4JSRunInlineJavascriptMethod("bindkeyupToB4J",Array("#testinput","mykeypress")) ' run JScript
     
     
        
    ' refresh the page
        page.Refresh
     
        
    ' Tell the browser we finished loading
        page.FinishedLoading
        
    ' restoring the navigation bar position
        page.RestoreNavigationBarPosition
    End Sub
    Which doesn't work because my JS function is not included in the Javascript generated for the page or in the page itself. So how do I get ABMaterial to include the Javascript?
     
    Last edited: Sep 17, 2019 at 3:50 PM
  5. Anser

    Anser Well-Known Member Licensed User

    How about adding the follwing line in the Sub BuildPage()
    Code:
    page.AddExtraJavaScriptFile()
    Its just an idea
     
    keirS likes this.
  6. alwaysbusy

    alwaysbusy Expert Licensed User

    When I first tried your example, I had the same. I then created a new ABM B4JS class (Project - Add New Module - Class Module - ABM B4JS, copied your code in it at then it did generate. I honestly have no idea why it didn't the first time.

    Couple of notes:
    1. First, do not add an initialize method in the B4JS class. My B4JSBinder class looks like this:
    Code:
    'Class module
    Sub Class_Globals
       
    ' use Public or Dim if you want to share this variable over ALL B4JS classes
       ' use Private if only within this class
       Public ABM As ABMaterial 'ignore, just to access the constants
       Public Page As ABMPage 'ignore, just to be able to run ABMPage B4JS functions

    End Sub

    'Initializes the object. You can NOT add parameters to this method.
    'MUST be called InitializeB4JS is automatically called when using this class
    Public Sub InitializeB4JS
    End Sub

    #if JAVASCRIPT
    function bindkeyupToB4J(htmlElement, b4jSub) {
          $(htmlElement).keyup(function() {
              var elementValue = $(htmlElement).val();
              b4j_raiseEvent(b4jSub, {"inputValue": elementValue})
              });
     }       
    #End If
    2. You must run the page.B4JSRunInlineJavascriptMethod AFTER page.Refresh. If you run it before, the Input is not yet added to the page so the javascript method does nothing. Also use .ToLowerCase as the generated html/js IDs will be lowercased too.
    Code:
    ...
       
    Dim InpLat1 As ABMInput
       InpLat1.Initialize(
    page"inpLat1", ABM.INPUT_TEXT, "From Latitude"False , "input")
       
    page.Cell(3,1).AddComponent(InpLat1)

       
    ' refresh the page
       page.Refresh
       
    ' Tell the browser we finished loading
       page.FinishedLoading
       
    ' restoring the navigation bar position
       page.RestoreNavigationBarPosition
       
       
    ' now you can run this method as the InpLat1 component is added   
       page.B4JSRunInlineJavascriptMethod("bindkeyupToB4J"Array("#inpLat1".ToLowerCase, "inpLat1_MyKeyUp".ToLowerCase))
    End Sub
    Now I receive on my page in Sub InpLat1_MyKeyUp(m As Map):
    Code:
    inputValue: 1
    inputValue: 
    12
    inputValue: 
    123
    inputValue: 
    1234
    inputValue: 
    12345
    inputValue: 
    123456
    inputValue: 
    1234567
    inputValue: 
    12345678
    inputValue: 
    123456789
    Note this is just to demonstrate how B4JS works, but with just ABM, you can archive the same using the Changed event. By default this event is off (because going back and forth to the server for each key press on the browser side is bad: it will stress your server traffic enormously). But if you really, really, really want it, you can activate it with:
    Code:
    Dim InpLat1 As ABMInput
    InpLat1.Initialize(
    page"inpLat1", ABM.INPUT_TEXT, "From Latitude"False , "input")
    InpLat1.RaiseChangedEvent = 
    True ' <-------------------
    page.Cell(3,1).AddComponent(InpLat1)
    ...
    Sub InpLat1_Changed(value As String)
       
    Log(value)
    End Sub
    Alain
     
    Johan Hormaza and keirS like this.
  7. keirS

    keirS Well-Known Member Licensed User

    I only need to capture the first key press. What I am trying to do is limit the size of the data downloaded by the client. If I have DB table with 100,000 records in and I have an even distribution of entries starting with A-Z then I only need to push 4000 records to client instead of pushing the whole lot. What I eventually hope to do is cache the data on the client although that's rather getting ahead of myself.
     
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