I'm trying to make the following work in Tapestry.
I have a Dictionary<String, Dictionary<String, Object>> which contains my data.
I'm trying to accomplish that I have 1 drop-down menu (Select component) which contains the keys from outer Dictionary.
When that selection changes, grid should be updated with the keys and values from the selected sub-dictionary.
For example:
Dictionary<String, Dictionary<String, Object>> dictionaries = new Hashtable<String, Dictionary<String, Object>>();
Dictionary<String, Object> dict1 = new Hashtable<String, Object>();
Dictionary<String, Object> dict2 = new Hashtable<String, Object>();
dict1.put("k1", "d1v1");
dict1.put("k2", "d1v2");
dict2.put("k1", "d2v1");
dict2.put("k2", "d2v2");
dictionaries.put("d1", dict1);
dictionaries.put("d2", dict2);
Would anyone would be so kind to give me an example or push me in the right direction?
EDIT:
I managed to get the first part working, with grid contents changing depending on which keys from outer dictionary are selected.
However, I I'm having problems with updating the grid and saving the changes:
I am using my own GridDataSource:
public class EntityDataSource<T> implements GridDataSource {
private Class<T> persistentClass;
protected List<T> data;
protected int count = -1;
protected int startIndex = 0;
public EntityDataSource(Class<T> persistentClass, List<T> data) {
this.persistentClass = persistentClass;
this.data = data;
}
public static final <T> EntityDataSource<T> create(
Class<T> persistentClass, List<T> data) {
return new EntityDataSource<T>(persistentClass, data);
}
public int getAvailableRows() {
return this.data.size();
}
public void prepare(int startIndex, int endIndex,
List<SortConstraint> sortConstraints) {
this.startIndex = startIndex;
this.data = this.data.subList(startIndex, endIndex + 1);
}
public Object getRowValue(int index) {
return this.data.get(index - this.startIndex);
}
#SuppressWarnings("rawtypes")
public Class getRowType() {
return this.persistentClass;
}
}
My grid looks like this:
<t:form t:id="configSelectForm">
<t:select t:id="storageKeySelecter"
t:model="storageKeyModel"
t:value="storageKey"
zone="configZone" />
</t:form>
<t:zone t:id="configZone" id="configZone">
<t:form t:id="configReviewForm">
<table width="100%">
<t:grid t:source="configurationEntrySource"
t:add="update, delete"
t:row="configurationEntry"
t:mixins="DisableGridSorting"
t:include="configKey, configValue"
t:encoder="configurationEntryEncoder">
<p:configValueCell>
<input t:id="value" t:type="TextField" t:value="configurationEntry.configValue"
t:validate="required" t:context="configurationEntry.configValue" />
</p:configValueCell>
<p:updateCell>
<t:actionlink t:id="update" zone="configZone" context="[configurationEntry.configKey, configurationEntry.configValue]">Update</t:actionlink>
</p:updateCell>
<p:deleteCell>
<t:actionlink t:id="delete" zone="configZone" context="configurationEntry.configKey">Delete</t:actionlink>
</p:deleteCell>
</t:grid>
</table>
<br></br>
<!-- <input type="submit" value="Update" class="button" /> -->
</t:form>
</t:zone>
I have managed to make a delete link work, however, I cannot seem to update the value for the arbitrary key.
When I click the link to update, the value from the text field is not the one that is being passed:
public Object onActionFromUpdate(String configKey, String configValue) {
// my stuff here
return request.isXHR() ? configZone.getBody() : null;
}
The configValue is the value of the entry that currently exist and not the one I'm trying to change it to.
Is there a way to get that value? My grid has an an arbitrary number of rows.
EDIT2: Even more info provided
This is my TML:
<t:form t:id="configSelectForm">
<t:select t:id="storageKeySelecter"
t:model="storageKeyModel"
t:value="storageKey"
zone="configZone" />
</t:form>
<br/>
<t:zone t:id="configZone" id="configZone" elementName="div">
<form t:type="form" t:id="configReviewForm" id="configReviewForm" t:zone="configZone" zone="configZone">
<table width="100%">
<t:grid t:source="configurationEntries"
t:add="update, delete"
t:row="configurationEntry"
t:mixins="DisableGridSorting"
t:include="configKey, configValue"
t:encoder="configurationEntryEncoder" >
<p:configValueCell>
<input t:id="configValueTextField" t:type="TextField" t:value="configurationEntry.configValue"
t:validate="required" />
</p:configValueCell>
<p:updateCell>
<t:actionlink id="update" t:id="update" zone="configZone" t:context="[configurationEntry.configKey, configurationEntry.configValue]">Update</t:actionlink>
</p:updateCell>
<p:deleteCell>
<t:actionlink id="delete" t:id="delete" zone="configZone" t:context="configurationEntry.configKey">Delete</t:actionlink>
</p:deleteCell>
</t:grid>
</table>
<br/>
<input type="submit" value="Update" class="button" zone="configZone"/>
</form>
</t:zone>
<br/>
<br/>
<t:form t:id="addNewEntryForm">
<table width="100%">
<tr>
<td>
<input t:id="newEntryKey" t:type="textfield" t:value="newEntry.configKey"
t:validate="required" t:context="newEntry.configKey" />
</td>
<td>
<input t:id="newEntryValue" t:type="textfield" t:value="newEntry.configValue"
t:validate="required" t:context="newEntry.configValue" />
</td>
<td>
<input type="submit" value="Add New Entry" zone="configZone"/>
</td>
</tr>
</table>
</t:form>
This is my JAVA:
public class PropertyConfiguration {
#Inject
private BeanModelSource beanModelSource;
#Component
private Form configReviewForm;
#Property
private List<ConfigurationEntry> configurationEntries;
private List<ConfigurationEntry> persistentEntries;
#Property
private ConfigurationEntry configurationEntry = new ConfigurationEntry("", "");
#Property
private ConfigurationEntryEncoder configurationEntryEncoder;
#InjectComponent
private Zone configZone;
#InjectComponent
private TextField configValueTextField;
#Inject
private ConfigurationPersitanceDAO dao;
private GridDataSource dataSource;
#Inject
private Messages messages;
#Property
private ConfigurationEntry newEntry;
#Inject
private Request request;
#Property
#Validate("required")
#Persist(PersistenceConstants.SESSION)
private String storageKey;
private StringSelectModel storageKeysSelectModel;
public ValueEncoder<ConfigurationEntry> getConfigurationEntryEncoder() {
initConfigurationEntityEncoder();
return this.configurationEntryEncoder;
}
public BeanModel<ConfigurationEntry> getModel() {
return beanModelSource.createDisplayModel(ConfigurationEntry.class, messages);
}
public SelectModel getStorageKeyModel() {
if (storageKeysSelectModel == null) {
storageKeysSelectModel = new StringSelectModel(this.dao.getStorageKeys());
}
return storageKeysSelectModel;
}
private void initConfigurationEntityEncoder() {
if (this.configurationEntryEncoder == null) {
this.configurationEntryEncoder = new ConfigurationEntryEncoder(dao, storageKey);
}
}
private void initZoneData() {
if (this.storageKey == null) {
this.storageKey = this.dao.getStorageKeys().get(0);
}
initConfigurationEntityEncoder();
}
public Object onActionFromDelete(String configKey) {
System.out.println("Deleting from: " + storageKey + " entry: " + configKey);
this.dao.deleteConfigurationEntry(storageKey, configKey);
return request.isXHR() ? configZone.getBody() : null;
}
public Object onActionFromUpdate(String configKey, String configValue) {
this.dao.updateConfigurationEntry(storageKey, configKey, configValue);
return request.isXHR() ? configZone.getBody() : null;
}
void onActivate(String storageKey) {
initZoneData();
this.newEntry = new ConfigurationEntry("", "");
}
String onPassivate() {
this.newEntry = new ConfigurationEntry("", "");
return this.storageKey;
}
Object onRefresh() {
return request.isXHR() ? configZone.getBody() : null;
}
Object onSuccessFromAddNewEntryForm() {
String configKey = this.newEntry.getConfigKey();
String configValue = this.newEntry.getConfigValue();
this.dao.addConfigurationEntry(storageKey, configKey, configValue);
return request.isXHR() ? configZone.getBody() : null;
}
void onValidateFromAddNewEntryForm() {
return;
}
Object onValueChangedFromStorageKeySelecter(String storageKey) {
this.storageKey = storageKey;
initConfigurationEntityEncoder();
this.configurationEntries = wrap(this.dao.getConfiguration(storageKey));
return configZone.getBody();
}
private void updateChangedConfigurations(List<ConfigurationEntry> changedEntries) {
for (ConfigurationEntry changedEntry : changedEntries) {
String configKey = changedEntry.getConfigKey();
String configValue = changedEntry.getConfigValue();
System.out.println("Updated: [" + storageKey + ":" + configKey + ":" + configValue + "]");
this.dao.updateConfigurationEntry(storageKey, configKey, configValue);
}
}
void onValidateFromConfigReviewForm() {
this.persistentEntries = wrap(this.dao.getConfiguration(storageKey));
List<ConfigurationEntry> tmpList = new ArrayList<ConfigurationEntry>();
for (ConfigurationEntry newEntry : this.configurationEntries) {
for (ConfigurationEntry oldEntry : this.persistentEntries) {
System.out.println("NewEntry: " + newEntry.toString() + " vs. OldEntry: " + oldEntry.toString());
if (oldEntry.getConfigKey().equals(newEntry.getConfigKey())) {
if (!oldEntry.getConfigValue().equals(newEntry.getConfigValue())) {
newEntry.setConfigValue(newEntry.getConfigValue().trim());
tmpList.add(newEntry);
}
}
}
}
this.persistentEntries = tmpList;
}
Object onSuccessFromConfigReviewForm() {
updateChangedConfigurations(this.persistentEntries);
return request.isXHR() ? configZone.getBody() : null;
}
/**
* Wraps dictionary entries in instances of ConfigurationEntry
*/
private List<ConfigurationEntry> wrap(
Dictionary<String, Object> rawConfiguration) {
Set<String> keySet = new TreeSet<String>();
List<ConfigurationEntry> wrappedEntries = new ArrayList<ConfigurationEntry>();
Enumeration<String> keys = rawConfiguration.keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
keySet.add(key);
}
for (String key : keySet) {
String value = (String) rawConfiguration.get(key);
ConfigurationEntry entry = new ConfigurationEntry(key, value);
wrappedEntries.add(entry);
}
return wrappedEntries;
}
}
For some reason, when the "Update" action link is clicked the values passed to the public Object onActionFromUpdate(String configKey, String configValue) aren't the ones I just wrote into the designated textfield, but the ones that were fetched from my database when page was rendered.
For example, if I had these pairs initially:
key1 => value1
key2 => value2
key3 => value3
and I wanted to change value for key2 to "newValue2" the parameters passed to the method are "key2" and "value2" instead of "key2" and "newValue2".
The same problem is the reason the mass-update doesn't work. All the values in configurationEntries are shapshot values from the database instead of the values currently written in my grid.
So, my question would be how I can update my DB from editable grid using AJAX for my concrete example. I've tried many things suggested on SO and rest of internet, but they don't seem to work and I don't know why.
You need to use the zone parameter.
Take a look at the SelectZoneDemo.tml and SelectZoneDemo.java from the select component's javadoc. It gives an example of updating a zone when a select changes.
For more complex interactions, you might be interested in this
To have actual values from inputs you need to submit form. As you use ActionLink the values from its context are used (this values was saved in context during link rendering and can't be changed on client side without hacking).
To have your example working you can use separate form for each row. You will also need some submit component that can work outside the form:
<t:zone t:id="configZone" id="configZone">
<table width="100%">
<t:grid t:source="configurationEntrySource"
t:add="update, delete"
t:row="configurationEntry"
t:mixins="DisableGridSorting"
t:include="configKey, configValue"
t:encoder="configurationEntryEncoder">
<p:configValueCell>
<t:form t:id="configReviewForm" zone="configZone">
<input t:id="value" t:type="TextField" t:value="configurationEntry.configValue"
t:validate="required" t:context="configurationEntry.configValue" />
</t:form>
</p:configValueCell>
<p:updateCell>
<t:customlinksubmit form="configReviewForm">Update</t:customlinksubmit>
</p:updateCell>
<p:deleteCell>
<t:actionlink t:id="delete" zone="configZone" context="configurationEntry.configKey">Delete</t:actionlink>
</p:deleteCell>
</t:grid>
</table>
<br/>
</t:zone>
CustomLinkSubmit:
#SupportsInformalParameters
public class CustomLinkSubmit implements ClientElement {
#Parameter(required = true, allowNull = false, defaultPrefix = BindingConstants.COMPONENT)
private Form form;
#Parameter(allowNull = false, defaultPrefix = BindingConstants.LITERAL)
private SubmitMode mode = SubmitMode.NORMAL;
#Inject
private ComponentResources resources;
#Inject
private JavaScriptSupport javascriptSupport;
private String clientId;
#BeginRender
void beginRender(MarkupWriter writer) {
clientId = javascriptSupport.allocateClientId(resources);
writer.element("span", "id", clientId);
resources.renderInformalParameters(writer);
}
#AfterRender
void afterRender(MarkupWriter writer) {
writer.end();
JSONObject spec = new JSONObject()
.put("form", form.getClientId())
.put("clientId", clientId)
.put("validate", mode == SubmitMode.NORMAL);
javascriptSupport.addInitializerCall(InitializationPriority.EARLY, "linkSubmit", spec);
}
public String getClientId() {
return clientId;
}
}
Related
I wonder if anyone can help, I'd like to Iterate over ArrayList but One item at a time with help of some button so when I press that button it would show me the next item in the list and so forth. Or if there's another way I'd be happy to take any advice. I'm trying to design a test so a student would get one question at a time he/she would submit the answer and it would move to the next question. This is what I have as showing full list on JSP.
My Servlet
String vassId = request.getParameter("vassId");
List<Assessment> qList = new ArrayList<Assessment>();
Assessment qObj = null;
DbConnection dbConn = null;
Connection conn = null;
CallableStatement proc = null;
response.setContentType("text/html");
ResultSet rs = null;
try {
dbConn = new DbConnection();
conn = DbConnection.connection();
String dbCall = "{ ? = call pa_customer_admin.fn_list_question(?) }";
proc = DbConnection.connection().prepareCall(dbCall);
proc.registerOutParameter(1, OracleTypes.CURSOR);
proc.setInt(2, Integer.parseInt(vassId));
proc.execute();
rs = (ResultSet) proc.getObject(1);
while (rs.next()) {
qObj = new Assessment();
qObj.setVassId(Integer.parseInt(rs.getString(1)));
qObj.setDescr(rs.getString(2));
qObj.setQuesStatus(rs.getString(3));
qObj.setQuesTypeCode(rs.getString(4));
qObj.setCreatedDate(rs.getString(6));
qObj.setQuestion(rs.getString(7));
qObj.setMark(rs.getString(8));
qObj.setTimeLimit(rs.getInt(9));
qList.add(qObj);
}
request.setAttribute("qObj", qObj);
request.setAttribute("qList", qList);
proc.close();
JSP
<form action="AnswerSaveProcess" method="POST" >
<c:if test="${empty qList}">
Empty list
</c:if>
<c:if test="${! empty qList}">
<c:forEach items="${qList}" var="q">
<label>Question</label>
<input type="hidden" value="<%= vassId%>">
<textArea readonly="readonly">${q.question}</textarea>
<input type="text" value="${q.mark}" readonly="readonly">
<input type="hidden" id="userTime" value="${q.timeLimit}" />
<label>Answer 1</label>
<input type="text" ><input name="ansStatusCode" type="radio"><br/>
<label>Answer 2</label>
<input type="text" ><input name="ansStatusCode" type="radio"><br/>
<input type="submit" name="submit" value="Save Answer">
</c:forEach>
</c:if>
</form>
ArrayList implements the Iterable interface and has index-based access to its members. All you need is to read some Java docs on usage examples.
Try something like (untested):
final List<String> questions = Arrays.asList(new String[]{"question1", "question2", "question3"});
JButton b = new JButton("Press Me");
final JLabel label = new JLabel();
final cnt = 0;
b.addActionListener(new ActionListener(){
pubic void actionPerformed(ActionEvent e) {
label.setText(question.get(cnt++));
if(cnt > questions.size()) cnt = 0;
}
});
JFrame frame = new JFrame();
frame.getConentPane().add(b);
frame.getConentPane().add(label);
frame.setSize(800,600);
frame.setVisible(true);
As it's an ArrayList you can use indexing. When the button is pressed increment the index and get the next item from the ArrayList.
Example
package items;
import java.util.List;
public class GetNextItem {
private static int itemIndex;
private List<String> itemList;
// Constructor with itemList
public GetNextItem(List<String> itemList) {
this.itemList = itemList;
itemIndex = 0; // start at the first item.
}
/**
* Get the current Item from the itemList
* #return the current item from the itemList or NULL if all the items are processed.
*/
public String getItem() {
if (itemIndex >= itemList.size()) {
return null; // end of list
}
return itemList.get(itemIndex);
}
/**
* Get the next Item from the itemList
* #return the next item from the itemList or NULL if all the items are processed.
*/
public String getNextItem() {
itemIndex ++;
return getItem();
}
}
Elements of an ArrayList can easily be accessed by index.
From a web page (built by JSP), you can request a specific question using a query parameter, e.g. showquestion.jsp?question=4.
The JSP-generated page can then include a button to show next question by generating a new link (Next) with the next higher index, as long as there are more questions.
so I have an extendedDataTables as follows(Code is shortened to keep it straightforward).
<rich:extendedDataTable value="#{package.packageList}" var="o"
styleClass="listStyle" selection="#{package.selection}"
selectionMode="single">
<a4j:ajax execute="#form" event="selectionchange"
listener="#{package.selectionListener}" render=":res" />
<rich:column>
<f:facet name="header">Package ID</f:facet>
#{o.packageID}
</rich:column>
</rich:extendedDataTable>
So when the user clicks on this it outputs the details of it to another table inside the a4j:outputPanel that follows.
<a4j:outputPanel id="res">
<rich:panel header="Selected Package"
rendered="#{not empty package.selectionPackage}">
</rich:panel>
</a4j:outputPanel>
This part works. However this new detail now contains several variables and also an arrayList of objects with which I need to also be able to select. So this arrayList generates its own extendedDataTable which I need to then select and retrieve its information. This part is where it is breaking. What I have attempted so far looks as follows.
<a4j:outputPanel id="res">
<rich:panel header="Selected Package"
rendered="#{not empty package.selectionPackage}">
<rich:dataTable value="#{package.selectionPackage}"
var="extensionTable" styleClass="listStyle" selectionMode="single">
<rich:column>
<rich:extendedDataTable value="# {extensionTable.extensionList}"
var="selectedExtension" styleClass="listStyle" style="height:200px;"
selection="#{package.extensionSelection}" selectionMode="single">
<a4j:ajax execute="#form" event="selectionchange"
listener="#{package.selectionExtensionListener}" render=":extensions" />
<rich:column>
<f:facet name="header">Extension Add on list</f:facet>
#{selectedExtension.extensionName}"
</rich:column>
</rich:extendedDataTable>
</rich:column>
</rich:dataTable>
</rich:panel>
</a4j:outputPanel>
I have another a4j panel to handle the new extensions selected object. The problem is that my selectedExtensionListener is not being called. I do not know why, is what I am trying even possible. The selection is working as the rows are changing colour however the selectionExtensionListener is never being called. I have some system.out.printlnts in just to check and whereas the first listener is being called the second one is not. Forgive me if this is obvious or not even possible but I am relatively new to jsf. Any help would be greatly appreciated.
I will copy and paste my bean below to show you the backend of the code. I will exclude declaring all of my variables and populating my lists and objects etc as it will just clog up the code, if you need them just let me know and I will edit them in. (Sorry for formatting, I do not know if you can format code here?)
public class Package implements Serializable{
public void selectionListener(AjaxBehaviorEvent event) {
System.out.println("In selection listener");
UIExtendedDataTable dataTable = (UIExtendedDataTable) event.getComponent();
Object originalKey = dataTable.getRowKey();
selectionPackage.clear();
for (Object selectionKey : selection) {
dataTable.setRowKey(selectionKey);
if (dataTable.isRowAvailable()) {
selectionPackage.add((PackageClass) dataTable.getRowData());
}
}
dataTable.setRowKey(originalKey);
}
public void selectionExtensionListener(AjaxBehaviorEvent event) {
System.out.println("Testing 1");
UIExtendedDataTable dataTable = (UIExtendedDataTable) event.getComponent();
Object originalKey = dataTable.getRowKey();
selectionExtension.clear();
for (Object selectionKey : extensionSelection) {
dataTable.setRowKey(selectionKey);
if (dataTable.isRowAvailable()) {
System.out.println("Testing 2");
selectionExtension.add((ExtensionClass) dataTable.getRowData());
}
}
dataTable.setRowKey(originalKey);
}
public Collection<Object> getSelection() {
return selection;
}
public void setSelection(Collection<Object> selection) {
this.selection = selection;
}
public Collection<Object> getExtensionSelection() {
return extensionSelection;
}
public void setExtensionSelection(Collection<Object> extensionSelection) {
this.extensionSelection = extensionSelection;
}
public List<PackageClass> getPackageList() {
return packageList;
}
public void setPackageList(ArrayList<PackageClass> packageList) {
this.packageList = packageList;
}
public PackageClass getSelectionPackage() {
if (selectionPackage == null || selectionPackage.isEmpty()) {
return null;
}
return selectionPackage.get(0);
}
public void setSelectionPackage(ArrayList<PackageClass> selectionPackage) {
this.selectionPackage = selectionPackage;
}
public ArrayList<PackageClass> getSelectionPackages() {
return selectionPackage;
}
public ExtensionClass getSelectionExtension() {
if (selectionExtension == null || selectionExtension.isEmpty()) {
return null;
}
return selectionExtension.get(0);
}
public void setSelectionExtension(ArrayList<ExtensionClass> selectionExtension) {
this.selectionExtension = selectionExtension;
}
public ArrayList<ExtensionClass> getSelectionExtensions() {
return selectionExtension;
}
}
I have been working on a Spring project that makes use of the Spring form taglib (http://www.springframework.org/tags/form).
I am using some multiple select boxes to indicate some options (Country, factory,...)When I pass an entire list to the select - all is well: the first option of the select list is selected by default. However, when a user is from a specific country, the list is filtered and only his country is shown. In this case the first element is not selected by default.
JSP page:
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:select path="countryValues" multiple="true" size="9" style="width:192px;" cssErrorClass="field-error">
<form:options items="${command.countries}" itemValue="countryCode" itemLabel="correctDisplayString"/>
</form:select>
Command.java
public List<CountryMaster> getCountries() {
return countries;
}
public void setCountries(List<CountryMaster> countries) {
this.countries = countries;
}
Controller.java
#RequestMapping(value = "/overview", method = RequestMethod.GET)
public String overview(HttpServletRequest request, Model model) {
Attrs attrs = getAttrs(request);
UserLocale.initUser(getUser(request));
User user = UserLocale.getUser();
List<FactoryMaster> factoryList = getFactoryList(attrs);
List<CountryMaster> countryList = getCountryList(attrs);
Command command = initCommand(attrs);
model.addAttribute(command);
if(user.hasRole(User.NORMAL)&& user.getCountryCode() != null){
if(countries == null){
countries= getDaoBuilder().getDaoCountry().countryMap();
}
String isoCode = countries.get(user
.getCountryCode());
List<CountryMaster> buffer = new ArrayList<CountryMaster>();
for(CountryMaster i : countryList){
if(isoCode.equalsIgnoreCase(i.getIsoCode())){
buffer.add(i);
}
}
System.out.println("List size: "+buffer.size());
command.setCountries(buffer);
}
else{
command.getCountries().addAll(getCountryList(attrs));
}
command.getModels().addAll(getModelList(attrs));
command.setBrands(getBrandList(attrs));
return "/reporting/overview";
}
private List<CountryMaster> getCountryList(Attrs attrs) {
List<CountryMaster> result = new ArrayList<CountryMaster>();
CountryMaster ct = new CountryMaster(CountryMaster.ISO_COUNTRY_JOKER, 00);
ct.setDescription("ALL");
result.add(ct);
result.addAll(attrs.countryList);
return result;
}
On the HTML page, I can see in other lists that the first element has the attribute selected="selected". Anybody have any idea why this is not the case when I manipulate my list? Or does anyone know what is resposible for this selected attribute allocation? (Is this javascript, java attribute,...?)
Thanks in advance!
Turns out the value of the listbox can be set: this piece of code made it quite an easy fix:
public String overview(HttpServletRequest request, Model model) {
Attrs attrs = getAttrs(request);
UserLocale.initUser(getUser(request));
User user = UserLocale.getUser();
List<FactoryMaster> factoryList = getFactoryList(attrs);
List<CountryMaster> countryList = getCountryList(attrs);
Command command = initCommand(attrs);
model.addAttribute(command);
if(user.hasRole(User.NORMAL)&& user.getCountryCode() != null){
if(countries == null){
countries= getDaoBuilder().getDaoCountry().countryMap();
}
String isoCode = countries.get(user
.getCountryCode());
List<CountryMaster> buffer = new ArrayList<CountryMaster>();
for(CountryMaster i : countryList){
if(isoCode.equalsIgnoreCase(i.getIsoCode())){
buffer.add(i);
}
}
System.out.println("List size: "+buffer.size());
command.setCountries(buffer);
// FIXED SELECTION OF ELEMENT
command.setFactoryValues(new String[]{isoCode});
// FIXED SELECTION OF ELEMENT
}
else{
command.getCountries().addAll(getCountryList(attrs));
}
command.getModels().addAll(getModelList(attrs));
command.setBrands(getBrandList(attrs));
return "/reporting/overview";
}
This way, you set the value of the listbox using code, and when the page is opened - the value is already there, making it selected by default.
I am using JSF 1.2 framework. Right now i am trying to implement a file upload process in which the number of files to be uploaded is controlled by the end user. Please find the below snapshot and code snippet for reference.
XHTML Implementation:-
<a4j:commandLink action="#{importWSDLBean.xsdLoopIncrementAction}" reRender="WSDLPanelGrid">
<h:graphicImage value="/images/plus_icon.gif" />
</a4j:commandLink>
<a4j:commandLink action="#{importWSDLBean.xsdLoopDecrementAction}" reRender="WSDLPanelGrid">
<h:graphicImage value="/images/minus_icon.gif" />
</a4j:commandLink>
<h:panelGrid id="WSDLPanelGrid">
<c:forEach items="#{importWSDLBean.acscDataList}" var="inputFUpload">
<t:inputFileUpload id="#{inputFUpload.id}" value="#{inputFUpload.value}" />
</c:forEach>
</h:panelGrid>
Java Bean Implementation:-
public String xsdLoopIncrementAction() {
if (acscDataList == null) {
acscDataList = new ACSCDataList(new ArrayList());
HtmlInputFileUpload htmlUpload = new HtmlInputFileUpload();
htmlUpload.setId("upload" + (acscDataList.size() + 1));
acscDataList.add(htmlUpload);
} else {
HtmlInputFileUpload htmlUpload = new HtmlInputFileUpload();
htmlUpload.setId("upload" + (acscDataList.size() + 1));
acscDataList.add(htmlUpload);
}
return "success";
}
public String xsdLoopDecrementAction() {
if (acscDataList != null) {
if (acscDataList.size() > 0) {
acscDataList.remove(acscDataList.size() - 1);
}
}
return "success";
}
This implementation resets the file upload values whenever i increment or decrement the no. of file upload fields. Also when i submit the form i cant able to get the UploadedFile object (File Upload prerequisite such as Form type and Web.xml configuration is also included).
Can anyone help me out?
If you create dinamically yours input uploads? with binding property
<h:panelGrid binding="#{importWSDLBean.myPanelGrid}"></h:panelGrid>
in your backing bean add property
private javax.faces.component.html.HtmlPanelGrid myPanelGrid;
/**
* #return the myPanelGrid
*/
public javax.faces.component.html.HtmlPanelGrid getMyPanelGrid() {
return myPanelGrid;
}
/**
* #param myPanelGrid the myPanelGrid to set
*/
public void setMyPanelGrid(javax.faces.component.html.HtmlPanelGrid myPanelGrid) {
this.myPanelGrid = myPanelGrid;
}
/*change for your value upload type*/
Map<String,Object> values = new LinkedHashMap<String, Object>();
public void addInputAction() {
String key = "key"+values.size();
values.put(key,"newValue");
HtmlInputText input = new HtmlInputText();
/*add input property (converter,css,etc?)*/
input.setId("id_"+key);
input.setValueExpression("value", createValueExpression(
"#{WSDLPanelGrid.values['"+key+"']}", new Class[0], String.class));
/*add to panel grid your input*/
myPanelGrid.getChildren().add(input);
}
public static ValueExpression createValueExpression(String value,
Class[] params, Class returnType) {
FacesContext fctx = FacesContext.getCurrentInstance();
ELContext elctx = fctx.getELContext();
Application jsfApp = fctx.getApplication();
ExpressionFactory exprFactory = jsfApp.getExpressionFactory();
ValueExpression valueExpr = exprFactory.createValueExpression(elctx,
value, returnType);
return valueExpr;
}
Does something prevent you from using JSF 2? Primefaces ( www.primefaces.org ) has a multiple fileupload component. It is available for JSF 1.2, but development will go on for JSF 2 only.
Background
Use Ajax to fire an event to the web server when a list of items are selected. The element is a JSF rich:orderingList item.
Problem
The class that must receive the event:
public class BusinessAreaListHandler extends ListHandler<ListElement> {
private static final long serialVersionUID = -581048454118449233L;
public BusinessAreaListHandler() { load(); }
public List<ListElement> getBusinessAreas() { return getList(); }
public Set<ListElement> getSelection() { return getSet(); }
public void select() {
System.out.println( "Clicked Element" );
}
protected void load() {
appendList( new ListElement( "employee" ) );
appendList( new ListElement( "company" ) );
appendList( new ListElement( "payroll" ) );
}
}
The ListElement container object:
public class ListElement implements Serializable {
private static final long serialVersionUID = 5396525520175914504L;
public final static char SEPARATOR = ':';
private String id, value;
protected ListElement( String value ) {
this( Integer.toString( value.hashCode() ), value );
}
public ListElement( String id, String value ) {
setId( id );
setValue( value );
}
#Override
public int hashCode() {
return (53 * (getId().hashCode() + 5)) + (53 * (getValue().hashCode() + 5));
}
#Override
public boolean equals( Object obj ) {
ListElement le = null;
if( obj != null && obj instanceof ListElement ) {
le = (ListElement)obj;
}
return le == null ? false : compare( le );
}
private boolean compare( ListElement le ) {
return getId().equals( le.getId() ) && getValue().equals( le.getValue() );
}
public String getId() {
return this.id == null ? "" : this.id;
}
public void setId( String id ) {
this.id = id;
}
public String getValue() {
return this.value == null ? "" : this.value;
}
public void setValue( String value ) {
this.value = value;
}
#Override
public String toString() {
return getValue();
}
}
The ListConverter:
public class ListConverter implements Converter {
#Override
public Object getAsObject( FacesContext fc, UIComponent ui, String value ) {
ListElement result = new ListElement( value );
int index = value.lastIndexOf( ListElement.SEPARATOR );
System.out.println( "Convert FROM: " + value );
if( index > 0 ) {
String id = value.substring( 0, index );
String v = value.substring( index + 1 );
result = new ListElement( id, v );
}
System.out.println( "Convert TO : " + result.toString() );
return result;
}
#Override
public String getAsString( FacesContext fc, UIComponent ui, Object value ) {
return value.toString();
}
}
The XHTML fragment that sets up the list and event actions:
<h:panelGrid columns="2">
<h:panelGroup>
<rich:orderingList value="#{businessAreas.list}" var="businessArea" converter="businessAreaConverter" immediate="true" orderControlsVisible="false" fastOrderControlsVisible="false" selection="#{businessAreas.selection}" id="BusinessAreas">
<f:facet name="caption">
<h:outputText value="Business Areas" />
</f:facet>
<rich:column>
<h:outputText value="#{businessArea}" />
</rich:column>
<a4j:support event="onclick" ignoreDupResponses="true" requestDelay="500" action="#{businessAreas.select}" reRender="ColumnClusters" />
<a4j:support event="onkeyup" ignoreDupResponses="true" requestDelay="500" action="#{businessAreas.select}" reRender="ColumnClusters" />
</rich:orderingList>
</h:panelGroup>
<h:panelGroup>
<rich:listShuttle sourceValue="#{columnClusters.list}" targetValue="#{domainContent.list}" var="columnCluster" converter="columnClusterConverter" sourceRequired="false" targetRequired="true" moveControlsVisible="true" orderControlsVisible="false" fastOrderControlsVisible="false" sourceCaptionLabel="Column Clusters" targetCaptionLabel="Domain Content" copyTitle="Move" copyControlLabel="Move" copyAllControlLabel="Move All" copyAllTitle="Move All" id="ColumnClusters">
<rich:column>
<h:outputText value="#{columnCluster}" />
</rich:column>
</rich:listShuttle>
</h:panelGroup>
<h:panelGroup>
<h:commandButton action="action" value="Create Domain" />
</h:panelGroup>
</h:panelGrid>
The corresponding managed bean is set in faces-config.xml correctly.
Browser output:
Error Message
The following error message is displayed:
INFO: WARNING: FacesMessage(s) have been enqueued, but may not have been displayed.
sourceId=j_id2:ColumnClusters[severity=(ERROR 2), summary=(j_id2:ColumnClusters:
Validation Error: Value is required.), detail=(j_id2:ColumnClusters: Validation Error:
Value is required.)]
Logging
New Element (Hash:Value): 1193469614:employee
New Element (Hash:Value): 950484093:company
New Element (Hash:Value): -786522843:payroll
New Element (Hash:Value): 3373707:name
New Element (Hash:Value): -1147692044:address
New Element (Hash:Value): 114603:tax
New Element (Hash:Value): 1193469614:employee
Convert FROM: employee
Convert TO : employee
New Element (Hash:Value): 950484093:company
Convert FROM: company
Convert TO : company
New Element (Hash:Value): -786522843:payroll
Convert FROM: payroll
Convert TO : payroll
New Element (Hash:Value): 3373707:name
Convert FROM: name
Convert TO : name
New Element (Hash:Value): -1147692044:address
Convert FROM: address
Convert TO : address
New Element (Hash:Value): 114603:tax
Convert FROM: tax
Convert TO : tax
Question
What is required to trigger a call to select() in BusinessAreaListHandler when users select (or deselect) items?
References
http://anonsvn.jboss.org/repos/richfaces/branches/community/3.3.X/samples/richfaces-demo/src/main/java/org/richfaces/demo/tree/Library.java
http://anonsvn.jboss.org/repos/richfaces/branches/community/3.3.X/samples/richfaces-demo/src/main/webapp/richfaces/orderingList/example/playlist.xhtml
http://livedemo.exadel.com/richfaces-demo/richfaces/orderingList.jsf
Richfaces combobox on selection changed event
Thank you!
The problem is this attribute:
targetRequired="true"
Since the click triggers an immediate Ajax request to the server, it is expected that the right-hand shuttle (the target) has data. Without data, the validation error will be posted.