Of course it would happen that my first Grails project presents a crazy mismatch between my data model and the presentation the UI designers want.
Here is a simplified statement of the problem space:
There are three ingredients in the grocery store: carrots, celery, and tomatoes. The purpose of the app is to save the user's shopping list: how many of each to buy.
The web designers want to accomplish this with multiple HTML SELECTs, so you select from the drop-down which ingredient you want to buy, then type the quantity next to it. If you want more ingredients, you click a JavaScript link that adds more SELECTs.
The design specifies that each drop-down is the same and that the number of lines are unlimited. So you can get a form back that has 5 lines, corresponding to 3 carrots, 9 celery, 2 celery, 5 carrots, and 1 tomato.
What I "should" produce out of this is an order for 8 carrots, 11 celery, and one tomato.
Not getting into all of the arguments about why this is bad UI design, I want to understand, practically, how to map the model/controller to the view given this kind of mismatch, both to submit and ultimately edit a stored submission.
My initial idea is:
However, as I read about Command objects, I wonder if that would be a better approach.
I've read through many pages online but don't see any solutions for this kind of MVC mismatch.
Setting aside the obvious answer (fight the designers), what is the "Grails" way to handle this?
I would think your initial idea should work. A command object would be nice to move the logic of building the domain objects out of the controller methods, but not NEEDED. One could result in easier to read code, and some easier validation if you ever add more info to your shoppingList (name, date, etc). But something without a cmd object should work and I don't think would be wrong...
GSP:
<g:form .......>
<div><g:select name="ingredient" from="${['Carrots','Celery','Tomato']}"><g:textField name="amount"/></div>
<div><g:select name="ingredient" from="${['Carrots','Celery','Tomato']}"><g:textField name="amount"/></div>
<div><g:select name="ingredient" from="${['Carrots','Celery','Tomato']}"><g:textField name="amount"/></div>
<div><g:select name="ingredient" from="${['Carrots','Celery','Tomato']}"><g:textField name="amount"/></div>
</g:form>
Controller:
def saveCart = {
def shoppingList = [:]
def ingredients = params.list('ingredient')
def amounts = params.list('amount')
ingredients.eachWithIndex() { obj, i ->
if (shoppingList.containsKey(obj)) {
shoppingList[obj] = shoppingList[obj] + amounts[i]
} else {
shoppingList[obj] = amt[i]
}
}
// shoppingListshould have everything you need now
....
....
}