B4J Tutorial [ABMaterial]: Creating a Sign In Modal Dialog with Options: Part 1

Discussion in 'B4J Tutorials' started by Mashiane, Feb 17, 2018.

  1. Mashiane

    Mashiane Expert Licensed User

    Well



    I wanted to create a modal dialog (ABMModalSheet), that will have options for 1. Forgot Password and 2. Not a Member Yet to 1. enable moving to another screen if user forgot the password and 2. enable a user to register by moving to another screen that will prompt the user to register.

    In this part of the tutorial we will work with the Sign In screen shown in the gif above. As you have noted, we have a logo, a small description of what we need to do here, an email and a password prompt, a label for forgot password and another for "not a member yet" and then a "Next" button to do whatever is necessary after that.


    ABMModalSheet Definition:

    An ABMModalSheet component is like a mini ABMPage helper, but it pops up over the existing page. It has two ABMContainers, one that makes up the header and one for the footer section, so you can use everyting an ABMContainer can.

    ABMModalSheets and its components have to be added to the page in the PageBuild() method. You can the later load the sheet and modify the content before you open it."

    #source HelperModalSheetPage.bas file (Demo.b4j ABMaterial 4.03)


    Another container actually exists, the .Content one which we use for this exercise as the .Footer and .Header are not used here.

    Goal

    A user is expected to enter their email and password, these are verified against a database table for existence, if they dont exist, a prompt telling the user is provided.

    • The email and password are compulsory.
    • A user can click the "Forgot Password" label, this will take the user to another screen to process that action. This we will discuss in Part 2
    • A user can click the "Not a Member yet" label, this will take the user to another screen to process that action. This we will discuss in Part 3
    • A notification is being used to indicate any errors on the page. This uses a red theme.
    • The modal sheet is not dismissable i.e a user needs to perform an action to close it.
    Reproduction

    As seen above, this modal sheet has an option for Forgot Password and Not a Member yet besides the sign in functionality. The forgot password label is right aligned whilst the Not a Member yet label is centered on the row. This is achieved with the use of cell theming.

    1. Create the modal sheet

    The name of our modal sheet is msLogin and here we difine its structure and its contents.

    Code:
    Private Sub msLoginBuild() As ABMModalSheet
        
    Dim msLogin As ABMModalSheet
        msLogin.Initialize(
    page"msLogin"False, ABM.MODALSHEET_TYPE_NORMAL, "ms")
        msLogin.Size = ABM.MODALSHEET_SIZE_NORMAL
        msLogin.IsDismissible = 
    False
        msLogin.IsTextSelectable = 
    True
        msLogin.Content.AddRows(
    1,True,"").AddCells12(1"")
        msLogin.Content.AddRows(
    1,True,"").AddCellsOSMPV(10001212120000, ABM.VISIBILITY_ALL, "")
        msLogin.Content.AddRows(
    1,True,"").AddCellsOSMPV(100012121200100, ABM.VISIBILITY_ALL, "")
        msLogin.Content.AddRows(
    1,True,"").AddCellsOSMPV(10001212120000, ABM.VISIBILITY_ALL, "")
        msLogin.Content.AddRows(
    1,True,"").AddCellsOSMPV(10001212120000, ABM.VISIBILITY_ALL, "")
        msLogin.Content.AddRows(
    1,True,"").AddCellsOSMPV(100012121200010, ABM.VISIBILITY_ALL, "")
        msLogin.Content.AddRows(
    1,True,"").AddCellsOSMPV(1000121212001010, ABM.VISIBILITY_ALL, "")
        msLogin.Content.AddRows(
    1,True,"").AddCellsOSMPV(10001212120000, ABM.VISIBILITY_ALL, "")
        msLogin.Header.BuildGrid  
    'IMPORTANT once you loaded the complete grid AND before you start adding components
        msLogin.Content.BuildGrid 'IMPORTANT once you loaded the complete grid AND before you start adding components
        msLogin.Footer.BuildGrid  'IMPORTANT once you loaded the complete grid AND before you start adding components
        'Add components to ModalSheet
        Dim lbllblCreateAccount As ABMLabel
        lbllblCreateAccount.Initialize(
    page"lbllblCreateAccount"$"{C:#CC9966}{I}{B}Not a Member yet?{/B}{/I}{/C}"$, ABM.SIZE_PARAGRAPH, False"centercontent")
        lbllblCreateAccount.Clickable = 
    True
        lbllblCreateAccount.SetCursor(ABM.CURSOR_POINTING)
        lbllblCreateAccount.supportemoji = 
    False
        msLogin.Content.Cell(
    8,1).AddComponent(lbllblCreateAccount)
        msLogin.Content.Cell(
    8,1).UseTheme("centercontent")
        
    Dim txtemail As ABMInput
        txtemail.Initialize(
    page"txtemail", ABM.INPUT_EMAIL, "Email Address"False"")
        txtemail.Tag = 
    "txtemail"
        msLogin.Content.Cell(
    4,1).AddComponent(txtemail)
        
    Dim txtpassword As ABMInput
        txtpassword.Initialize(
    page"txtpassword", ABM.INPUT_PASSWORD, "Password"False"")
        txtpassword.Tag = 
    "txtpassword"
        msLogin.Content.Cell(
    5,1).AddComponent(txtpassword)
        
    Dim btnNext As ABMButton
        btnNext.InitializeRaised(
    page"btnNext""""""Next""")
        btnNext.Tag = 
    "btnNext"
        btnNext.UseFullCellWidth = 
    True
        btnNext.Size = ABM.BUTTONSIZE_NORMAL
        msLogin.Content.Cell(
    7,1).AddComponent(btnNext)
        
    Dim lblheader As ABMLabel
        lblheader.Initialize(
    page"lblheader"$"{B}To continue, let's verify it's you{/B}"$, ABM.SIZE_PARAGRAPH, False"")
        lblheader.supportemoji = 
    False
        msLogin.Content.Cell(
    3,1).AddComponent(lblheader)
        
    Dim lbllblForgotPassword As ABMLabel
        lbllblForgotPassword.Initialize(
    page"lbllblForgotPassword"$"{C:#CC9966}{I}Forgot Password?{/I}{/C}"$, ABM.SIZE_PARAGRAPH, False"rightlabel")
        lbllblForgotPassword.Clickable = 
    True
        lbllblForgotPassword.SetCursor(ABM.CURSOR_POINTING)
        lbllblForgotPassword.istextselectable = 
    True
        lbllblForgotPassword.supportemoji = 
    False
        msLogin.Content.Cell(
    6,1).AddComponent(lbllblForgotPassword)
        
    Dim imglogo As ABMImage
        imglogo.Initialize(
    page"imglogo""../images/logo.png?"DateTime.Now, 1)
        imglogo.Tag = 
    "imglogo"
        imglogo.IsResponsive = 
    False
        imglogo.IsCircular = 
    False
        imglogo.IsClickable = 
    False
        imglogo.IsMaterialBoxed = 
    False
        msLogin.Content.Cell(
    2,1).AddComponent(imglogo)
        
    Return msLogin
    End Sub
    Some things to note. I have used the AddRows and the AddCellsOSMPV method here to create my modal sheet rows, that is just my preference and you can use whatever methods you deem fit to achieve the same results. All my columns are 12 in size across all devices. Whilst there is no content on the .Header and .Footer, I have opted to include the .BuildGrid methods for those, these can be commented out. I forget stuff so for me this is a pre-caution.

    The label for "Not a Member yet" is centered, the theme "centercontent" has been used, this is defined as

    1.1. Centering the label

    Code:
    MyTheme.AddCellTheme("centercontent")
        MyTheme.Cell(
    "centercontent").align = ABM.CELL_ALIGN_CENTER
    As noted above, I did NOT actually follow a sequential RC in adding the components. I started with 8,1 then up to 2,1. This might be confusing, but just to think of it, it does not matter I think because after all ABMaterial places your components where they are supposed to be. Cool stuff, but, going forward, its really better to follow a sequential approach as it helps in following your code, I think.

    1.2. Right align the label

    Code:
    MyTheme.AddLabelTheme("rightlabel")
        MyTheme.Label(
    "rightlabel").align = ABM.INPUT_TEXTALIGN_RIGHT
    1.3. Call the msLoginBuild on BuildPage

    Code:
    page.AddModalSheetTemplate(msLoginBuild)
    This call above should be added to the BuildPage method.

    1.4 Show the modal sheet

    As my page has only this modal sheet, I need this modal sheet to appear as soon as the page is shown. I have decided to put that call on the ConnectPage method of my page.

    Code:
    page.ShowModalSheet("msLogin")
    Getting the Sign In details & Validating them

    In this next step, we need a way to get the contents from the modal sheet, check if they are entered i.e. not blank. To do this I have created two methods, to get the details as a map and then run that map against a fixed validating method, these are msLoginGetContents and msLoginValidate respectively.

    Code:
    'Get the contents of the modal sheet input components and save to a map
    Sub msLoginGetContents() As Map
        
    Dim pMap As Map
        pMap.Initialize
        
    Dim msLogin As ABMModalSheet
        msLogin = 
    page.ModalSheet("msLogin")
        
    Dim txtemail As ABMInput = msLogin.Content.Component("txtemail")
        
    Dim txtpassword As ABMInput = msLogin.Content.Component("txtpassword")
        pMap.put(
    "email", txtemail.Text)
        pMap.put(
    "password", txtpassword.Text)
        
    Return pMap
    End Sub
    'Get the contents of the modal sheet from GetContents and check validity
    Sub msLoginValidate(gMap As MapAs Boolean
        
    Dim msLogin As ABMModalSheet
        msLogin = 
    page.ModalSheet("msLogin")
        
    Dim stxtemail As String
        stxtemail = gMap.get(
    "email")
        
    If stxtemail = "null" Then stxtemail = ""
        
    If stxtemail.Length = 0 Then
            ABMShared.Warn(
    page,"Email Address cannot be blank. Please enter a value.")
            
    Dim txtemail As ABMInput = msLogin.Content.Component("txtemail")
            txtemail.SetFocus
            
    Return False
        
    End If
        
    Dim stxtpassword As String
        stxtpassword = gMap.get(
    "password")
        
    If stxtpassword = "null" Then stxtpassword = ""
        
    If stxtpassword.Length = 0 Then
            ABMShared.Warn(
    page,"Password cannot be blank. Please enter a value.")
            
    Dim txtpassword As ABMInput = msLogin.Content.Component("txtpassword")
            txtpassword.SetFocus
            
    Return False
        
    End If
        
    Return True
    End Sub
    The validation method is such that when an email or password are not entered, the focus is brought back to the needed component. As noted above, this calls an ABMShared.Warn method. I have defined that as a simple toast message below.

    Code:
    Sub Warn(page As ABMPage, msg As String)
        toastCount = toastCount + 
    1
        
    page.ShowToast("toast" & toastCount, "toastred"$"${msg}"$3000False)
    End Sub
    The toast theme, defined as..

    Code:
    MyTheme.AddToastTheme("toastred")
        MyTheme.Toast(
    "toastred").actionforecolorintensity = ABM.INTENSITY_NORMAL
        MyTheme.Toast(
    "toastred").backcolor = ABM.COLOR_RED
        MyTheme.Toast(
    "toastred").forecolorintensity = ABM.INTENSITY_NORMAL
        MyTheme.Toast(
    "toastred").actionforecolor = ABM.COLOR_BLACK
        MyTheme.Toast(
    "toastred").rounded = True
        MyTheme.Toast(
    "toastred").forecolor = ABM.COLOR_WHITE
        MyTheme.Toast(
    "toastred").backcolorintensity = ABM.INTENSITY_NORMAL
    The email and password are read as soon as the "Next" button is clicked, thus to achieve that we need to call a method to do the checks. This method will 1. get the entered details, 2. validate them 3. check them against a database table and process the next sequence of events.

    For this I have defined a login call.

    Code:
    Private Sub msLoginSignIn() As Boolean
        
    'define a map to hold the form contents
        Dim m As Map
        
    'read the file contents to a map
        m = msLoginGetContents
        
    'validate the form contents where required
        If msLoginValidate(m) = False Then
            
    Return False
        
    End If
        
    'the form contents are ok, continue with the sign in process
        'define the search criteria, fields must equal
        Dim w As Map
        
    Dim nk As String
        
    Dim nv As String
        w.Initialize
        
    For Each strKey As String In m.Keys
            nv = m.Get(strKey)
            nk = strKey & 
    "="
            w.put(nk, nv)
        
    Next
        
    'Get connection from current pool if MySQL/MSSQL
        Dim jSQL As SQL = ABMShared.SQLGet
        
    Dim UserMap As Map = ABMShared.SQLSelectRecordWhereMap(jSQL,"users", w)
        
    If UserMap.IsInitialized = False Then
            ABMShared.Warn(
    page,"The Sign In credentials you have provided are incorrect. Please check them and try to sign in again.")
            ws.Session.SetAttribute(
    "IsAuthorized""")
            
    Return False
        
    End If
        
    Dim uactive As String = UserMap.get("useractive")
        ws.Session.SetAttribute(
    "UserActive", uactive)
        
    If uactive = 0 Then
            ABMShared.Warn(
    page,"Your Profile is currently in-active, please contact the App Administrator.")
            
    Return False
        
    End If
        
    Dim uemail As String = UserMap.get("email")
        ws.Session.SetAttribute(
    "UserEmail", uemail)
        
    Dim uname As String = UserMap.get("username")
        ws.Session.SetAttribute(
    "authName", uname)
        
    Dim uid As String = UserMap.get("id")
        ws.Session.SetAttribute(
    "UserID", uid)
        
    Dim utype As String = UserMap.get("groupid")
        ws.Session.SetAttribute(
    "UserType", utype)
        ws.Session.SetAttribute(
    "IsAuthorized""true")
        ws.Session.SetAttribute(
    "authType""local")
        
    'Build the permissions
        ABMShared.PermissionsL.Initialize
        ABMShared.Permissions.Initialize
        ABMShared.PermissionsL = ABMShared.SQLExecuteMaps(jSQL,
    "select * from GroupPermissions where groupid = ?"Array As String(utype))
        
    For Each permission As Map In ABMShared.PermissionsL
            
    Dim spageName As String = permission.get("pagename")
            spageName = spageName.tolowercase
            ABMShared.Permissions.put(spageName,permission)
        
    Next
        
    'Close the connection to the database
        ABMShared.SQLClose(jSQL)
        
    Return True
    End Sub
    From the code above, a lot of work happens. We get the contents, run a select where?? call to check the details against a database and if these dont exist, tell the user with a toast. if the details are obtained, we read the group permissions that this user belongs to and then save the details to a session variable.

    As the focus of this tutorial is the UX, you can refer to this tutorial I wrote about groups permissions etc etc.

    The next button is clicked, thus, its code should be simple as..

    Code:
    'An ABMButton has been clicked
    Sub btnNext_Clicked(Target As String)
        
    If msLoginSignIn = False Then Return
        ABMShared.NavigateToPage(ws, ABMPageId, 
    "../frmMainMenu/frmMainMenu.html")
    End Sub
    If the user is validated, move to the next page.

    The user forgot the password (Part 2)

    When a user clicks this label, the user is supposed to be prompted of the email address, this should be validated, checked against the database, the user details should be read and these should be emailed to the user. For now, we just go to that page..

    Code:
    'The label has been clicked
    Sub lbllblForgotPassword_Clicked(Target As String)
        ABMShared.NavigateToPage(ws, ABMPageId,
    "../frmForgotPassword/frmForgotPassword.html")
    End Sub
    The user is not a member yet (Part 3)

    When a user clicks this label, the user is supposed to be sent to another page to register, these user details should be read, the compulsory items validated and then if the user does not already exist, a new record should be created in the database.

    Code:
    'The label has been clicked
    Sub lbllblCreateAccount_Clicked(Target As String)
        ABMShared.NavigateToPage(ws, ABMPageId,
    "../frmCreateAccount/frmCreateAccount.html")
    End Sub
    Disclaimer:

    There are different ways to achieve the same thing and this is just my own method of doing it and its not cut in stone. I could be wrong and there might be stuff I have left out, I'm not an expert and learning as everybody else. #SharingTheGoodness

    HappyCoding... ;)
     

    Attached Files:

    Last edited: Feb 23, 2018
  2. alwaysbusy

    alwaysbusy Expert Licensed User

    Harris, joulongleu and Mashiane like this.
  3. Mashiane

    Mashiane Expert Licensed User

    Thanks @alwaysbusy

    Have replaced the gif with a youtube. Much better actually.
     
    amaxco, joulongleu and alwaysbusy like this.
  4. Mashiane

    Mashiane Expert Licensed User

    Part 1,2,2.1 and 3 of this tutorial is now complete. Hope you enjoyed it.

    Coming Soon: Activating a user's account

    When a user Signs Up, on success, their accounts are in-active and thus they will not be able to sign in until their accounts are active. When completed, a user is supposed to get an email with a link that they need to click on and activate their account. In my dream world this should execute a php script on the server, activating the account.

    This in essence does two things, verifies their email address and also enables them to use TeenCoach. I think I saw an article about getting query string values somewhere here and instead of a php script, will follow that approach.

    Any ideas??
     
    Johan Hormaza likes this.
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