B4J Library [BANano] UOETreeView: A designer treeview you might use

Ola

I was kind of excited when I found this today. It justs meets most of the requirements that I need from a treeview. To mention a few, one can

1. Check, CheckAll, UnCheck, UnCheckAll
2. Select, SelectAll, UnSelect, UnSelectAll,
3. Specify an id, text for a node
4. Search a node by id
5. Update a node's text using the id and many many more..

Dependencies

1. JQuery
2. Bootstrap Css
3. FontAwesome

Using in your project

1. Unzip the files and copy the attached UOETreewView custom view component to your project files.
2. Copy the css and js files to your project files folder
3. Open the designer and add the UOETreeView component from custom layouts and set its size etc also changing its name
4. Generate events etc for your code
5. Use BANano.LoadLayout method to load your layout and then add nodes via code.

The attached code file is the most updated version of the example for this component.


UOENowTreeView
  • Refresh
    set the options for the tree
  • AddNode (parentID As String, pk As String, Text As String, ImgURL As String, Icon As String, Tag As Map)
    add node
  • GetDataById (pk As String) As BANanoObject
    get data by id
  • GetNodeById (pk As String) As BANanoObject
    get node by id
  • GetNodeByText (pk As String) As BANanoObject
    get node by text
  • GetDataByText (nodeText As String) As BANanoObject
    get data by text
  • SetText (pk As String, Text As String)
    set text of node
  • SetIcon (pk As String, Icon As String)
    set icon of node
  • SetImage (pk As String, ImageURL As String)
    set image of node
  • SetData (pk As String, Tag As Map)
    set data for Node
  • UpdateNode (pk As String, Text As String, ImgURL As String, Icon As String, Tag As Map)
    update node
  • GetChildren (pk As String) As List
    get children
  • GetCheckedNodes() As List
    get checkedNodes
  • GetSelections() As List
    get selected nodes
  • GetAll() As String
    get all ids
  • RemoveNode (pk As String)
    remove a node
  • Check (pk As String)
    check a node
  • UnCheck (pk As String)
    uncheck a node
  • SelectNode (pk As String)
    select a node
  • UnSelectNode (pk As String)
    unselect a node
  • ExpandAll()
    ExpandAll nodes
  • Reload()
    reload tree view
  • CollapseAll()
    collapse all nodes
  • CheckAll()
    checkAll nodes
  • UnCheckAll()
    UncheckAll nodes
  • SetBackgroundColor (pk As String, color As String)
    set background color of node
  • SetColor (pk As String, color As String)
    set color of the node
  • Expand (pk As String)
    Expand a node
  • Collapse (pk As String)
    collapse a node
  • Enable (pk As String)
    enable a node
  • Disable (pk As String)
    disable a node
  • Destroy
    destroy the tree
Known Issues:

UpdateNode does not update the icon & image of the node.
 

Attachments

  • UOETreeView.zip
    152.2 KB · Views: 413
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Here is some of the example code...

B4X:
Dim tv As UOETreeView
    tv.Initialize(App,"tv","id")
    tv.Width = "500"
    tv.Border = True
    tv.CheckBoxes = True
    tv.AddToParent(tvc.GetRC(1,1))
    tv.AddNode("","0","My Family")
    tv.AddNode("0","1","My Grand-mother")
    tv.AddNode("1","2","My Mother")
    tv.AddNode("2","3","My Big Brother")
    tv.AddNode("2","4","Me")
    tv.AddNode("4","6","My Son")
    tv.AddNode("4","7","My 1st Daughter")
    tv.AddNode("4","8","My 2nd Daughter")
    tv.AddNode("2","5","My Little Sister")
    tv.AddNode("4","9","Unknown Child")
  
    tv.UpdateNode("3","Xolani")
    Log(tv.GetChildren("0"))
    tv.SetBackgroundColor("2","red")
    tv.Collapse("0")
    tv.Disable("4")
    Log(tv.GetAll)
    tv.CheckAll
    tv.ExpandAll
    tv.RemoveNode("9")
    tv.UnCheck("0")
    tv.SelectNode("0")
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Checking out the code behind...

