B4J Tutorial BANano for Dummies by Example

Mashiane

Expert
Licensed User
Lesson 16: Let's create a simple app to record our tasks using everything we have learned so far. This is:

1. Creating elements on a page
2. Setting properties and classes to elements
3. Linking events to elements
4. Using JQuery as an additional library in our app.

We will also add some additional things to make our app work, we will demonstrate how to use LocalStorage to save and retrieve our tasks.

Lets build the skeleton... its not too much eye candy at the moment. What we are NOT doing is to use a framework here because one can choose their own framework to use. At the end, the principle of creating websites/webapps is the same, they are all HTML elements.

TaskAtHand.gif


Preparations:

1. We changed our page header to that it now shows Task@Hand
2. We took all our inline css and saved it in a file and added this file link to our header.
3. We added JQuery as a dependency for the project.

B4X:
'the title of the page
    BANano.Header.Title = "Task@Hand"
    'add our own css
    BANano.Header.AddCSSFile("taskathand.css")
    'add jquery
    BANano.Header.AddJavascriptFile("jquery-3.4.1.min.js")
We then went on and created the skeleton of our page. This time, to attach an event to an element, we have used the On keyword of the BANanoElement.

B4X:
Sub Show
    'initialize jquery
    JQuery.Initialize
    'call the javascript method to ensure all variables are defined
    JQuery.UseStrict
   
    'get the body element of the page
    body = BANano.GetElement("#body")
    'clear the body
    body.Empty
    'define the body of the app
    body.Append($"<div id="app">
<header>Task@Hand </header>
<div id="main">
<div id="add-task">
<label for="new-task-name">Add a task</label>
<input type="text" id="new-task-name"
title="Enter a task name" placeholder="Enter a task name"/>
</div>
<ul id="task-list">
</ul>
</div>
<footer>
</footer>
</div>"$)
   
    'define the version
    version = "v1.0"
    '
    JQuery.Append("#app>header", version)
    setStatus("Ready")
   
    'get the element to attach event to
    Dim taskName As BANanoElement = BANano.GetElement("#new-task-name")
    'attach the event
    taskName.On("keypress", Me, "task_keypress")
   
End Sub

'fires when a keypress happens on task
Sub task_keypress(e As BANanoEvent)
    Log(e)
End Sub

Sub setStatus(message As String)
    JQuery.SetText("#app>footer", message)
End Sub
What we want to achieve is that as soon as the user, presses Enter key, the task is added to the list and the focus set on the task name element.

B4X:
taskName.On("keypress", Me, "task_keypress")
What we are saying is, On a 'keypress' event, in this code module (ME), execute a method called 'task_keypress'

As you noted in the GIF, each time we pressed a key in the textbox, console log recorded our keypress.

B4X:
Sub task_keypress(e As BANanoEvent)
    Log(e)
End Sub
 

Mashiane

Expert
Licensed User
Lesson 16: Continued

TaskAtHand1.gif


1. As soon as the user has entered a task, add it to the task list by calling addTask

B4X:
'fires when a keypress happens on task
Sub task_keypress(e As BANanoEvent)
    'if we press enter
    If e.CharCode = 13 Then
        addTask
        'cancel default operation/bubbling
        Return False
    End If
    'set the focus to the task name element
    JQuery.Focus("#new-task-name")
End Sub
2. In addTask, the contents of the input text are read. I have written equivalents of this in both jquery and BANano, so we can just comment out the jquery for .GetValue and .SetValue and use BANano built in methods.

B4X:
Sub addTask
    'get the task name
    '*** jquery : var tskName = $("#new-task-name").val();
    '*** BANano : Dim tskName As Object = BANano.GetElement("#new-task-name").GetValue
    Dim tskName As String = JQuery.GetValue("#new-task-name")
    If tskName = "" Then Return
    addTaskElement(tskName)
    'clear the contents of the textvalue and set focus
    '*** jquery : $("#new-task-name").val("");
    '*** jquery : $("#new-task-name").focus();
    '*** BANAno : BANano.GetElement("#new-task-name").SetValue("")
    JQuery.SetValue("#new-task-name", "")
    JQuery.Focus("#new-task-name")
End Sub
When the contents are read, they are added to the task list by calling addTaskElement. When that is done, the input text is cleared and then the focus moved to the input element.

B4X:
Sub addTaskElement(taskName As String)
    '*** BANANO : BANano.GetElement("#task-list").Append($"<li>${taskName}</li>"$)
    'var $task = $("<li></li>");
    ''$task.text(taskName);
    '$("#task-list").append($task);
 
    Dim task As BANanoObject = JQuery.createElement("li")
    JQuery.SetTextBO(task, taskName)
    JQuery.Append("#task-list", task)
End Sub
IMPORTANT:

It could be really confusing doing these mandane tasks using JQuery whilst BANano has a potent system of doing so. So, for anything that BANano can do, rather use it than using JQuery.

To summarise, this was taking you through the process of calling jquery within BANano.

1. We declared JQuery and initialized it.

B4X:
Public JQuery As BANanoObject
B4X:
JQuery.Initialize("$")
2. We showed how to call the val method to set a value to an element.

B4X:
JQuery.Selector(elID).RunMethod("val", val)
3. We showed how to get a value from an element

B4X:
Dim obj As Object = JQuery.Selector(elID).RunMethod("val", Null).result
4. We showed how to append text using JQuery

B4X:
JQuery.Selector(elID).RunMethod("append", text)
5. We called the focus method..

B4X:
JQuery.Selector(elID).RunMethod("focus", Null)
6. We also called createElement by using a LI (list item). We created a method to do that.

B4X:
'create an element
Sub createElement(tag As String) As BANanoObject
    Dim markup As String = $"<${tag}></${tag}>"$
    Dim newEL As BANanoObject = JQuery.Selector(markup)
    Return newEL
End Sub
IMPORTANT:

Most of what one will do when writing BANano code is to write javascript / jquery code using BANano, thus understanding the nitty gritties of BANano and how it does things will help.

If you explore the BANanoElement class in BANano, it has enough methods to perform the tasks that we did with JQuery here. So use JQuery sparringly as it just bloats your app with functions that already exists in BANano. For those libraries that have it that you might want to wrap for BANano, using javascript and then call .RunJavaScriptMethod is better. But then again, use your discretion as nothing is limited. #

I have learned that there are just some things that are just left as javascript without having to convert them to BANano code. Why? Because BANano transpiles B4J code to Javascript, so 10 lines of javascript are better than 50 lines of B4J in BANano in some cases. Let's think about it.

OPTION 1
Copy the following code to your code and use RunJavaScriptMethod.

B4X:
BANano.RunJavascriptMethod("drawOnCanvas", Null)
B4X:
#if javascript
function drawOnCanvas() {
    ctx = document.getElementById('mycanvas').getContext('2d');
    ctx.fillStyle = "#E34C26";
    ctx.beginPath();
    ctx.moveTo(39, 250);
    ctx.lineTo(17, 0);
    ctx.lineTo(262, 0);
    ctx.lineTo(239, 250);
    ctx.lineTo(139, 278);
    ctx.closePath();
    ctx.fill();
}
#End If
OPTION 2
Writing BANano Code for the same thing. Yes you can use both methods in your project.

B4X:
Sub drawOnCanvas
    'var ctx = document.getElementById('mycanvas').getContext('2d');
    Dim doc As BANanoObject = BANano.Window.GetField("document")
    Dim mycanvas As BANanoObject = doc.RunMethod("getElementById", Array("mycanvas"))
    Dim ctx As BANanoObject = mycanvas.RunMethod("getContext", Array("2d"))
    '
    'ctx.fillStyle = "#E34C26";
    ctx.SetField("fillStyle", "#E34C26")
    'ctx.beginPath();
    ctx.RunMethod("beginPath", Null)
    'ctx.moveTo(39, 250);
    ctx.RunMethod("moveTo", Array(39, 250))
    'ctx.lineTo(17, 0);
    ctx.RunMethod("lineTo", Array(17, 0))
    'ctx.lineTo(262, 0);
    ctx.RunMethod("lineTo", Array(262, 0))
    'ctx.lineTo(239, 250);
    ctx.RunMethod("lineTo", Array(239, 250))
    'ctx.lineTo(139, 278);
    ctx.RunMethod("lineTo", Array(139, 278))
    'ctx.closePath();
    ctx.RunMethod("closePath", Null)
    'ctx.fill();
    ctx.RunMethod("fill", Null)
End Sub
You decide and yes, you can CHAIN methods with BANano.
 
Last edited:

Mashiane

Expert
Licensed User
Lesson 16: Another Version

We decided to do an extra part of lesson 16 using BANano and Javascript all the way. For this we needed the focus method.

B4X:
Sub Focus(elID As String)
'document.getElementById("???").focus();
    BANano.Window.GetField("document").RunMethod("getElementById", Array(elID)).RunMethod("focus", Null)
End Sub
So that we can set the focus to the task element we need.

In the end, you have a more simpler and shorter code base.

B4X:
Sub addTask
    'get the task name
    Dim tskName As String = BANano.GetElement("#new-task-name").GetValue
    If tskName = "" Then Return
    addTaskElement(tskName)
    BANano.GetElement("#new-task-name").SetValue("")
    Focus("#new-task-name")
End Sub
'
Sub addTaskElement(taskName As String)
    BANano.GetElement("#task-list").Append($"<li>${taskName}</li>"$)
End Sub

Sub setStatus(message As String)
    BANano.GetElement("#app>footer").SetText(message)
End Sub
 

Mashiane

Expert
Licensed User
Lesson 17: We showcase a task manager built with BANano + Jquery

This lesson is more about the logic and functionality than the UX / used libraries.


1. Add a task
2. Update a task
3. Delete a task
4. Move a task up
5. Move a task down
6. Save tasks to LocalStorage
7. Load tasks from LocalStorage
8. Adding buttons inside a list
9. Adding events to items before they get added to UX.
10. Detecting events on button clicks for elements without ids by using BANanoEvent

As we are not using any framework, we have not styled the UX for this.

TaskAtHand2.gif


Get lesson content here,, https://github.com/Mashiane/BANano4Dummies

What this meant...

Our sub to add the tasks had to be updated to ensure that we have X, E, U and D buttons inside the list. Whenever X,E,U,D is clicked, we needed to trap this and fire the right event.

In creating each BANAnoElement below, we called JQuery and converted the object from Jquery to a BANanoElement. We are doing this because at time of creation, the element is not yet added to the body of the page and it also does not have an identifier.

B4X:
Sub addTaskElement(taskName As String)
    'delete button segment
    Dim delete As BANanoElement = JQuery.createElement($"<button title="Delete" class='delete'>X</button>"$)
    delete.On("click", Me, "task_delete")
    'edit button segment
    Dim edit As BANanoElement = JQuery.createElement($"<button title="Edit" class='edit'>E</button>"$)
    edit.On("click", Me, "task_edit")
    'move up button
    Dim moveUp As BANanoElement = JQuery.createElement($"<button title="Up" class='move-up'>U</button>"$)
    moveUp.On("click", Me, "task_up")
    'move down button
    Dim moveDown As BANanoElement = JQuery.createElement($"<button title="Down" class='move-down'>D</button>"$)
    moveDown.On("click", Me, "task_down")
    'span to show the item
    Dim span As BANanoElement = JQuery.createElement($"<span class='task-name'> ${taskName}</span>"$)
    'create an empty list item
    Dim task As BANanoElement = JQuery.createElement($"<li class="task"></li>"$)
    'join other elements
    JQuery.AppendMulti(task, Array(delete, edit, moveUp, moveDown, span))
    'add to the list
    JQuery.Append("#task-list", BANano.ToObject(task))
End Sub
.AppendMulti, adds all the children to the parent task element using JQuery. We then append everything to the 'task-list' element.

In this case use the .On method to add an event to the button. This is not the only method to do this. We might hav just created a template html for all of this and just assigned events to it later.

The last item in the <li></li> item is the text of the task being added, so in our edit button, we set the mode to 'E', then read the lastSibling in the list and then set the value of the textbox.

B4X:
'when a task is being edited
Sub task_edit(e As BANanoEvent)
    Mode = "E"
    'get the parent node of the button as the button is inside a li
    Dim task As BANanoElement = JQuery.ParentNode(e)
    'get last child in the list
    lastEdit = JQuery.LastChild(task)
    Dim text As String = lastEdit.GetText
    'edit mode show entry
    BANano.GetElement("#new-task-name").SetValue(text)
    'focus to text box
    JQuery.Focus("#new-task-name")
End Sub
To delete the task, we need to remove the complete <li></li> item, so we need a way to get it and then remove it from the list. Here we use the BANanoEvent and get the 'target' and from the target get the 'parentNode' to be able to get the <li></li> the button is inside of.

B4X:
'when a task is being deleted
Sub task_delete(e As BANanoEvent)
    Mode = ""
    'get the parent node of the button as the button is inside a li
    Dim task As BANanoElement = JQuery.ParentNode(e)
    'remove the item from the list
    JQuery.Remove(task)
    SaveTasks
End Sub
The ParentNode sub is NOT JQuery (just saved there) is...

B4X:
'get the parent node from the event
Sub ParentNode(e As BANanoEvent) As BANanoElement
    'get the target from event
    Dim target As BANanoObject = e.OtherField("target")
    'get the parentNode from target
    Dim parent As BANanoElement = BANano.ToElement(target.GetField("parentNode"))
    Return parent
End Sub
Moving the tasks up / down

For that we get the <li></li> that we have selected using ParentNode, then we move that up/down

B4X:
'when a task is being moved up
Sub task_up(e As BANanoEvent)
    Mode = ""
    'get the li the up button sits inside
    Dim task As BANanoElement = JQuery.ParentNode(e)
    'move the item up
    JQuery.MoveUp(task)
    SaveTasks
End Sub

'when a task is being moved down
Sub task_down(e As BANanoEvent)
    Mode = ""
    'get the task the button sits inside of
    Dim task As BANanoElement = JQuery.ParentNode(e)
    'move item down
    JQuery.MoveDown(task)
    SaveTasks
End Sub
After we have moved an element, they are saved to LocalStorage.

Let's look at moveup in a simplified way..

B4X:
'move an item up
Sub MoveUp(itm As BANanoElement)
    'get the previous sibling
    Dim prev As BANanoElement = BANano.ToElement(itm.GetField("previousSibling"))
    Dim s As BANanoObject = BANano.ToObject(itm)
    Dim t As BANanoObject = BANano.ToObject(prev)
    JQuery.Selector(s).RunMethod("insertBefore", t)
End Sub
In Summary..

1. We click a button inside a list, this fires an event and returns a BANanoEvent
2. We read this BANanoEvent in task_up, 2.1 we get the target of BANanoEvent and from the target 2.2 we get the parentNode, this gives us the LI item
1. We get the list item from 2.2, (a BANanoElement) and pass this to move up sub
2. The LI is storing the link to the previousSibling, we get that previous LI
3. We then convert the current LI and the previous LI to BANanoObjects and then use JQuery 'insertBefore' method to move these around.

Mind boggling...
 
Last edited:

Mashiane

Expert
Licensed User
Lesson 18: In most cases you will not need JQuery

Whilst lesson 18, dealt with functionality done using the JQuery library, in most cases you will not need this as JavaScript is capable.

To demo this, we will create a class named BANanoJavaScript. As most of what you will do is to reference the document object, let's create a global variable and then initialize it in Initialize.

javascript.png


B4X:
#IgnoreWarnings:12
Sub Class_Globals
    Private document As BANanoObject
    Private BANano As BANano  'ignore
End Sub

Public Sub Initialize
    document = BANano.Window.GetField("document")
End Sub
For starters, in our previous example, we used the .Focus method

Let's create a javascript version..

B4X:
'focus
Sub focus(arguements As String)
    'document.getElementById("myAnchor").focus();
    document.RunMethod("getElementById", Array(arguements)).RunMethod("focus", Null)
End Sub
One of the most things we are doing is to create HTML elements, set properties to them and styles and add them to the DOM tree. In most cases, you call an .Append method to the parent element you need and use .Get with BANano. Let's work on a premise that you want to create an element and then add it it the DOM tree. With javascript there is a .createElement to do that and then you can use .Append later. Let's create own own .createElement method.

B4X:
'createElement
Sub createElement(arguements As String) As BANanoElement
    'var newItem = document.createElement("LI");
    Dim bo As BANanoObject = document.RunMethod("createElement", Array(arguements))
    Return BANano.ToElement(bo)
End Sub
You might want to get the innerHML and outerHTML of your element

B4X:
'GetOuterHTML
Sub GetOuterHTML(el As BANanoElement) As String
    'var content = element.outerHTML;
    Dim sout As String = el.GetFIeld("outerHTML").Result
    Return sout
End Sub
B4X:
'GetInnerHTML
Sub GetInnerHTML(el As BANanoElement) As String
    'var content = element.innerHTML;
    Dim sout As String = el.GetField("innerHTML").Result
    Return sout
End Sub
If you are used to JavaScript, you might still want a familiar approach, lets look at the querySelector...

B4X:
'querySelector
Sub querySelector(parent As BANanoElement) As BANanoElement
    Dim bo As BANanoObject = parent.RunMethod("querySelector", Null)
    Return BANano.ToElement(bo)
End Sub
You might want to create multiple items and then add them in one go, why dont you pass them as a list to the .appendChild method.

B4X:
'appendChild
Sub appendChild(parent As BANanoElement, childs As List)
    For Each child As BANanoElement In childs
        Dim bo As BANanoObject = BANano.ToObject(child)
        parent.RunMethod("appendChild", Array(bo))
    Next   
End Sub
Finally, some of the more or less used methods in javascript... more / less

B4X:
'getElementById
Sub getElementById(arguements As String) As BANanoElement
    'var list = document.getElementById("myList");
    Dim bo As BANanoObject = document.RunMethod("getElementById", Array(arguements))
    Return BANano.ToElement(bo)
End Sub

'getElementsByTagName
Sub getElementsByTagName(parent As BANanoElement, arguements As String) As List
    'var list = document.getElementsByTagName("<p>");
    Dim lst As List = parent.RunMethod("getElementsByTagName", Array(arguements)).result
    Return lst
End Sub

'getElementsByClassName
Sub getElementsByClassName(parent As BANanoElement, arguements As BANanoElement) As List
    'var list = element.getElementsByTagName("<p>");
    Dim lst As List = parent.RunMethod("getElementsByClassName", Array(arguements)).result
    Return lst
End Sub
Lesson 18 here demos how the attached page was created using simple calls to both banano and the javascript class created. It does not have everything but the basis to create elements, set properties and styles. The basics to get you going.

Ta!
 

Mashiane

Expert
Licensed User
In closing this [Just to get you Going] journey

During the course of this series, we have demonstrated the following...

1. Setting up your BANano project
2. Adding a page and multiple pages to your project.
3. Adding elements to the body of the page
4. Setting element properties like styles, attributes, changing color, changing font
5. Adding buttons and linking events to them using CallBacks
6. Manipulating data from the BANanoEvent object
7. Adding an input control and getting / setting a value to it.
8. Creating a markup using a class for your HTML elements and appending this to a BANanoElement
9. Using another library with BANano, e.g. JQuery and how to initialize it and use Selectors and call other methods like .GetField, .SetField, RunMethod
10. Inline JavaScript and how to call it
11. Inline CSS
12. Defining own css file and adding it to the header of our project
13. Accessing Javascript object e.g. document and calling its method e.g. getElementByID, .focus
14. We took a peek at the MiniCSS and Skeleton frameworks that you can use with BANano to create your amazing projects
15. We explored the canvas and how to access the 2d context. This was just a brief..

etc

There are a lot of tutorials in the forum to do a variety of things with BANano. In this thread, we have demonstrated the basic things to get one up and going in doing a website/webapp and also just understand what BANano is and what it does. It has a lot of other things that have not been discussed on this thread as they are beyond this thread.

If you have any questions about BANano, kindly start a new thread with your questions.

Enjoy your BANano Journey, I'm out!!

PS: Thanks for the ears, appreciated!
 
Last edited:
Top