B4J Library [BANano] UOEGridTable: An interesting grid that you might like

Mashiane

Expert
Licensed User
Ola

Seemingly I'm getting closer to my app goal for my next project, so here is something for the community again. A grid and there some very few things I like about it too. This is a wrap for this project here.

Quick Reference

ShowCase: Header Filters (onchange / onkeypress events)

UOEFilter.gif


Full Table

UOENowGrid.png


This is what you get:

1. Sortable columns
2. Table title
3. Table headers themeable with css
3. DropDown
4. Checkbox
5. Pager (limits, number of pages etc)
6. Many interesting events and methods..

It's also possible to set the custom view designer properties when using the designer.

UOENowGridDesigner.png


Ok, let me help you to succeed. Let's look at the definition of the component. This is based on gijgo again.

UOENowGridTable
  • Cancel (pk As String)
    cancel operation for primary key
  • SetDataSource (rows As List) As UOENowGridTable
    set data source
  • GetRecordFromEvent (e As BANanoEvent) As Map
    get record from event
  • SetColumnGroupBy (colField As String) As UOENowGridTable
    set columns to group by
  • SetColumnEditors (colField As List) As UOENowGridTable
    set columns editors
  • SetColumnModeReadOnly (colField As List) As UOENowGridTable
    set columns editor mode to readonly
  • SetColumnModeEditOnly (colField As List) As UOENowGridTable
    set columns editor mode to editor only
  • SetColumnDataSource (colField As String, colDataSource As Object, colValueField As String, colEditField As String) As UOENowGridTable
    set columns data source for dropdown
  • GetByPos (rowPos As Int) As Map
    get data for primary key
  • GetRowsVisible() As List
    get all visible rows data
  • GetRows() As List
    get all rows data
  • GetById (id As String) As Map
    get data by id
  • SearchFor (searchValues As Map)
    search the grid, use a map that has the field names and values to search for
  • Reload
    reload, if autoload is false
  • Clear
    clear the data
  • HideColumn (colName As List)
    hide columns via code
  • ShowColumn (colField As List)
    show columns via code
  • RemoveRow (pk As String)
    remove a row by id
  • CountVisible As Int
    count visible records
  • CountAll As Int
    count all records
  • Refresh As UOENowGridTable
    refresh the grid
  • UpdateRow (rowData As Map)
    update an existing row of data
  • AddColumn (colName As String, colTitle As String, colType As String, colWidth As Int, colSortable As Boolean, colAlign As String) As UOENowGridTable
    add a column
  • AddIcon (colField As String, colTitle As String, colIcon As String, colWidth As String, colAlign As String)
    add Icon
  • AddIconEdit (colField As String, colTitle As String, colWidth As String, colAlign As String)
    add edit icon
  • AddIconDelete (colField As String, colTitle As String, colWidth As String, colAlign As String)
    add delete icon
  • AddTemplate (colField As String, colTitle As String, colTemplate As String, colWidth As String, colSortable As Boolean, colAlign As String)
    add template
  • SetColumnTmpl (colName As String, coltmpl As String) As UOENowGridTable
    set the column data template
  • SetColumnClickEvent (colField As String, stopPropagation As Boolean)
    set column click event
  • SetColumnEvent (colField As String, colEvent As String, stopPropagation As Boolean)
    set column event
  • SetColumnMinWidth (colField As String, colMinWidth As Int, colPriority As Int) As UOENowGridTable
    set the column min width
  • GetSelected As String
    get selected record id
  • GetSelections As List
    get all selected record ids
  • SelectAll
    select all records
  • UnSelectAll
    un-select all records
  • ExpandAll
    expand all records
  • CollapseAll
    collapse all records
  • SetSelected (rowPos As Int)
    set a selection
  • SetColumnName (colField As String, colName As String) As UOENowGridTable
    set the column name
  • SetColumnToolTip (colName As String, colToolTip As String) As UOENowGridTable
    set the column tooltip
  • SetColumnStopPropagation (colName As String, colStopPropagation As Boolean) As UOENowGridTable
    set the column stop probagation for events
  • GetChanges As List
    get changed records on table for only changed fields and primary key
  • SetColumnIcon (colName As String, colIcon As String) As UOENowGridTable
    set the column icon
  • SetColumnHidden (colName As String) As UOENowGridTable
    set column visibility
  • SetColumnSortable (colName As String, colSortable As Boolean) As UOENowGridTable
    set column sortable
  • AddRow (rowData As Map)
    add a row dynamically
  • DownloadCSV (fileName As String)
    download data as csv
  • GetCSV
    get data as csv
  • SetColumnItalic (colName As String) As UOENowGridTable
    set header italic
  • SetColumnHeaderCSS (colName As String, headerCssClass As String) As UOENowGridTable
    set header css
  • SetColumnFilterable (colName As String, colFilter As Boolean) As UOENowGridTable
    set column filterable
  • SetColumnCSS (colName As String, colCSS As String) As UOENowGridTable
    set the column class
  • SetColumnFormat (colName As String, colFormat As String) As UOENowGridTable
    set the column data format
  • Destroy
    removes all data and events and keep table and wrapper
 