We initialize a tree variable as a BANanoObject, the refresh method does a few of setting up a few things...

B4X:
'refresh the treeview
Sub Refresh
    If Multiple Then
        selectionType = "multiple"
    End If
    Dim dataSource As List
    dataSource.Initialize
    Dim opt As Map = CreateMap("iconsLibrary": "fontawesome", _
    "uiLibrary": "bootstrap4", _
    "checkboxes": CheckBoxes, _
    "border": Border, _
    "cascadeCheck": cascadeCheck, _
    "lazyLoading": lazyLoading, _
    "primaryKey": primaryKey, _
    "dragAndDrop": dragAndDrop, _
    "selectionType": selectionType, _
    "dataSource": dataSource)
    tree = App.JQElement(ID)
    tree.RunMethod("tree", Array(opt))
End Sub

This uses JQuery, so what JQElement does is basically run BANanoObject.Selector(xxx)

Our AddNode methods, expects a parent node. When the parent node is blank, the node is added to the root of the tree.

B4X:
'add node
Sub AddNode(parentID As String, pk As String, Text As String)
    'define the node to add
    Dim node As Map = CreateMap("id":pk,"text":Text)
    If parentID = "" Then
        tree.RunMethod("addNode",Array(node))
    Else
        Dim prnt As BANanoObject = tree.RunMethod("getNodeById", Array(parentID))
        If prnt <> Null Then
            tree.RunMethod("addNode",Array(node,prnt))
        End If
    End If   
End Sub

Each node is identified by an id and text. When we initialized the TreeView, we specified that the primary key for all records should be "id". So each node primary key is anything stored in id. The id should be unique. If the parent is specified, its read from the treeview using getNodeById, if found, the child node is added.
 

Mashiane

Expert
Licensed User
Longtime User
To update a node, it's searched by id also and then the text of it also updated.

B4X:
'update node
Sub UpdateNode(pk As String, Text As String)
    Dim node As BANanoObject = tree.RunMethod("getDataById", Array(pk))
    If node <> Null Then
        node.SetField("text", Text)
        tree.RunMethod("updateNode", Array(pk, node))
    End If
End Sub

To remove a node, the node is searched by id and then if it exists, it gets removed.

B4X:
'remove a node
Sub RemoveNode(pk As String)
    Dim node As BANanoObject = tree.RunMethod("getNodeById", Array(pk))
    If node <> Null Then
        tree.RunMethod("removeNode", node)
    End If
End Sub

Source to be uploaded soon, trying to figure out events and stuff.

#HelpingOthers2Succeed.
 

Mashiane

Expert
Licensed User
Longtime User
One will also be able to store additional data on each treeview node. This is possible with the AddNode1 and UpdateNode1 methods.

B4X:
'add a new node with data
    tv.AddNode1("0","10","Node with Data", CreateMap("population":"1200M","elders":"8000"))
    tv.UpdateNode1("5", CreateMap("name":"Bulelwa","Age":"43"))

NodeData.png


And the data stored per node, can be read with the following methods, GetDataById and GetDataByText directly from the treeview.

B4X:
Log(tv.GetDataById("10"))
    Log(tv.GetDataByText("Xolani"))

and logged

AddNode1 is just an extension of AddNode1 which justs ensures that the additional data as specified with the map is added. The node id and text are compulsory, thus required individually.

B4X:
'add node with data
Sub AddNode1(parentID As String, pk As String, Text As String, Tag As Map)
    'define the node to add
    Dim node As Map = CreateMap("id":pk,"text":Text)
    For Each strKey As String In Tag.Keys
        Dim strVal As Object = Tag.Get(strKey)
        node.Put(strKey,strVal)
    Next
    If parentID = "" Then
        tree.RunMethod("addNode",Array(node))
    Else
        Dim prnt As BANanoObject = tree.RunMethod("getNodeById", Array(parentID))
        If prnt <> Null Then
            tree.RunMethod("addNode",Array(node,prnt))
        End If
    End If
