Implementing Value Lists
Whenever I build an application, one of the requirements is to support the concept of "value lists" for populating drop downs, lists of radio buttons and the like. I created an approach to handling this a few years back with my procedural generator which has worked out really well for me and I wanted to document that as well as updating it to work with service layers and DAOs (the old system had queries built into the value list scripts). Any feedback appreciated . . .



Now, the tricky part - on the first form load, the value User.get("BillAddressState") would be totally fine. However, on the second form load, this value would not be appropriate as it would not reflect the previous form selection (but would instead reset to the default form value). Does that make sense?
How do you handle the "selected" form value changing form form load to form load if the "Value" in question is not persisted in an object (ie. you wouldn't re-init the User object with the current form values - User.set("billaddres...", form.billaddres...) - as the user's billing value might not be the property in question such as in an order checkout page).
My flow on "returning" pages (where a form is being submitted is to load the form values into the appropriate object and run validations in it, so the controller looks something like:
User = UserService.new();
User.loadStructure(form);
Valid = User.validate();
If Valid
xxx
Else
yyy
And because I pass User back to the form, all of the form fields are automatically prepopulated with the appropriate values.
Make sense?
Take a silly example: a shipping service web site where you have to select your country / state before you enter the site (so that they can adjust shipping weights and info for your locale). Now, let's say that country / state combo needs to be validated. This form really has nothing to do with a user object (arguably). So, for that kind of a scenario, where is the state / country kept? would you still create some sort of "Address" object, load the form into that, and then validate it:
Address.Load( form ).
Address.validate().
Sorry - this one is kind of mired in the middle of my system so it is pretty dependent on a set of base classes and the like so I can't really pull it out. Sorry about that!
Yes - it allows for a comma delimited list of selected values. In an "add" situation, it'd take the default values from the bean. In an edit situation, it'd use the existing values.
I want your job! I am always thinking about ways to abstract everything to the nth degree in the way that you do, but I am too bound up in needing to get things done...
One idea I had was to represent a value list using a struct of arrays, where the name of the struct is the name of your list eg "products", each key is a field name (productname, productid etc.), and the value of each key is an array with two elements: the first is the field value, and the second is "isSelected." This struct would be able to take care of most of your dsl as described in your post. I haven't gotten around to trying it yet but in theory it should work.
Keep rockin' your blog, I learn a lot here.
Interesting approach - will have to think about that more, and glad you're enjoying the blog!
It was a little late last night, so I thought I'd try to clarify my approach using your states example.
Suppose you already had your query with your name/value columns, and your selectedlist. To load up your "valueStruct" you'd do something like:
<cfset var s = structNew() />
<cfloop query="q">
<cfset s[name] = arrayNew(1) />
<cfset s[name][1] = value>
<cfset s[name][2] = iif(ListFindNoCase(arguments.selectedlist,name),'true','false')>
</cfloop>
<cfreturn s />
Your valueStruct is all loaded up and ready to go.
Then to output, for example a dropdown:
<cfset s = ValueStruct.get(params to your method) />
<select name="states">
<cfloop collection="s" item="statename">
<option value="#s[statename][1]#" selected="#s[statename][2]#">#s[statename]#</option>
</cfloop>
</select>
The nice thing is that since everything is associated in the struct you don't have to worry about name/value mapping. Your point about valid variable names is certainly valid. I think you could do something like replacing whitespaces with a delimiter of some sort on the way into the struct, and then remove them on the way out to overcome that limitation.
The other possible downside would be the ordering of the struct keys, not exactly sure how that would play out. You generally don't want your states coming out any other way than alphabetically. I haven't messed with ordering a struct so I'm not sure how that would be handled.
still, interesting approach!
How about a 2-dimensional array - the first dimension would have the same number of elements as the value list, the second dimension would have 3 elements. Something like
states[1][1] = "Arkansas"
states[1][2] = "AR"
states[1][3] = false
states[2][1] = "California"
states[2][2] = "CA"
states[2][3] = true
etc.
This handles both the variable naming issue, since you are not using the name as a struct key or array index, and the ordering issue, since the array would maintain whatever order you set. The code to load up and output the array would be similar to the struct idea, just looping over an array instead of a struct.
Always good to look at different solutions :->