Attachments

Last edited:

Mashiane

Expert
Licensed User
To add the grid, one needs to use the abstract designer and then generate the necessary events needed. Lets journey ahead.

Let's define the structure of the grid first by defining the columns and their attributes.

B4X:
'define the columns
    uoegrid.PrimaryKey = "id"
    uoegrid.AddColumn("id","#",uoegrid.COLUMN_TEXT, 56, False, uoegrid.ALIGN_CENTER)
    uoegrid.AddColumn("Name","Name",uoegrid.COLUMN_TEXT, 0, True, uoegrid.ALIGN_LEFT)
    'make the column header italic
    uoegrid.SetColumnItalic("Name")
    'set the column tooltip
    uoegrid.SetColumnToolTip("Name","Full name of player.")
    uoegrid.AddColumn("CountryName","Country Name",uoegrid.COLUMN_DROPDOWN,200,True,uoegrid.ALIGN_LEFT)
    uoegrid.AddColumn("PlaceOfBirth","Place of Birth",uoegrid.COLUMN_TEXT, 0, True, uoegrid.ALIGN_LEFT)
    uoegrid.AddColumn("DateOfBirth","Date of Birth", uoegrid.COLUMN_DATE,150,False,uoegrid.ALIGN_CENTER)
    'set the column data format
    uoegrid.SetColumnFormat("DateOfBirth","dd.mm.yyyy")
    'uoegrid.AddColumn("tmpl","Template", uoegrid.COLUMN_String,0,False,uoegrid.ALIGN_LEFT)
    uoegrid.AddColumn("IsActive","Active?",uoegrid.COLUMN_CHECKBOX,80,False,uoegrid.ALIGN_CENTER)
    'add buttons
    uoegrid.AddMaterialEdit("EditRecord","",64, uoegrid.ALIGN_CENTER)
    uoegrid.SetColumnClickEvent("EditRecord",True)
    uoegrid.AddMaterialDelete("DeleteRecord","",64, uoegrid.ALIGN_CENTER)
    uoegrid.SetColumnClickEvent("DeleteRecord",True)
The assumption here is that the data to be loaded will be read directly from a database. By using an AddColumn method, it means we can easily add and remove column definitions anytime we want as each column is individually defined. This improves code maintenance too. The grid needs to have a primarykey which will be used to identify each unique record in the grid. Each column is linked to a field in our database records, thus we identify these, their titles, the widths, whether sortable or not and their alignment.

After we have added the column definitions, we also add action buttons and add click events for the two, being edit / delete buttons. One can then write their code to manage that as each click event returns the record being accessed.
 

Mashiane

Expert
Licensed User
The next phase of the example is adding records. When reading records from a db, these will be returned as JSON string, basically meaning these will be a list of map records, each with field definitions and values. The data in this example is dependent of a countries list and is being referenced by the players records. All of this can be read from a database and then added to the UOEGrid.