End Sub
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
UpdateNode1 also extends on UpdateNode, however we use the BANano setfield method to update the node data.

B4X:
'Set node data using map
Sub UpdateNode1(pk As String, Tag As Map)
    Dim node As BANanoObject = tree.RunMethod("getDataById", Array(pk))
    If node <> Null Then
        For Each strKey As String In Tag.Keys
            Dim strVal As Object = Tag.Get(strKey)
            node.SetField(strKey, strVal)
        Next
        tree.RunMethod("updateNode", Array(pk, node))
    End If
End Sub
 

Mashiane

Expert
Licensed User
Longtime User
Turning UseFontAwesome = True, the expand and collapsible icons for each node is changed into a chevron. One is able to use whatever arrows they want for the treeview by changing the CollapseIcon and ExpandIcon for the fontawesome icons (when included in the project). By default UseFontAwesome for this component is False.

TreeConfig.png
 

Mashiane

Expert
Licensed User
Longtime User
Please note that The code file attached in the first post is based on a custom view and the BANano.LoadLayout method has been used to load the treeview.

There is a modular release of the files for just the treeview component on gijgo and when that can work only that will be used as the attached js and css files are for all components they have.

The events for this control are still tricky to figure out but I’m sure a solution will be got soon and a repost done however anyone confident to sort that out is very much welcome.

Ta!
 

joulongleu

Active Member
Licensed User
Longtime User
Hi :)Mashiane:There are two questions to ask?
1.Turning tv.CheckBoxes = False ,change event No action?
2.How to get change event Value?
 

Mashiane

Expert
Licensed User
Longtime User
Hi :)Mashiane:There are two questions to ask?
1.Turning tv.CheckBoxes = False ,change event No action?
2.How to get change event Value?
The first post has been updated with the latest updates of the project. This includes the select and checkbox change events. The change event has been removed.

Ta!
 

Mashiane

Expert
Licensed User
Longtime User
Updates: UOETree Events

TreeEvents.gif


The latest update of the treeview has 4 events..

B4X:
#Event: CheckboxChange(e As BANanoEvent, node As Object, record As Map, state As String)
#Event: Select (e As BANanoEvent, node As Object, id as String)
#Event: NodeDrop (e As BANanoEvent, id As String, parentId As String, orderNumber As String)
#Event: NodeDataBound (e As BANanoEvent, node As Object, id As String, record As Map)

1. CheckBoxChange

This happens when a node is checked / unchecked. The CheckBoxes designer property should be turned on for this to work.

To trap the event...

B4X:
Sub tv_CheckboxChange(e As BANanoEvent, node As Object, record As Map, state As String)
    Select Case state
    Case "checked"
        BANano.Alert("Checked: " & BANano.ToJson(record))
    Case Else
        BANano.Alert("Unchecked: " & BANano.ToJson(record))
    End Select
End Sub

2. Select

The select event happens whenever a node is selected. The Un-Select event has not been built in.

To trap this event...

B4X:
Sub tv_Select (e As BANanoEvent, node As Object, id As Object)
    Dim rec As Map = tv.GetDataById(id).Result
    BANano.Alert(BANano.ToJson(rec))
End Sub

3. NodeDrop

The NodeDrop event happens when a node is dragged from one node to another. For this to work, the DragNDrop designer property should be turned on.

B4X:
Sub tv_NodeDrop (e As BANanoEvent, id As String, parentId As String, orderNumber As String)
    Dim node As Map = tv.GetDataById(id).Result
    If parentId = Null Then parentId = ""
    node.Put("parentId",parentId)
    BANano.Alert(BANano.ToJson(node))
End Sub

4. NodeDataBound

The NodeDataBound event happens for each node being added to the tree. When this happens one can check something about the node and set some conditions. In the attached example, we turn the background of the node depending on the id.

