Ola
So i am sitting and thinking... I need some multi-check box functionality in my combo box. I need to return the selected items and be able to set each item to be checked. Then it dawns on me. One of the nice things about the ABMCombo is the functionality to add ABMContainers to it. So it should be possible to add a container with a checkbox as an item. This basically is a nicer alternative for what I intend doing. I can trap the combo click event, get the selected items and process what I need to do.
So, I need a container that has a checkbox, I should be able to set the checkbox on and off on addition.
So I add this to my ABMShared..
Here I create a container with a checkbox, specifiying the id and text of the checkbox.
So in my connectpage, I create a combo and add some check boxes to it.
Now, when the combo box is selected, I need to get the items that are checked in the combobox. So I add a click event. Off course, returning the selected items can be done anywhere in my code. The returned object is a list with the ids of each of the items selected.
As noted above, I have called ABMComboGetChecked passing the combo box name to it. To be able to do this I needed to write some JQuery.
When you right click on any HTML element on your page, you can see how its created. So the UL (unordered list) that stores the combo items is called dropdown + id of your component. The checkboxes are somewhere in that html element, so I call jquery to return all checked input ids inside the UL. Remember from this, the ABM dropdown is not a SELECT component but a UL.
Each element id is suffixed with -id+'input' being for example opt1-opt1input, so we need to return opt1, thus the mvfield function. This ends up being shown on the msgbox in the click event.
So, to be able to check anything in the combo, I also needed another method.
This I can call whenever I need to.
As each element in a page needs a unique name, there can only be one opt5. This also creates the proper name for the element and then runs a JQuery script to check the element.
Should you wish to check elements in ConnectPage, ensure you do so after page.refresh.
Happy coding.
PS: In Summary, just to show how I have currently implemented this...
1. I build my normal modal sheet the same way it has been and add an ABMCombo in it.
2. On Add / Edit, I show the modal and clear the contents of the controls and refresh the ones I need where necessary. As an example, to refresh my combo /w checkboxes combo I call this method after I have called .ShowModalSheet. This selects records form a database and loads them to the combo, all the items are un-checked. This is both applicable for Add / Edit CRUD functions.
3. When a record is added / updated, I save the contents to a map which is used on my inserts database calls. To read the contents of the checked combo items, I call..
The contents of outcboforums will be like ["1","2","4"] which will be ids of the checked items, this is put on the pMap map object and saved to the db.
4. When a record is selected for Edit i.e. ShowModal and view current record for editing, I read the db record to a map and then for the combo / w check, after it has been refreshed, just check the relevent items for this record.
So i am sitting and thinking... I need some multi-check box functionality in my combo box. I need to return the selected items and be able to set each item to be checked. Then it dawns on me. One of the nice things about the ABMCombo is the functionality to add ABMContainers to it. So it should be possible to add a container with a checkbox as an item. This basically is a nicer alternative for what I intend doing. I can trap the combo click event, get the selected items and process what I need to do.
So, I need a container that has a checkbox, I should be able to set the checkbox on and off on addition.
So I add this to my ABMShared..
B4X:
'add a checkbox item to combo
Sub ABMCheckBoxItem(page As ABMPage, id As String, text As String, checked As Boolean) As ABMContainer
Dim ItemCont As ABMContainer
ItemCont.Initialize(page, id, "")
ItemCont.AddRowsM(1,False,0,20, "").AddCellsOSMP(1,0,0,0,12,12,12,0,0,10,10,"")
ItemCont.BuildGrid 'IMPORTANT once you loaded the complete grid AND before you start adding components
Dim chk As ABMCheckbox
chk.Initialize(page, id,text,checked,"")
ItemCont.Cell(1,1).AddComponent(chk)
Return ItemCont
End Sub
Here I create a container with a checkbox, specifiying the id and text of the checkbox.
So in my connectpage, I create a combo and add some check boxes to it.
B4X:
Dim asel As ABMCombo
asel.Initialize(page,"asel","Resources","650","")
asel.AddItem("opt1","Option 1",ABMShared.ABMCheckBoxItem(page,"opt1","Option 1",True))
asel.AddItem("opt2","Option 2",ABMShared.ABMCheckBoxItem(page,"opt2","Option 2",False))
asel.AddItem("opt3","Option 3",ABMShared.ABMCheckBoxItem(page,"opt3","Option 3",True))
asel.AddItem("opt4","Option 4",ABMShared.ABMCheckBoxItem(page,"opt4","Option 4",False))
asel.AddItem("opt5","Option 5",ABMShared.ABMCheckBoxItem(page,"opt5","Option 5",False))
page.Cell(2,1).AddComponent(asel)
Now, when the combo box is selected, I need to get the items that are checked in the combobox. So I add a click event. Off course, returning the selected items can be done anywhere in my code. The returned object is a list with the ids of each of the items selected.
B4X:
Sub asel_Clicked(itemId As String)
Dim lst As List = ABMShared.ABMComboGetChecked(page,"asel")
Dim out As String = ABMShared.List2JSON(lst)
page.Msgbox("",out,"asel checked","ok",False,"","")
End Sub
As noted above, I have called ABMComboGetChecked passing the combo box name to it. To be able to do this I needed to write some JQuery.
B4X:
'get checked from combobox
Sub ABMComboGetChecked(page As ABMPage, id As String) As List
Dim ulKey As String = $"dropdown${id}"$
Dim script As String = $"var selected = [];
$('#${ulKey} input:checked').each(function() {
selected.push($(this).attr('id'));
});
var myJSON = selected.toString();
return myJSON;"$
Dim f As Future = page.ws.EvalWithResult(script,Null)
Dim sout As String = f.value
Dim items() As String = StrParse(",",sout)
Dim lstItems As List
lstItems.Initialize
For Each strItem As String In items
strItem = MvField(strItem,1,"-")
lstItems.Add(strItem)
Next
Return lstItems
End Sub
When you right click on any HTML element on your page, you can see how its created. So the UL (unordered list) that stores the combo items is called dropdown + id of your component. The checkboxes are somewhere in that html element, so I call jquery to return all checked input ids inside the UL. Remember from this, the ABM dropdown is not a SELECT component but a UL.
Each element id is suffixed with -id+'input' being for example opt1-opt1input, so we need to return opt1, thus the mvfield function. This ends up being shown on the msgbox in the click event.
So, to be able to check anything in the combo, I also needed another method.
B4X:
Sub iif(Expression2Evaluate As String, ReturnIfTrue As Object, ReturnIfFalse As Object) As Object
If Expression2Evaluate = True Then Return ReturnIfTrue Else Return ReturnIfFalse
End Sub
'set checked
Sub ABMComboSetChecked(page As ABMPage, compid As String, id As String, bChecked As Boolean)
If id.length = 0 Then Return
If id.StartsWith("[") And id.EndsWith("]") Then
Dim lst As List = Json2List(id)
id = MvFromList(lst,",")
End If
Dim parentID As String = $"dropdown${compid}"$
'ability to set multiple items at once
Dim spItems() As String = StrParse(",",id)
Dim sbCode As StringBuilder
sbCode.Initialize
For Each strItem As String In spItems
id = strItem
Dim itmKey As String = $"${id}-${id}input"$
Dim sChecked As String = iif(bChecked=True,"true","false")
Dim script As String = $"$('#${parentID}').find('#${itmKey}').prop('checked', ${sChecked});"$
sbCode.Append(script).Append(CRLF)
Next
page.ws.Eval(sbCode.tostring,Null)
page.ws.flush
End Sub
Sub MvFromList(lst As List, Delim As String) As String
Dim lTot As Int
Dim lCnt As Int
Dim lStr As StringBuilder
lStr.Initialize
lTot = lst.Size - 1
For lCnt = 0 To lTot
lStr.Append(lst.Get(lCnt))
If lCnt <> lTot Then lStr.Append(Delim)
Next
Return lStr.tostring
End Sub
This I can call whenever I need to.
B4X:
ABMShared.ABMComboSetChecked(page, "cboItems"", "opt5",True)
As each element in a page needs a unique name, there can only be one opt5. This also creates the proper name for the element and then runs a JQuery script to check the element.
Should you wish to check elements in ConnectPage, ensure you do so after page.refresh.
Happy coding.
PS: In Summary, just to show how I have currently implemented this...
1. I build my normal modal sheet the same way it has been and add an ABMCombo in it.
2. On Add / Edit, I show the modal and clear the contents of the controls and refresh the ones I need where necessary. As an example, to refresh my combo /w checkboxes combo I call this method after I have called .ShowModalSheet. This selects records form a database and loads them to the combo, all the items are un-checked. This is both applicable for Add / Edit CRUD functions.
B4X:
'Refresh the contents of the ABMCombo at runtime.
Private Sub RefreshOnLoad_cboforums()
'Get access to the component in the page.
Dim msgenpeople As ABMModalSheet = page.ModalSheet("msgenpeople")
Dim cboforums As ABMCombo = msgenpeople.Content.Component("cboforums")
'Clear the ABMCombo items
cboforums.Clear
'Define list details to load to the combo
Dim results As List
Dim resCnt As Int
Dim resTot As Int
Dim resMap As Map
'variable to hold the source field
Dim id As String
'variable to hold the description field
Dim Name As String
'Read arguments from LocalStorage (if any)
'Add a spinner to the page
'Get connection from current pool if MySQL/MSSQL
Dim jSQL As SQL = ABMShared.SQLGet
'Get the records as a list of maps from the db
results = ABMShared.SQLExecuteMaps(jSQL,"select id,name from Forums order by name", Null)
'Close the connection to the database
ABMShared.SQLClose(jSQL)
'Loop throught each record read and process it
resTot = results.size - 1
For resCnt = 0 To resTot
'Get the record map
resMap = results.get(resCnt)
'process the id field
id = resMap.get("id")
Name = resMap.get("name")
cboforums.AddItem(id, Name, ABMShared.ABMCheckBoxItem(page, id, Name, False))
Next
'Refresh the ABMCombo contents
cboforums.Refresh
End Sub
3. When a record is added / updated, I save the contents to a map which is used on my inserts database calls. To read the contents of the checked combo items, I call..
B4X:
Dim lstcboforums As List = ABMShared.ABMComboGetCheckedModal(page, "msgenpeople", "cboforums")
Dim outcboforums As String = ABMShared.List2JSON(lstcboforums)
pMap.put("forums",outcboforums)
The contents of outcboforums will be like ["1","2","4"] which will be ids of the checked items, this is put on the pMap map object and saved to the db.
4. When a record is selected for Edit i.e. ShowModal and view current record for editing, I read the db record to a map and then for the combo / w check, after it has been refreshed, just check the relevent items for this record.
B4X:
Dim cboforumsContents As String
cboforumsContents = pMap.getdefault("forums","")
ABMShared.ABMComboUnCheckAllModal(page, "msgenpeople","cboforums")
ABMShared.ABMComboSetCheckedModal(page, "msgenpeople","cboforums", cboforumsContents,True)
Last edited: