B4J Question [SOLVED] B4X PreferencesDialog and Data map, can you change a value to null if something else?

Magma

Expert
Licensed User
Longtime User
Hi there...

Well searching-creating a small app (for personal use) found something like a bug ?? or may be is a question and my wrong way..

Well lets say we have a json template created from FormBuilder with 2-3 textfields...

1. lets ' pre-define them with a map... right ?
B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private prefdialog As PreferencesDialog
...
End Sub
...
...
    Dim Options1 As Map=CreateMap()
    Options1.Put("Field1","FirstValue")
    Options1.Put("Field2","SecondValue")
    Options1.Put("Field3","ThirdValue")
    Wait For (prefdialog.ShowDialog(Options1, "OK", "CANCEL")) Complete (Result As Int)
    If Result = xui.DialogResponse_Positive Then
          log(options1.get("Field2")) 'well if set Field2 to null, or ""... will give again SecondValue... if it is any other value - will be displayed....
...
    end if

2. When run the above example - and set at form the Field1 value to "" (nothing)... after OK button - it will keep the old value... :-(


Please check it... is there a solution ???
FOUND SOLUTION - SEE HERE
 
Last edited:

aeric

Expert
Licensed User
Longtime User
How about this?

V1.40 - Adds an IsValid event that you can use to validate the data before it is committed.
In order to use it you need to first call:
B4X:
pref.SetEventsListener(Me, "Pref") 'sets the callback and event name.
Handle the event:
B4X:
'Number value should be between 1 to 50. If not we call ScrollToItemWithError and return False.
'You can check all fields here.
Sub Pref_IsValid (TempData As Map) As Boolean
    Dim number As Int = TempData.GetDefault("Number", 0)
    If number < 1 Or number > 50 Then
        pref.ScrollToItemWithError("Number")
        Return False
    End If
    Return True
End Sub

 
Upvote 0

Magma

Expert
Licensed User
Longtime User
@aeric Sorry but how that can help ? that will help to message the end user to change a value... - I want just to return at specific fields null values...

[I edit the post - because aeric thought i was angry - sorry ☮️ - no bold]
 
Last edited:
Upvote 0

aeric

Expert
Licensed User
Longtime User
Try this example:
B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private PrefDialog1 As PreferencesDialog
    Private ProductName, Category As String
End Sub

Public Sub Initialize
'    B4XPages.GetManager.LogEvents = True
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    CreateDialog1
End Sub

Private Sub B4XPage_Resize(Width As Int, Height As Int)
    If PrefDialog1.IsInitialized And PrefDialog1.Dialog.Visible Then PrefDialog1.Dialog.Resize(Width, Height)
End Sub

Private Sub BtnShow_Click
    ShowDialog1
End Sub

Private Sub CreateDialog1
    PrefDialog1.Initialize(Root, "Product", 300dip, 300dip)
    PrefDialog1.Dialog.OverlayColor = xui.Color_ARGB(128, 0, 10, 40)
    PrefDialog1.Dialog.TitleBarHeight = 50dip
    PrefDialog1.LoadFromJson(File.ReadString(File.DirAssets, "template.json"))
    PrefDialog1.SetEventsListener(Me, "PrefDialog1") '<-- must add to handle events.
End Sub

Private Sub ShowDialog1
    PrefDialog1.Dialog.TitleBarColor = xui.Color_RGB(65, 105, 225)
    PrefDialog1.Title = "Product"
    Dim Item As Map = CreateMap("Product Name": ProductName, "Category": Category)
    Dim sf As Object = PrefDialog1.ShowDialog(Item, "CONFIRM", "CANCEL")
    Sleep(0)
    PrefDialog1.CustomListView1.sv.Height = PrefDialog1.CustomListView1.sv.ScrollViewInnerPanel.Height + 10dip
    Wait For (sf) Complete (Result As Int)
    If Result = xui.DialogResponse_Positive Then
        Log(Item)
    End If
End Sub

Private Sub PrefDialog1_BeforeDialogDisplayed (Template As Object)
    Try
        ' Fix Linux UI (Long Text Button)
        Dim btnCancel As B4XView = PrefDialog1.Dialog.GetButton(xui.DialogResponse_Cancel)
        btnCancel.Width = btnCancel.Width + 20dip
        btnCancel.Left = btnCancel.Left - 20dip
        btnCancel.TextColor = xui.Color_Red
        Dim btnOk As B4XView = PrefDialog1.Dialog.GetButton(xui.DialogResponse_Positive)
        If btnOk.IsInitialized Then
            btnOk.Width = btnOk.Width + 20dip
            btnOk.Left = btnCancel.Left - btnOk.Width
        End If
    Catch
        Log(LastException)
    End Try
End Sub

Sub PrefDialog1_IsValid (TempData As Map) As Boolean
    ProductName = TempData.Get("Product Name")
    If ProductName = "null" Then
        ProductName = ""
    End If
    Category = TempData.Get("Category")
    If Category = "null" Then
        Category = ""
    End If
    Return True
End Sub
 

Attachments

  • PreferencesDialog.zip
    3.7 KB · Views: 93
Upvote 0

Magma

Expert
Licensed User
Longtime User
This is not what exactly i am telling... and ofcourse in your example creating too much code for nothing (no offense) - because actually I want to get no value :)