B4X:
Sub tv_NodeDataBound (e As BANanoEvent, node As Object, id As String, record As Map)
    Select Case id
    Case 1,5,7
        Dim el As BANanoElement = BANano.ToElement(node)
        el.SetStyle($"{"background-color": "red"}"$)
    End Select
End Sub

The first post has been updated with the latest example.

PS: Also for consistency, the property bag has been updated for use with material design / fontawesome & bootstrap.

UOETreePropBag.png
 

Mashiane

Expert
Licensed User
Longtime User
Coming Updates: Loading JSON data

You can also just load JSON data to the treeview...

B4X:
'use data source
    tv.imageUrlField = "flagUrl"
    Dim data As String = $"[{"id":1,"text":"Asia","population":null,"flagUrl":null,"checked":false,"hasChildren":false,"children":[{"id":2,"text":"China","population":1373541278,"flagUrl":"https://code.gijgo.com/flags/24/China.png","checked":false,"hasChildren":false,"children":[]},{"id":3,"text":"Japan","population":126730000,"flagUrl":"https://code.gijgo.com/flags/24/Japan.png","checked":false,"hasChildren":false,"children":[]},{"id":4,"text":"Mongolia","population":3081677,"flagUrl":"https://code.gijgo.com/flags/24/Mongolia.png","checked":false,"hasChildren":false,"children":[]}]},{"id":5,"text":"North America","population":null,"flagUrl":null,"checked":false,"hasChildren":false,"children":[{"id":6,"text":"USA","population":325145963,"flagUrl":"https://code.gijgo.com/flags/24/United%20States%20of%20America(USA).png","checked":false,"hasChildren":false,"children":[{"id":7,"text":"California","population":39144818,"flagUrl":null,"checked":false,"hasChildren":false,"children":[]},{"id":8,"text":"Florida","population":20271272,"flagUrl":null,"checked":false,"hasChildren":false,"children":[]}]},{"id":9,"text":"Canada","population":35151728,"flagUrl":"https://code.gijgo.com/flags/24/canada.png","checked":false,"hasChildren":false,"children":[]},{"id":10,"text":"Mexico","population":119530753,"flagUrl":"https://code.gijgo.com/flags/24/mexico.png","checked":false,"hasChildren":false,"children":[]}]},{"id":11,"text":"South America","population":null,"flagUrl":null,"checked":false,"hasChildren":false,"children":[{"id":12,"text":"Brazil","population":207350000,"flagUrl":"https://code.gijgo.com/flags/24/brazil.png","checked":false,"hasChildren":false,"children":[]},{"id":13,"text":"Argentina","population":43417000,"flagUrl":"https://code.gijgo.com/flags/24/argentina.png","checked":false,"hasChildren":false,"children":[]},{"id":14,"text":"Colombia","population":49819638,"flagUrl":"https://code.gijgo.com/flags/24/colombia.png","checked":false,"hasChildren":false,"children":[]}]},{"id":15,"text":"Europe","population":null,"flagUrl":null,"checked":false,"hasChildren":false,"children":[{"id":16,"text":"England","population":54786300,"flagUrl":"https://code.gijgo.com/flags/24/england.png","checked":false,"hasChildren":false,"children":[]},{"id":17,"text":"Germany","population":82175700,"flagUrl":"https://code.gijgo.com/flags/24/germany.png","checked":false,"hasChildren":false,"children":[]},{"id":18,"text":"Bulgaria","population":7101859,"flagUrl":"https://code.gijgo.com/flags/24/bulgaria.png","checked":false,"hasChildren":false,"children":[]},{"id":19,"text":"Poland","population":38454576,"flagUrl":"https://code.gijgo.com/flags/24/poland.png","checked":false,"hasChildren":false,"children":[]}]}]"$
    Dim countries As List = Json2List(data)
    tv.SetDataSource(countries)
    tv.refresh

treefromjson.png
 
Top