B4X:
Dim countries As List
    countries.Initialize
    countries.Add(CreateMap("id":18, "text": "Bulgaria"))
    countries.Add(CreateMap("id":12, "text": "Brazil"))
    countries.Add(CreateMap("id":16, "text": "England"))
    countries.Add(CreateMap("id":17, "text": "Germany"))
    countries.Add(CreateMap("id":19, "text": "Poland"))
    countries.Add(CreateMap("id":14, "text": "Colombia"))
    countries.Add(CreateMap("id":15, "text": "South Africa"))
    uoegrid.SetColumnDataSource("CountryName", countries, "id", "CountryID")
      
    'add the datasource
    Dim dataSource As List
    dataSource.Initialize
    dataSource.Add(CreateMap("id": 1, "Name": "Hristo Stoichkov", "PlaceOfBirth": "Plovdiv, Bulgaria","DateOfBirth":"/Date(-122227200000)/","IsActive":False,"CountryID":18,"CountryName": "Bulgaria"))
    dataSource.Add(CreateMap("id": 2, "Name": "Ronaldo Luis Nazario de Lima", "PlaceOfBirth": "Rio de Janeiro, Brazil", "DateOfBirth":"/Date(211878000000)/","IsActive":False,"CountryID":12,"CountryName": "Brazil"))
    dataSource.Add(CreateMap("id": 3, "Name": "David Platt", "PlaceOfBirth": "Chadderton, Lancashire, England","DateOfBirth":"/Date(-112122000000)/","IsActive":False,"CountryID":16,"CountryName": "England"))
    dataSource.Add(CreateMap("id": 4, "Name": "Manuel Neuer", "PlaceOfBirth": "Gelsenkirchen, West Germany", "DateOfBirth":"/Date(512294400000)/", "IsActive":True, "CountryID":17, "CountryName": "Germany"))
    dataSource.Add(CreateMap("id": 5, "Name": "James Rodríguez", "PlaceOfBirth": "Cúcuta, Colombia", "IsActive":True, "CountryName": "Colombia","DateOfBirth":"/Date(349689600000)/","CountryID":14))
    dataSource.Add(CreateMap("id": 6, "Name": "Dimitar Berbatov", "PlaceOfBirth": "Blagoevgrad, Bulgaria", "IsActive":False, "CountryName": "Bulgaria","DateOfBirth":"/Date(349689600000)/","CountryID":18))
    dataSource.Add(CreateMap("id": 7, "Name": "Robert Lewandowski", "PlaceOfBirth": "Warsaw, Poland", "DateOfBirth":"/Date(588150000000)/", "CountryID":19, "CountryName": "Poland", "IsActive":True))
    uoegrid.SetDataSource(dataSource).Refresh
    'add a row dynamically
    uoegrid.AddRow(CreateMap("id": 8, "Name": "Mashy", "PlaceOfBirth": "East London, Eastern Cape", "DateOfBirth":"/Date(588150000000)/", "CountryID":15, "CountryName": "South Africa", "IsActive":True))
We first define the countries records. These have id and text fields. For this component, when referencing such data, one needs to give the description field to be text, thus, id and text for the countries records.

Then we build the example data as if it will be sourced directly from the database, as individual records (maps). We have text boxes, a dropdown, a checkbox etc. The records are added to the grid and the grid is refreshed.

To demonstrate adding records dynamically to the grid without a complete record reload, we have added an .AddRow call after refresh.

SetDataSource is a memory list and its compulsory that after adding records this way, one does a refresh. With .AddRow, one does not have to do a refresh as records are added as and when they are added to the grid after the last added record. The structure of the added record should meet the column definition with the exception of the Edit/Delete buttons.

For the dropdown, we have added a column called CountryName on the grid. The countryname is linked to the countryid. To establish this link, we call SetColumnDataSource specifying the column that will display the country name as CountryName, from the countries source. The value field on the countries list is 'id' and this will be linked as CountryID on the table. Yes, I noted, a little data redudancy here for this to be effective.
 

Mashiane

Expert
Licensed User
We have a couple of events that we have added. These are...