but even so...
if at Private Sub ShowDialog1 add the following line above all: ProductName="TEST1"

and then run the project... at runtime give at first field null ("") not "null" / just delete the TEST1 and submit/OK... map will return you TEST1

:)

I think that is a bug...

[I edit the post - because aeric thought i was angry - sorry ☮️ ]
 
Last edited:
Upvote 0

aeric

Expert
Licensed User
Longtime User
First, don’t get angry (bold words)

Why so many code? Because I recycle my old sample. Since you didn’t provide a working project that I can run directly. Just ignore the styling and don’t need to mention. Just focus on the last part where I demo how to use the IsValid event sub.
No value in your context is null? Maybe you can try to use Object instead of String. I just demo if no value pass to a String then it changed to “null”.

I don’t know how you pass the source value but in my project I will load from SQL query. Once the OK button is pressed then the values will save into database. The updated value is loaded to the Prefdialog.

If my answer doesn’t help then I can’t help further as I don’t understand what you actually want to achieve.
 
Upvote 0

AnandGupta

Expert
Licensed User
Longtime User
I think what Magma wants is as below logic,
  1. default value is shown as "NAME" say
  2. user blanks / deletes it and press OK
  3. result returned is "NAME" but should be ""
I think we will need to change the source of PreferencesDialog for it.
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
@aeric First of all thank you for your fast responses...

...i just used bold to see exactly what needed... and as i said ---> "no offense" | i think you got angry
...I am so sorry you see that "angry" - bold was to saw you what i need...

The isvalid i think that is to just prompt again the user... to enter new value...

Let's take your example - if pre-define as I said you the value...
at Private Sub ShowDialog1 (sorry for bold) --> add the following line above all: ProductName="TEST1"

If run:

ex0.jpg
ex1.jpg


