'Rebind' form bean values in webflow after submit. What's wrong?
Hi guys.
I'm using spring-framework-3.2.0.RELEASE, spring-webflow-2.3.1.RELEASE with Spring Security, Thymleaf template engine + Tiles2 support.
I have sub-flow inside a 'main execution flow' and I'm trying to create 'view/add/edit' functionality in sub-flow for form bean and entity behind it.
The problem I'm facing is following.
I can render entity from formBean on page, I modify DOM tree by JS code and then changed data is posted to webflow. When I try to save that 'updated' formBean after 'POST' made from page, I'm getting 'previous' data rather then data 'POSTED' by browser.
I have following sub-flow definition:
Code:
<input name="venueForm" required="false" type="com.web.form.venue.FormBeanVenueField" />
<on-start>
<evaluate expression="venuePlaceController.initializeForm()" result="flowScope.venueForm"/>
</on-start>
<view-state id="showMap" view="event/registerEvent/selectVenue/showMap" model="venueForm">
<on-render>
<evaluate expression=............... />
</on-render>
<transition on="create" to="createVenue"/>
<transition on="select" to="endVenueFieldOk"/>
<transition on="edit" to="editVenue"/>
</view-state>
<view-state id="createVenue" view="event/registerEvent/selectVenue/addVenue" model="venueForm">
<on-render>
</on-render>
<transition on="cancel" to="showMap" validate="false"/>
<transition on="save" to="showMap">
<evaluate expression="venuePlaceController.saveVenuePlace(
externalContext, flowScope.venueForm, messageContext)"/>
</transition>
</view-state>
<view-state id="editVenue" view="event/registerEvent/selectVenue/addVenue" model="venueForm">
<on-entry>
<evaluate expression="venuePlaceController.initializeFormByVenueId(flowScope.venueForm)"
result="flowScope.venueForm"/>
</on-entry>
<on-render>
............
</on-render>
<transition on="save" to="showMap">
<evaluate expression="venuePlaceController.saveVenuePlace(
externalContext, venueForm, messageContext)"/>
</transition>
</view-state>
..............
Here is a simplified code for clarity.
Code:
public class FormBeanVenueField implements Serializable {
private String venueId; // selected venue Id
private List<String> venueFieldNames = new ArrayList<>(0);
............ // the rest is skipped
}
@Controller
public class VenuePlaceController {
public FormBeanVenueField initializeForm() {
FormBeanVenueField venueForm = new FormBeanVenueField();
}
public FormBeanVenueField initializeFormByVenueId(FormBeanVenueField venueForm) {
if (venueForm != null && venueForm.getVenueId() != null && !venueForm.getVenueId().isEmpty()) {
// get Entity by Id from database and create form bean
venueForm = new FormBeanVenueField(entity);
}
return venueForm;
}
public org.springframework.webflow.execution.Event saveVenuePlace(
ExternalContext externalContext,
@Valid FormBeanVenueField formBean, MessageContext messageContext) {
// make form bean validations and return result
if (formBean.venueFieldNames.size() <= 0) { // break point HERE to view received data
....... // generate error
MessageBuilder errorMessageBuilder = new MessageBuilder().error();
messageContext.addMessage(errorMessageBuilder.build());
return new EventFactorySupport().error(this);
}
........
// when all is ok, create Entity from 'form bean' data and save entity to database
return new EventFactorySupport().success(this);
}
}
HTML code is written by thymeleaf library syntax. Here is simplified: event/registerEvent/selectVenue/addVenue.html
I use that page for 'create' and 'edit' cases.
Code:
<form method="post" th:action="${flowExecutionUrl}" action='' th:object="${venueForm}" id="form">
............
<input type="text" name="venueFieldNames[0]" value="0" />
<input type="text" name="venueFieldNames[1]" value="1" />
<input type="text" name="venueFieldNames[2]" value="2" />
<button id="cancelBtn" type="submit" name="_eventId_cancel" >Cancel</button>
<button id="saveBtn" type="submit" name="_eventId_save" >Save</button>
</form>
1. The state <view-state id="createVenue".. works fine. I can render a 'empty' page. Add several 'input controls' to DOM model by JS code and then submit all data by 'onclick' handler on 'Save'. The data comes to saveVenuePlace(.......) method and save to DB.
2. When I try <view-state id="editVenue" .... state I don't get correct data which actually submitted by page AFTER data editing and DOM model modifications.
Say, I have several 'input' controls rendered by <view-state id="editVenue" .... state on page initially.
Then I modify DOM model by JS code and POST changed data, say only ONE input value, to state. I can see only ONE input data (venueFieldNames[1]=1) posted to my 'editVenue' state.
The problem I have... I see ALL three input data values (instead on one) on break point inside method :
public org.springframework.webflow.execution.Event saveVenuePlace(.......) {
if (formBean.venueFieldNames.size() <= 0) {
.......
}
So it looks like... 1) data posted by page is not bind to form bean, 2) binded form bean values are overwritten by webflow and I get 'initial data' instead of 'updated data' from page.
Most probably, there is something I don't know about webflow. Is it possible to make such functionality ? How better to solve that issue?
How properly do 'Binding parameterized / indexed property'
Ok, I'm continue...Dancing with myself (song by Billy Idol, 1981)
http://4.bp.blogspot.com/_rJBmix_SFs...ence-poesy.jpg
OMG
Just in 2006 year people could help to each other. How fast time is passing... :D
Spring become more complex and there are almost few people who can give advice, but despite of that they are moving to Spring v.4 !!!
But those topics are not quite helpful now
Creating complex Domain Objects from Web MVC
http://forum.springsource.org/showth...-Web-MVC/page2
Binding Custom Object to Collection
http://forum.springsource.org/showth...dexed+property
Binding checkboxes to Enums and possible bug in Booking demo
http://forum.springsource.org/showth...dexed+property
Quote:
This is a known limitation with today's EL-based binding systems.
The Spring BeanWrapper can do this type of conversion when binding to parameterized lists; however it's only enableable in Spring MVC view environments. To turn it on, configure the "useSpringBeanBinding" flag on a custom MvcViewFactoryCreator instance.
Spring EL will generally solve this problem in the Spring Framework 3.0 timeframe.
Keith
(Looks like it's still limitation......)
I'm still curious if I should go with:
PropertyEditor
http://static.springsource.org/sprin...ty-editors-tbl
or
should I go with
Spring 3 Type Conversion
http://static.springsource.org/sprin...l#core-convert
or with
Customizing WebDataBinder initialization
http://static.springsource.org/sprin...-webdatabinder
or may be kick off Spring approach and make custom code like:
Complex forms & Springs’ ServletRequestDataBinde
http://log4p.com/2006/05/31/complex-...estdatabinder/
indexed data, indexed property, parameterized properties, parameterized property
WOW, YAHOOOOO
I've found freaky good and simple solution for 'indexed data' and 'parameterized properties' used in form bean class.
It's easy to avoid 'index out of bound' exception after dynamic adding form elements by JS code.
Thank you very much all who viewed that thread hundred times and couldn't give any advice.