Web Connection
HtmlListBox - Bug 6.21
Gravatar is a globally recognized avatar based on your email address. HtmlListBox - Bug 6.21
  Marcel DESMET
  All
  Mar 13, 2019 @ 11:14am

There is a unwanted [">] in lcOutput in array mode

Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Rick Strahl
  Marcel DESMET
  Mar 13, 2019 @ 01:06pm

Thank you. Fixed.

lcOutput = lcOutput + [<option value="] + lcValue + [" ] +;
                      IIF(llSelected,[selected="selected" ],[]) + [>] +;
		      lcText +[</option>] + CRLF

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Marcel DESMET
  Rick Strahl
  Mar 13, 2019 @ 01:49pm

Hello,

There is also a problem for passing array from the HtmlDropDown so far as I know you need to pass a array's as reference not value

And also the lcSelectedValue doens't work form the HtmlDropDown ...

Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Rick Strahl
  Marcel DESMET
  Mar 13, 2019 @ 01:59pm

Example please...

Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Marcel DESMET
  Rick Strahl
  Mar 13, 2019 @ 02:58pm

Here is the code for the selected value

I put all the code in visual classes ... but to work I need to trim the selected value

IF VARTYPE(THIS.cSelectedValue) = "C"
	IF ATC(":FORCED",THIS.cSelectedValue) > 0
		THIS.cSelectedValue = STRTRAN(THIS.cSelectedValue,":FORCED","",1,-1,1)
		llForced = .T.
	ENDIF
	THIS.cSelectedValue = ALLTRIM(THIS.cSelectedValue)
ELSE
	THIS.cSelectedValue = ALLTRIM(TRANSFORM(THIS.cSelectedValue))
ENDIF
Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Rick Strahl
  Marcel DESMET
  Mar 13, 2019 @ 04:08pm

I don't see how this relates to the array issue you described below.

Can you please clearly state what your issue is and then perhaps shown an example. The control works as a functions so it can render with a simple command from the command window or a small prg so it should be easy to demonstrate.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Marcel DESMET
  Rick Strahl
  Mar 13, 2019 @ 04:15pm

How did you pass aarray datasource here ?

FUNCTION HtmlDropDown(lcName,lcSelectedValue,lcDataSource,;
                      lcDataValueField,lcDataTextField,;
                      lcAttributes,lcInitialText,lcInitialValue)
IF EMPTY(lcAttributes)
 
   lcAttributes = ""
ENDIF
RETURN HtmlListBox(lcName,lcSelectedValue,lcDataSource,lcDataValueField,;
                   lcDataTextField,lcAttributes + " !DROPDOWN!",;
                   lcInitialText,lcInitialValue)
ENDFUNC
Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Rick Strahl
  Marcel DESMET
  Mar 14, 2019 @ 04:45pm

Oh I get it. The array is not getting passed through @lcDataSource.

Does anybody still use arrays in FoxPro? 😃 You know because of shit like this:

     *** Satisfy compiler - won't compile in project without this
     if .F.  
        LOCAL ARRAY lcDatasource[1]
     endif

     lnDimensions = ALEN(lcDataSource,2)
     IF (lnDimensions = 0)
       lnDimensions = 1
       lnRows = ALEN(lcDataSource,0)
    ELSE 
       lnRows = ALEN(lcDataSource,1)
    ENDIF
		
    FOR lnX = 1 TO lnRows

Gotta love FoxPro design for that sort of madness 😃 All because arrays can't be assigned without copying... Argh, Fox arrays are the scourge of programming. Anyway I disgress...

later...

Ok so I took a look at this and it looks like neither arrays or collections never really worked - not with HtmlDropDown() or HtmlListBox(). Apparently nobody was using those features ever since none of that worked and I've never had any reports of issues with it. There were all sorts of problems there that needed fixing. I've fixed them now so this should now work with the following code fixes (large code block alert!):

************************************************************************
*  HtmlListBox
****************************************
***  Function: Creates an HTML Listbox from a cursor, collection or
***            array. Pass the cursor as a string alias, collections
***            as a plain object and arrays by references (@laItems).
***    Assume:
***      Pass: 
***    Return:
************************************************************************
FUNCTION HtmlListBox(lcName,lcSelectedValue,lcDataSource,;
                     lcDataValueField,lcDataTextField,;
                     lcAttributes,lcInitialText, lcInitialValue)
LOCAL lcOutput, lcOldAlias, lcText, lcValue, lnDataMode, llForced

IF EMPTY(lcName)
  lcName = SYS(2015)
ENDIF
IF ISNullOrEmpty(lcSelectedValue) 
  lcSelectedValue = ""
ENDIF

llForced = .F.
IF VARTYPE(lcSelectedValue) = "C" 
   IF ATC(":FORCED",lcSelectedValue) > 0
	   lcSelectedValue = STRTRAN(lcSelectedValue,":FORCED","",1,-1,1)
	   llForced = .T.
   ENDIF
ELSE
   lcSelectedValue = TRANSFORM(lcSelectedValue)   
ENDIF

LOCAL loSelectedValues, lnSelectedCount, lcSelectedValues

loSelectedValues = CREATEOBJECT("Collection")
lcSelectedValues = ""
lnSelectedCount = 0

*** Handle AutoPostback
IF VARTYPE(REQUEST) = "O" AND Request.IsFormVar(lcName) AND !llForced
   loSelectedValues = Request.GetFormMultipleCollection(lcName)
   lnSelectedCount = loSelectedValues.Count
ELSE
   *** On get set single value 
   * TODO: Handle array model value
   loSelectedValues.Add(lcSelectedValue)
   lnSelectedCount = 1
ENDIF

*** Create a string list of selected values to match against
*** |value1|value2| 
IF lnSelectedCount > 0
	lcSelectedValues = "|" 
	FOR lnX = 1 TO lnSelectedCount
	    lcSelectedValues = lcSelectedValues + loSelectedValues.Item(lnX) + "|"
	ENDFOR      
ENDIF

IF ISNULLOREMPTY(lcDataSource)
   lcDataSource = ""
ENDIF
IF EMPTY(lcDataValueField)
   lcDataValueField = ""
ENDIF    
IF EMPTY(lcDataValueField)
   lcDataValueField = ""
ENDIF 

llIsDropDown = .F.
IF EMPTY(lcAttributes)
   lcAttributes = ""
ELSE
   IF AT("!DROPDOWN!",lcAttributes) > 0
      llIsDropDown = .T.      
      lcAttributes = STRTRAN(lcAttributes,"!DROPDOWN!","")
   ENDIF	
ENDIF

lnDataMode = 0  && Cursor
DO CASE 
	CASE TYPE("lcDataSource.Count") = "N"
   	   lnDataMode = 2 && Collection
	CASE TYPE("lcDataSource[1]") # "U"
	   lnDataMode = 1 && Array
ENDCASE

lcOutput = [<select id="] + lcName + [" name="] + lcName + [" ] +;
           IIF(llIsDropDown,[Size="1" ],[Size="5" ]) + lcAttributes + [>] + CRLF

IF VARTYPE(lcInitialText) = "C"
    lcValue = ""
    IF VARTYPE(lcInitialValue) = "C"
       lcValue = [value="] + lcInitialValue + ["]
    ENDIF
	lcOutput = lcOutput + [<option ] + lcValue + [>] + lcInitialText +[</option>] + CRLF
ENDIF

IF lnDataMode = 0
	lcOldAlias = SELECT()

	SELECT (lcDataSource)	
	SCAN
		lcValue = TRANSFORM(EVALUATE(lcDataValueField))
		IF EMPTY(lcDataTextField)
		   lcText = lcValue
		ELSE
		   lcText = TRANSFORM(EVALUATE(lcDataTextField))
		ENDIF		

		llSelected = .f.
		IF lnSelectedCount > 0 AND AT("|" + lcValue + "|",lcSelectedValues) > 0
		   llSelected = .T.
		ENDIF
				
		lcOutput = lcOutput + [<option value="] + lcValue + [" ] +;
		                      IIF(llSelected,[selected="selected" ],[]) + [>] +;
		                      lcText +[</option>] + CRLF
	ENDSCAN
	
	IF !EMPTY(lcOldAlias)
	   SELECT (lcOldAlias)
	ENDIF
ENDIF

*** Array - Assume 1 or 2 dimensional array. 2 dimensions: 1 -value 2 -text
***         1 dimension value: Value for text and value
***         1 dimension object: Use lcDataTextField/lcDataValueField for eval
IF lnDataMode = 1
	*** Satisfy compiler
	if .F.
	LOCAL ARRAY lcDatasource[1]
	endif
	lnDimensions = ALEN(lcDataSource,2)
	IF (lnDimensions = 0)
	   lnDimensions = 1
	   lnRows = ALEN(lcDataSource,0)
    ELSE 
       lnRows = ALEN(lcDataSource,1)
	ENDIF
		
	FOR lnX = 1 TO lnRows
		IF lnDimensions >1
	       lcValue = lcDataSource[lnX,1]
		   lcText = lcDataSource[lnX,2]
		ELSE
		   IF !EMPTY(lcDataValueField)
		   		loItem = lcDataSource[lnX]
		   		lcValue = EVALUATE("loItem." + lcDataValueField)
		   		IF !EMPTY(lcDataTextField)
			   		lcText = EVALUATE("loItem." + lcDataTextField)
			   	ELSE
			   		lcText = lcValue
			   	ENDIF
		   ELSE
		      	lcValue = lcDataSource[lnX]	
	  		    lcText = lcValue
		   ENDIF
		ENDIF
		
		llSelected = .f.
		IF lnSelectedCount > 0 AND AT("|" + lcValue + "|",lcSelectedValues) > 0
		   llSelected = .T.
		ENDIF
		
		lcOutput = lcOutput + [<option value="] + lcValue + [" ] +;
		                      IIF(llSelected,[selected="selected" ],[]) + [>] +;
							  lcText +[</option>] + CRLF
	ENDFOR
ENDIF

*** Collection - assume item is an object with two properties
***              Evaluated with lcDataValueField & lcDataTextField
IF lnDataMode = 2
    LOCAL loCol 
    loCol = lcDataSource  &&EVALUATE(lcDataSource)
	FOR EACH loItem in loCol FOXOBJECT
	    IF VARTYPE(loItem) = "O"
			lcValue = EVALUATE("loItem." + lcDataValueField)
			IF !EMPTY(lcDataTextField)
				lcText = EVALUATE("loItem." + lcDataTextField)
		   	ELSE
		 		lcText = lcValue
		 	ENDIF
		ELSE
			lcValue = loItem
			lcText = loItem
	 	ENDIF
		
		llSelected = .f.
		IF lnSelectedCount > 0 AND AT("|" + lcValue + "|",lcSelectedValues) > 0
		   llSelected = .T.
		ENDIF
		
		
		lcOutput = lcOutput + [<option value="] + lcValue + [" ] +;
		                      IIF(llSelected,[selected="selected" ],[]) + [>] +;
							  lcText +[</option>] + CRLF
	ENDFOR
ENDIF

lcOutput = lcOutput + "</select>" + CRLF

RETURN lcOutput
ENDFUNC
*   HtmlListBox

************************************************************************
*  HtmlDropDown
****************************************
***  Function:
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION HtmlDropDown(lcName,lcSelectedValue,lcDataSource,;
                      lcDataValueField,lcDataTextField,;
                      lcAttributes,lcInitialText,lcInitialValue)
IF EMPTY(lcAttributes)
 
   lcAttributes = ""
ENDIF
RETURN HtmlListBox(lcName,lcSelectedValue,@lcDataSource,;
				   lcDataValueField,lcDataTextField,;
				   lcAttributes + " !DROPDOWN!",;
                   lcInitialText,lcInitialValue)
ENDFUNC
*   HtmlDropDown

I still need to test a few more scenarios but this should now work for code like this:

*** Selected value to select in listbox
lcSelectedValue = "Item2"

*** Cursor Binding - Key Value
CREATE CURSOR TITEMS (Key  varchar(40), Value varchar(100) )
INSERT INTO TItems VALUES ("Item1","First Item #1 Db")
INSERT INTO TItems VALUES ("Item2","Second Item #2 Db")

? HtmlDropdown("lstItemsCursor",lcSelectedValue,"TItems","Key","Value")


*** Array Binding  - Single Item
DIMENSION laItems[2]
laItems[1] = "Item1"
laItems[2] = "Item2"

? HtmlDropdown("lstItemsArray",lcSelectedValue,@laItems)

*** Collection Binding - Single Item
loCol = CREATEOBJECT("Collection")
loCol.Add("Item1")
loCol.Add("Item2")
  
? HtmlDropdown("lstItemsCollection",lcSelectedValue,loCol)

*** Object Binding for arrays and collections
loObj1 = CREATEOBJECT("EMPTY")
ADDPROPERTY(loObj1,"Key","Item1")
ADDPROPERTY(loObj1,"Value","First Item #1")

loObj2 = CREATEOBJECT("EMPTY")
ADDPROPERTY(loObj2,"Key","Item2")
ADDPROPERTY(loObj2,"Value","Second Item #2")

?
? loObj1.Key
? loObj1.Value
? loObj2.Key
? loObj2.Value
?

*** Array of Objects Binding
DIMENSION laItems[2]
laItems[1] = loObj1
laItems[2] = loObj2

? HtmlDropdown("lstItemsArray2",lcSelectedValue,@laItems,"Key","Value")

*** Collection of Objects Binding
loCol = CREATEOBJECT("Collection")
loCol.Add(loObj1)
loCol.Add(loObj2)
  
? HtmlDropdown("lstItemsCollection",lcSelectedValue,loCol,"Key","Value")

Updated docs

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Marcel DESMET
  Rick Strahl
  Mar 15, 2019 @ 08:32am

Hello, tks
Just see a litle possible problem with selectedvalue as descibed above

This code will probably ( the 6.21 does ) fail for the selected value

lcSelectedValue = "Item2                      "

*** Cursor Binding - Key Value
CREATE CURSOR TITEMS (Key  varchar(40)

I am at work to edit any cursor data on the web and selected value comes usually from a field value filled with space. ( I don't tested it with your new code )

Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Marcel DESMET
  Rick Strahl
  Mar 15, 2019 @ 08:53am

If would be also usefull if you add some code like

IF ATC(lcAttributes,"class=") < 1
	lcAttributes = lcAttributes + [class="form-control" ]
ENDIF
Gravatar is a globally recognized avatar based on your email address. re: HtmlListBox - Bug 6.21
  Rick Strahl
  Marcel DESMET
  Mar 15, 2019 @ 10:00pm

Selection and Spacing

These controls render values as is including spaces. They always have. So if you render with spaces your selected values have to have spaces too.


*** Selected value to select in listbox
lcSelectedValue = "Item2   "

*** Cursor Binding - Key Value
CREATE CURSOR TITEMS (Key  varchar(40), Value varchar(100) )
INSERT INTO TItems VALUES ("Item1   ","First Item #1 Db")
INSERT INTO TItems VALUES ("Item2   ","Second Item #2 Db")

? HtmlDropDown("lstItemsCursor",lcSelectedValue,"TItems","Key","Value")

produces - correctly - the following:

<select id="lstItemsCursor" name="lstItemsCursor" Size="1"  >
<option value="Item1   " >First Item #1 Db</option>
<option value="Item2   " selected="selected" >Second Item #2 Db</option>
</select>

If you need things trimmed, use a TRIM(key) expression rather than the field name.

Adding form-control

I kind of agree that it would be useful, but I think this is not a good idea because a) it would have then to be added to all input controls, and b) it makes it hard to create a plain textbox. Not everybody is using the bootstrap fields and if you're not it would be a PITA to use because you couldn't force attributes to be empty - you always would have to pass something.

So no, I am not adding that at this point 😃

+++ Rick ---

© 1996-2019