B4X:
#Event: RowDataBound (e As BANanoEvent, row As Object, id as Object, record As Object)
#Event: RowRemoving (e As BANanoEvent, row As Object, id as Object, record As Object)
#Event: RowSelect (e As BANanoEvent, row As Object, id as Object, record As Object)
#Event: RowUnSelect (e As BANanoEvent, row As Object, id as Object, record As Object)
#Event: CellDataChanged (e As BANanoEvent, cell As Object, column As Object, record As Object, newValue As Object)
#Event: RowDataChanged (e As BANanoEvent, id As Object, record As Object)
#Event: Click (e As BANanoEvent)
These do different things as per their definitions..

B4X:
Sub uoegrid_click(e As BANanoEvent)
    Dim record As Map = uoegrid.GetRecordFromEvent(e)
    Log(record)
End Sub


Sub uoegrid_CellDataChanged (e As BANanoEvent, cell As Object, column As Object, record As Object, newValue As Object)
    'Log(cell)
    'Log(column)
    'Log(record)
    'Log(newValue)
End Sub

Sub uoegrid_RowDataChanged (e As BANanoEvent, id As Object, record As Object)
    Log(record)
End Sub


Sub uoegrid_RowDataBound (e As BANanoEvent, row As Object, id As Object, record As Object)
    'Log(record)
End Sub

Sub uoegrid_RowRemoving (e As BANanoEvent, row As Object, id As Object, record As Object)
    'Log("row removed")
    'Log(record)
End Sub

Sub uoegrid_RowSelect (e As BANanoEvent, row As Object, id As Object, record As Object)
    'Log("row selected")
    'Log(record)
End Sub

Sub uoegrid_RowUnSelect (e As BANanoEvent, row As Object, id As Object, record As Object)
    'Log("row un-selected")
    'Log(record)
End Sub
The click event for edit and delete will return the record being accessed. One can write their own code to handle that.
 

Mashiane

Expert
Licensed User
On the designer, there are some settings that one can set to make the grid work for them.

B4X:
#DesignerProperty: Key: Width, DisplayName: Width, FieldType: Int, DefaultValue: 0, Description: Width
#DesignerProperty: Key: PagerLimit, DisplayName: PagerLimit, FieldType: Int, DefaultValue: 10, Description: Pager Width, List: 5|10|15|20|25|30|35|40|45|50
#DesignerProperty: Key: PrimaryKey, DisplayName: PrimaryKey, FieldType: String, DefaultValue: id, Description: PrimaryKey
#DesignerProperty: Key: AutoLoad, DisplayName: AutoLoad, FieldType: Boolean, DefaultValue: True, Description: AutoLoad
#DesignerProperty: Key: BodyRowHeight, DisplayName: BodyRowHeight, FieldType: String, DefaultValue: autogrow, List: fixed|autogrow
#DesignerProperty: Key: SelectionType, DisplayName: SelectionType, FieldType: String, DefaultValue: single, List: single|multiple
#DesignerProperty: Key: ColumnReorder, DisplayName: ColumnReorder, FieldType: Boolean, DefaultValue: True, Description: ColumnReorder
#DesignerProperty: Key: KeepExpandedRows, DisplayName: KeepExpandedRows, FieldType: Boolean, DefaultValue: False, Description: KeepExpandedRows
#DesignerProperty: Key: FixedHeader, DisplayName: FixedHeader, FieldType: Boolean, DefaultValue: False, Description: FixedHeader
#DesignerProperty: Key: HeaderFilter, DisplayName: HeaderFilter, FieldType: Boolean, DefaultValue: False, Description: HeaderFilter
#DesignerProperty: Key: HeaderFilterType, DisplayName: HeaderFilterType, FieldType: String, DefaultValue: onchange, List: onchange|onenterkeypress
#DesignerProperty: Key: ResizableColumns, DisplayName: ResizableColumns, FieldType: Boolean, DefaultValue: False, Description: ResizableColumns
#DesignerProperty: Key: ShowHiddenColumnsAsDetails, DisplayName: ShowHiddenColumnsAsDetails, FieldType: Boolean, DefaultValue: False, Description: ShowHiddenColumnsAsDetails
#DesignerProperty: Key: Title, DisplayName: Title, FieldType: String, DefaultValue: , Description: Title
#DesignerProperty: Key: RowReorder, DisplayName: RowReorder, FieldType: Boolean, DefaultValue: False, Description: RowReorder
#DesignerProperty: Key: SelectionMethod, DisplayName: SelectionMethod, FieldType: String, Description: SelectionMethod, DefaultValue: checkbox, List: checkbox|basic
For example, RowReorder enables one to drag and drop rows where ever in the grid.
ColumnRecorder enables one to move columns whilst FixedHeader ensures that your header does not scroll where many records are concerned.
 