but at log... you ll see returning the map... TEST1 :-(
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
Upvote 0

aeric

Expert
Licensed User
Longtime User
I think what Magma wants is as below logic,
  1. default value is shown as "NAME" say
  2. user blanks / deletes it and press OK
  3. result returned is "NAME" but should be ""
I think we will need to change the source of PreferencesDialog for it.

Try again if what it suppose to mean is always set value to "Default" if user enter "blank" or leave the Text input empty.

B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private PrefDialog1 As PreferencesDialog
    Private ProductName As String = "Default"
    Private Category As String = "Toys"
End Sub

Public Sub Initialize
'    B4XPages.GetManager.LogEvents = True
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    CreateDialog1
End Sub

Private Sub B4XPage_Resize(Width As Int, Height As Int)
    If PrefDialog1.IsInitialized And PrefDialog1.Dialog.Visible Then PrefDialog1.Dialog.Resize(Width, Height)
End Sub

Private Sub BtnShow_Click
    ShowDialog1
End Sub

Private Sub CreateDialog1
    PrefDialog1.Initialize(Root, "Product", 300dip, 300dip)
    PrefDialog1.Dialog.OverlayColor = xui.Color_ARGB(128, 0, 10, 40)
    PrefDialog1.Dialog.TitleBarHeight = 50dip
    PrefDialog1.LoadFromJson(File.ReadString(File.DirAssets, "template.json"))
    PrefDialog1.SetEventsListener(Me, "PrefDialog1") '<-- must add to handle events.
End Sub

Private Sub ShowDialog1
    PrefDialog1.Dialog.TitleBarColor = xui.Color_RGB(65, 105, 225)
    PrefDialog1.Title = "Product"
    Dim Item As Map = CreateMap("Product Name": ProductName, "Category": Category)
    Dim sf As Object = PrefDialog1.ShowDialog(Item, "CONFIRM", "CANCEL")
    Sleep(0)
    PrefDialog1.CustomListView1.sv.Height = PrefDialog1.CustomListView1.sv.ScrollViewInnerPanel.Height + 10dip
    Wait For (sf) Complete (Result As Int)
    If Result = xui.DialogResponse_Positive Then
        'Log(Item) ' don't confuse, you need the returned ProductName, not the map
        Log($"Product Name: ${ProductName}"$) '<--- default if no value specified
    End If
End Sub

Sub PrefDialog1_IsValid (TempData As Map) As Boolean
    ProductName = TempData.GetDefault("Product Name", "Default") '<-- use GetDefault as mentioned in post #2
    Category = TempData.GetDefault("Category", "Toys")
    Return True
End Sub
 
Last edited:
Upvote 0

Magma

Expert
Licensed User
Longtime User
@aeric Sorry you didn;t understand again what i need...

1)Let's say you save at your db, array, 3 texts...
A
B
C

2)First you pass the texts to the map will be used at prefdialog - then you just running the prefdialog

At screen shows you the input boxes...
A
B
C

OK - Cancel

3) Changing to...
A

C

and pressing OK (you want the result of map to be A,,C ... not A,B,C) --->but returning map is A,B,C again!
 
Upvote 0

aeric

Expert
Licensed User
Longtime User
@aeric Sorry you didn;t understand again what i need...

1)Let's say you save at your db, array, 3 texts...
A
B
C

2)First you pass the texts to the map will be used at prefdialog - then you just running the prefdialog

At screen shows you the input boxes...
A
B
C

OK - Cancel

3) Changing to...
A

C

and pressing OK (you want the result of map to be A,,C ... not A,B,C) --->but returning map is A,B,C again!
Then the code in post #4 is correct.
You may have confused of my Log(item) in line 44

Change it to:
B4X:
'Log(Item)
Log($"Product Name: ${ProductName}"$)
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
..Yes if use secondary variables, or second map for the results can be a fix-trick...

but i think that the right should be one map / enough to use -> to set the values and get the values from it... So I think must be fixed
 
Upvote 0

aeric

Expert
Licensed User
Longtime User
..Yes if use secondary variables, or second map for the results can be a fix-trick...

but i think that the right should be one map / enough to use -> to set the values and get the values from it... So I think must be fixed
Let’s see what @Erel say, is it by design or a bug.
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
Found Solution - Hope help others... too - was quite simple

...Well I have edit the source of the latest (1.75) b4xlib B4xPreferencesDialog... at these points:
B4X:
...
Private Sub CommitChanges (Data As Map) As Boolean
....
            Case TYPE_TEXT, TYPE_PASSWORD, TYPE_MULTILINETEXT 
                Dim ft As B4XFloatTextField = ItemPanel.GetView(0).Tag
                If ft.Text <> "" Then  'added by me
                    Value = ft.Text 'This was before
                else 'added by me
                    Value = "" 'added by me
                end if 'added by me
...
    If mEventName <> "" And xui.SubExists(mCallback, mEventName  & "_IsValid", 1) Then
        Dim Valid As Boolean = CallSub2(mCallback, mEventName & "_IsValid", Temp)
        If Valid = False Then Return False
    End If
    Data.clear 'added by me
    For Each key As String In Temp.Keys
        Data.Put(key, Temp.Get(key))
        'log(Temp.Get(key)) 'fixed by me
    Next

Now works...

Attaching library... here
 
Last edited:
Upvote 0
Top