Mashiane

Expert
Licensed User
With just one line of code, you easily activate inline editing that uses built in components to render, date picker, dropdown and input controls.

B4X:
uoegrid.SetColumnEditors(Array("Name","PlaceOfBirth","DateOfBirth","IsActive","CountryName"))
UOEInlineEditing.png


For inline editing, you can trap the RowChanged event to get record fields that have changed and update your records.
 

Mashiane

Expert
Licensed User
I also needed to group my players by country of birth including detailed information about the place of birth. This was easily done by specifying a grouping field and also the detailed template.

B4X:
uoegrid.DetailTemplate = $"<div style="text-align: left"><b>Place Of Birth:</b> {PlaceOfBirth}</div>"$
    uoegrid.SetColumnGroupBy("CountryName")
And this resulted in..

UOEGroupBy.png


Providing collapsible content that I can easily expand and collapse as per need. With DownloadCSV, the content of the grid is directly exported to Excel CSV without any dependencies.

Enjoy

Ta!

PS: As this is a custom component, you are welcome to do as you please with it as the source is attached. I only effected the necessary stuff for use in my project and shared to help others succeed. If you find it useful all the better.
 
Last edited:

joulongleu

Active Member
Licensed User
:)UoeGrid is very glad,When push Checkbox The following error occurred ::)
file:///C:/Users/joulo/DOWNLO~1/UOEGrid/BANANO~1/Objects/UOETreeView/fonts/gijgo-material.ttf?235541 net::ERR_FILE_NOT_FOUND
 
Last edited:

joulongleu

Active Member
Licensed User
Yes,Thank You :)
Two other questions:
1.uoegrid.Title how to center?
2. In addition to edit, delete how to use select icon?
 

Mashiane

Expert
Licensed User
Yes,Thank You :)
Two other questions:
1.uoegrid.Title how to center?
2. In addition to edit, delete how to use select icon?
There is a method to pass your own css to the header however I don’t think I added it. You can check their docs. What you can do is create your own container and use LoadLayout to load the grid inside that container that can have your own controls. I will check it later for you though.
 

Mashiane

Expert
Licensed User
It's perfect, thanks!
How to reload grid with changed DataSource?
There are two methods to load the data sources, one for a combo field, just run the methods again passing updated lists of records. There should be a clear method, I’m not infront of my laptop now I will check it for you later.

I think it’s SetDataSource and SetColumnDataSource. Remember to also run the .Refresh method.
 

GanjaKyp

Active Member
Licensed User
There are two methods to load the data sources, one for a combo field, just run the methods again passing updated lists of records. There should be a clear method, I’m not infront of my laptop now I will check it for you later.

I think it’s SetDataSource and SetColumnDataSource. Remember to also run the .Refresh method.
I try to update with timer, but table doesn't changed

B4X:
Sub Timer_Tick
BANano.GetElement("#countvisible").SetText(DateTime.Time(DateTime.Now))
Dim json As BANanoJSONParser
json.Initialize(BANano.CallAjaxWait("http://10.20.2.7:88/crmset.aspx?query=exec call_list 1556301600000,0,'Все менеджеры'", "GET", "jsonp", "", False, Null))
uoegrid.SetDataSource(json.NextArray).Refresh
End Sub
 

Mashiane

Expert
Licensed User
Yes,Thank You :)
Two other questions:
1.uoegrid.Title how to center?
2. In addition to edit, delete how to use select icon?
Edit and delete do the same function of getting the record in question, you can then define your own code to manipulate them. There is a RemoveRow method that you can pass the id of the record though. You will have to add your own confirmation dialog if needed and link the deleted record back to your datasource and thus the underlying database.

The removerow has an event where you can trap the record removal and then expand. I will work on an example to showcase such CRUD functionality with an dB soon for you.
 
Top