<form:form method="post" action="/changeEnabledResource" modelAttribute="user">
<c:forEach items="${user.resources}" var="resource">
<form:radiobutton path="resources"
value="${resource}"
label="${resource.name}"
checked="${resource.enabled ? 'checked' : ''}/>
</c:forEach>
<input type="submit" value="Submit"/>
</form>
Resource class:
public class Resource {
private Long id;
private String name;
private boolean enabled;
//getters setters
}
User class:
public class User {
private List<Resource> resources;
....
//rest of code
}
With the above code all form:radiobuttons have checked="checked", so the last one is always checked when the form loads. Submitting works correctly and it changes the correct one to enabled and the rest to not enabled (service class handles this). But when the page loads all radio buttons have checked="checked".
Why is this happening, or what would be the correct way to do this so that the resource that IS enabled has the radio button checked?
The answer to this is to NOT use the form:radiobutton(s) tags since they apparently don't work very well. I have yet to find any good examples anywhere using this tag. My solution was just to use plain HTML input tags and use the #RequestParam in the controller method which will pass only the value of the radio button that is checked. And I can easily use ${resource.enabled ? 'checked' : ''} to ensure that the correct one is selected.
Set the selected value in a separate property:
public class User {
private int selectedResourceId;
private List<Resource> resources;
....
//rest of code
}
...
<form:radiobutton path="selectedResourceId"
value="${resource.id}"
label="${resource.name}"/>
...
On page load, initalize the selectedResourceId (based on the resource where enabled flag is true), so that the form:radiobutton tag knows which one is selected when the page is rendered.
Upon form submission, go in the other direction and set the appropriate resource.enabled flag based on the selectedResourceId.
Related
I’m using tapestry 5.3.7, and I want to use Ajax chaining select form elements : If I choose one option in a select element, another select appear to choose another element based on your first choice. I try a sample in the tapestry doc, and adapted for my project. Despite the fact that my custom code is very close to the sample, I always have the following error :
Render queue error in SetupRender[SelectZoneDemo:version]: Component SelectZoneDemo:version must be enclosed by a Form component.
Working sample from the doc (Chaining of select components CarMaker) http://tapestry.apache.org/5.3/apidocs/org/apache/tapestry5/corelib/components/Select.html)
Here is my code :
Template file (.tml)
<t:form>
<p>
<t:errors />
</p>
<p>
<t:select t:id="selectApplicatifs" t:model="selectApplicatifs"
t:value="selectedApplicatif" validate="required" zone= "VersionZone"
t:zone="versionZone" t:encoder="ApplicatifDtoEncoder" />
</p>
<t:zone t:id="versionZone" id="versionZone">
<t:if test="selectedApplicatif">
<p>
<t:select t:id="version" model="selectVersions" t:encoder="VersionDtoEncoder" />
</p>
</t:if>
<p>
<t:submit value="literal:Submit" />
</p>
</t:zone>
</t:form>
Java file
#Inject
private AjaxResponseRenderer ajaxResponseRenderer;
#Inject
private IServiceApplicatif serviceApplicatif;
#Inject
private SelectModelFactory selectModelFactory;
#Property
#Persist
private SelectModel selectApplicatifs;
#Property
#Persist
private String version;
#Property
#Persist
private SelectModel selectVersions;
#Inject
#Property
private ApplicatifDtoEncoder applicatifDtoEncoder;
#Inject
#Property
private VersionDtoEncoder versionDtoEncoder;
#Property
#Persist
private ApplicatifDto selectedApplicatif;
#InjectComponent
private Zone versionZone;
public void onActivate() {
List<ApplicatifDto> listApplicatifs = serviceApplicatif.findAllApplicatifDto();
List<VersionDto> listVersionApplicatifs = new ArrayList<VersionDto>();
selectApplicatifs = selectModelFactory.create(listApplicatifs, "nom");
if (selectVersions == null) {
selectVersions = selectModelFactory.create(listVersionApplicatifs,"version");
}
}
public void onValueChangedFromSelectApplicatifs(ApplicatifDto applicatifDto) {
List<VersionDto> versionList = applicatifDto.getVersionList();
selectVersions = selectModelFactory.create(versionList,"version");
ajaxResponseRenderer.addRender(versionZone);
}
Rendering zones within a form via ajax can get tricky as you have discovered. Fields require a FormSupport instance to be on the Environment stack. This is normally added to the environment as the parent form renders but as you have discovered, when rendering a zone within a form the FormSupport is not available.
Here's a few options:
Have a zone that wraps the entire form and update the whole form via ajax
Instead of refreshing a zone, use some javascript (via JavaScriptSupport) to update the options in an existing select menu
Use the Observe mixin to update zones in the form. Instead of using the core tapestry select component, you could render your own select. This might require you to use #RequestParameter to get the values serverside when the form is finally submitted.
Use the FormInjector. I've never used it myself but I think it somehow spoofs the environmental. I'm not sure how you'd pass the user's selection in the event. I think this component may have also been scrapped in tapestry 5.4.
I have a ListView composed by different fragment which contains text and a link (inside another fragment). The link is visible depending on the state of the listview model.
For simplicity let's say the link is visible depending on a boolean field of the listview model, if it's true is visible, invisible otherwise.
At first the link is visible, I copy the link location (encrypted), I wait for my model to change (i.e. boolean to false) and after I refresh the page the link is gone. (correct!)
If I try to give the URL (copied before) back in the browser I receive a WicketRuntimeException telling me that the listener for this link was not found.
To be more complete the link is inside a fragment:
<wicket:fragment wicket:id="reservationRatingFragment">
<li>
<div>
<img src="/img/good.png" />
</div>
<p>
<a wicket:id="ratingGoodLink" href="#"> <wicket:message
key="messaging.reservation.rating.good" />
</a>
</p>
</li>
</wicket:fragment>
And when I say invisible I mean that I set the markup container of the fragment as .setVisible(false);
Why is this happening? I'm supposing that if I recall a link which is not visible anymore the framework should just skip it and refresh the page I'm currently on (or redirect me to the base page).
If for example I copy the link and I change BasePage (go to the homepage for example), the exception still occurs when I'm recalling the copied URL.
EDITED:
In the first fragment:
WebMarkupContainer msgRatingContainer = new WebMarkupContainer("messageRatingContainer") {
private static final long serialVersionUID = 1L;
#Override
public void onConfigure() {
setVisible(message.getType() == MessageType.RATING);
}
};
if (msgRatingContainer.isVisible()) {
if (message.getType() == MessageType.RATING) {
msgRatingContainer.add(new ReservationRatingFragment("messageRatingSection",
"reservationRatingFragment", this, item, message));
}
The nested fragment (ReservationRatingFragment):
public ReservationRatingFragment(String id, String markupId,MarkupContainer markupContainer, Item item, Message msg) {
super(id, markupId, markupContainer, new Model<Message>(msg));
/* Avoid render container */
setRenderBodyOnly(true);
/* Load button components */
Link<Void> ratingGoodLink = new Link<Void>("ratingGoodLink"){
private static final long serialVersionUID = 1L;
#Override
public void onClick() {
processRating(ReservationEvaluationResult.GOOD);
}
};
add(ratingGoodLink);
Link<Void> ratingBadLink = new Link<Void>("ratingBadLink"){
private static final long serialVersionUID = 1L;
#Override
public void onClick() {
processRating(ReservationEvaluationResult.BAD);
}
};
add(ratingBadLink);
}
Markup for both fragments:
<wicket:fragment wicket:id="messageFragment">
Some content...
<!-- Here goes my fragment with link -->
<ul wicket:id="messageRatingContainer">
<div wicket:id="messageRatingSection"></div>
</ul>
<wicket:fragment wicket:id="reservationRatingFragment">
<li><div>
<img src="/img/messaging/good.png" />
</div>
<p>
<a wicket:id="ratingGoodLink" href="#"> <wicket:message
key="messaging.reservation.rating.good" />
</a>
</p></li>
<li><div>
<img src="/img/messaging/bad.png" />
</div>
<p>
<a wicket:id="ratingBadLink" href="#"> <wicket:message
key="messaging.reservation.rating.bad" />
</a>
</p></li>
</wicket:fragment>
</wicket:fragment>
EDITED:
The processRating just perform a call to a controller (which handle the change in the backend). In the controller I check for the replay attack (if this action is already performed) and if so I throw a runtime exception that lead the user to a warning page (You already rated this message). The fact is, in this case it don't get to this point, since the link is not available it doesn't call the controller and it just throw the InvalidUrlException since the link is not visible.
Wicket version: 1.4.19
Thanks
Your assumption that an invalid link will be ignored or redirect you to the base page is wrong.
Why is that?
If we take a step back, what happens when you click a link? The state of your application changes. However this is only safe to do so if the application is in the state it was when the link was created. If this rule wasn't enforced, you would need to make sure that every single potential state transition is either acceptable or explicitly marked as invalid. This would be highly impractical, if not impossible in most systems. But neglecting this would not only be a security risk but it could result in corrupt data.
It's best to think of it as a case of optimistic locking. (Mostly because it is :)) When the link is created, it is given the version number of the internal state at the time of creation. When the link is clicked, that version number is compared to the current version of the internal state. If the two match, the link is accepted as valid, the internal state is updated and its version number is incremented. If the two numbers don't match, the link is rejected and an exception is thrown because an invalid state transition attempt can't be ignored.
I won't explain how to get around this limitation as it's already been told in another answer, I just wanted to answer the "why" question.
I am not sure I understand the exact reason for your implementation. That said, I would recommend using the BookmarkablePageLink() with PageParameters set to perform your processRating() method upon loading the destination page.
Add your link components:
PageParameters ppGood = new PageParameters("0="+ReservationEvaluationResult.GOOD);
PageParameters ppBad = new PageParameters("0="+ReservationEvaluationResult.BAD);
add(new BookmarkablePageLink("ratingGoodLink", DestinationPage.class, ppGood));
add(new BookmarkablePageLink("ratingBadLink", DestinationPage.class, ppBad));
Then create a new constructor in your DestinationPage:
public class DestinationPage extends WebPage {
public DestinationPage(PageParameters param) {
if(param.getString("0")!=null){
String rating = param.getString("0");
processRating(rating);
}
...
This will give you a link that will be persistent and should allow you to copy and paste the URL.
The only viable solution I found was to extend the RequestCycle and override the onRuntimeException method this way:
#Override
public Page onRuntimeException(Page page, RuntimeException e) {
if(e instanceof InvalidUrlException) {
return new HomePage();
} else {
return super.onRuntimeException(page, e);
}
}
I'm doing web-application. And I have a problem when I edit data
I want to create smth like this
I hope you can help me to find way to do this. I found next variant but I don't know as people usually do this.
Multiply submit in one form.
More than 1 submit in one form.
Or more then one form in 1 JSP
And I should't use any framework. And without javascript.
Thanks
OK, If It helps to understand what I want to get on servlet
I show some part of selvlet
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String page = new String();
Command command = CommandFactory.getCommand(request);
page = command.execute(request);
if (page != null) {
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(page);
dispatcher.forward(request, response);
}
....
}
And CommandFactory
public static Command getCommand(HttpServletRequest request){
Command current = new NoCommand();
String action = request.getParameter("command");
if(action == null || action.isEmpty()){
return current;
}
try{
CommandEnum currentState = CommandEnum.valueOf(action.toUpperCase());
current = currentState.getCurrentCommand();
}
...
}
And CommandEnum
public enum CommandEnum {
EDIT_QUESTION {
{
this.command = new EditQuestionCommand();
}
};
}
And in particular command I do some business logic
Please, help me to find way getting from jsp value as command="delete". With single submit I use hidden field. How we can do the same for several button?
You can use any number of submit buttons in a single form. But name them uniquely so that you can identify easily which button is clicked. Server will not receive name, value pair of buttons that are not clicked. It becomes easy for you to find which button clicked is available as request parameter. Using that you can implement your requirement.
Sample HTML:
<form>
<input type="submit" name="s1" value="S1"/><br/>
<input type="submit" name="s2" value="S2"/>
</form>
On clicking any of these buttons you will see query string as either ?s1=S1 or ?s2=S2
UPDATE 1:
You can have same name for all submit buttons and to identify uniquely, they MUST have different values.
<input type="submit" name="modeOfAction" value="Delete"/><br/>
<input type="submit" name="modeOfAction" value="Update"/>
UPDATE 2:
If you really don't care what the value of each button, then it would be better using unique names for each of the submit buttons.
<input type="submit" name="delete" value="Удалить (Err! I don't know what this text is!)"/><br/>
<input type="submit" name="update" value="Update"/>
There was a time when indeed the optional JavaScript meant: gracefully accept when no JavaScript is present. With the small devices one might think this position might be strengthened again, but:
HTML forms are limited in their usage, as shown above a bit.
DOM usage, like AJAX calls updating part of the page, need JS.
JavaScript user interface possibilities (effects, table sorting, paging, themes, validation) with libraries like jQuery.
I still now a way to get a command=edit: write a servlet filter that translates request parameters. For instance translate a parameter command-NAME = TEXT into command=NAME.
I am developing a registration web app using Struts2 and need some guidance.
Background:
On the registration form, there is a set of five form fields: 1 text box, and 4 drop down select boxes. The five fields describe a person's primary position in an educational setting: the text field allows the user to insert their job title, and the drop down menus allow the user to select what school, institution, department, and division they belong to. The drop down menus are initialized with options that are stored in a database (inside the registration action, array lists are initialized with these values before the form is displayed). For example:
<s:select emptyOption="true" key="school1.schoolId" list="schoolList" listKey="schoolId" listValue="schoolName" required="true" />
Problem:
I need to provide the user with the ability add an X number of secondary positions. On the registration form, a user can click an "add another affiliation" button, and a new set of the 5 form fields are displayed. These fields will also need to be validated, and saved when the user clicks the form's submit button.
What would be the best approach to tackling this problem?
So far, I have only declared array lists for each form field, like so:
private List<String> jobTitles = new ArrayList<String>();
private List<School> schools = new ArrayList<School>();
private List<Institution> institutions = new ArrayList<Institution>();
private List<Department> departments = new ArrayList<Department>();
private List<Division> divisions = new ArrayList<Division>();
But I do not know how to proceed. How do I display the initial 5 fields for the primary position? If I use Javascript to insert new form fields dynamically, how do I initialize the dynamic drop down menus with the options stored in the database? How do I retain these values if the page is reloaded?
Any help is appreciated - thanks!
The basic problem you need to tackle is how to get an indexed list of request parameters into your action class. This is quite simple, and I think you are on the right track by starting off by creating Lists of input parameters. I found a bit of documentation on the subject here. Basically you can have form fields with names like jobTitles[0], jobTitles[1] which would be used to populate the jobTitles List.
However, I think the concept of 'Affiliation' deserves a class of it's own:
class UserAffiliation {
private String title;
private String schoolId;
private String institutionId;
private String departmentId;
private String divisionId;
// Make sure that there is a no-args constructor (default or explicit) for Struts to create instances.
// Add getters and setters
}
In your action class:
private List<UserAffiliation> affiliations;
...
// getter and setter for affiliations
Would be enough to capture the user input.
Your jsp could look something like:
<form action=".." method="post">
<div class="affiliation">
<s:textfield name="affiliations[0].title"/>
<s:select name="affiliations[0].schoolId" list="schools" listKey="schoolId" listValue="schoolName"/>
...
</div>
<s:if test="affiliations != null && affiliations.size > 1">
<s:iterator value="affiliations" begin="1" status="status">
<s:textfield name="affiliations[%{#status.index + 1}].title"/>
<s:select name="affiliations[%{#status.index + 1}].schoolId" list="schools" listKey="schoolId" listValue="schoolName"/>
...
</s:iterator>
</s:if>
....
</form>
<div id="affilationTemplate" style="display:none;">
<div class="affiliation">
<s:textfield name="affiliations[__IDX__].title"/>
<s:select name="affiliations[__IDX__].schoolId" list="schools" listKey="schoolId" listValue="schoolName"/>
</div>
...
</div>
Note the div affilationTemplate. You could use JS to get the html of this template, replace __IDX__ with the appropriate index, and append to the form contents when the user clicks on the 'add another affiliation' button. This makes sure that the newly added select boxes are pre-populated with appropriate values.
The iterator block displays what ever the values the user had already submitted (with the exception of the 'primary affiliation', which is already displayed above it).
NOTE: You should of course, try to get rid of the repeated form elements if possible. I would try with extracting them into an include.
My command object have a list of objects. I want to bind a text field to the attribute of the object inside that list. Is it possible to do in Spring MVC?
Command object class
public class SubDevisonDto {
private String devId;
private List subDevisions;
Subdevision object class mentioned in the list
public class SubDivison implements Serializable{
private String subDivisonName;
private String createdBy;
private String createdDate;
private String developerID;
private List users;
I want text box to set the value for subDivisonName field.
I have written the Spring MVC tags like this.
<spring:bind path="subdivisondto.subDevisions[0].subDivisonName">
<span class="formw">
<input name="subDivisonName" type="text" style="width:350px;" />
</span>
</spring:bind>
Just for test purpose I have given it as 0. If it's working I can make it to a variable. my requirement is, I should let the user to dynamically add subdevision objects. So, initially when page is loading I will just show one text box. I will give a button for him to add if he want to add more. I will dynamically generate text boxes when he clicks the add button. After that I have to submit the form with the list.
This jsp code gives me an error. It says:
org.springframework.beans.NullValueInNestedPathException
Is there anyway for me to do this in jsp code?
I found the answer for my question. But, it's not the solution for my requirement as I need to implement a dynamic list. but I found a solution for this question.
As I understood, first time we have to send data from back end to bind input elements. I didn't find a way to bind form elements which takes input without sending a list data from beck end. But when we send data and bind the elements, we can take input from those elements. So, I think to bind the element in a situation like this we need to send data first time. Correct me if this statement is wrong. Because, that would be a more good solution for me.
We need to use the lazy list and jsp code is bit modified.
Your command class object should be created as below mentioned.
import org.apache.commons.collections.list.LazyList;
import org.apache.commons.collections.FactoryUtils;
public class SubDevisonDto {
private String devId;
private List subDevisions =
LazyList.decorate(
new ArrayList(),
FactoryUtils.instantiateFactory(SubDivison.class));
JSP code should look like below.
<c:forEach items="${subs.subDevisions}" var="obj" varStatus="gridRow">
Binding an input element text box
<spring:bind path="subdivisondto.subDevisions[${gridRow.index}].subDivisonName">
<span class="formw"><input name="<c:out value="${status.expression}"/>" type="text" style="width:350px;" />
binding an input element check box. This input element makes a list.
<spring:bind path="subs.subDevisions[${gridRow.index}].users">
<c:forEach items="${obj.users}" var="dependenttwo" varStatus="dependentRowtwo">
<li>
<input name="<c:out value="${status.expression}"/>" type="checkbox" class="users" value="<c:out value="${dependenttwo}"/>"/>
<c:out value="${dependenttwo}"/>
</li>
</c:forEach>
</spring:bind>
`subs` is a map key name. the value for this key `subs` is a list of my DTO objects which named as `SubDevisonDto `
This code works fine for me.
Thanks the support given.
In dto :
private List<SubDivision> SubDivisions = new AutoPopulatingList<SubDivision>(new SubDivisionFactory());
and factory would be something like:
public class SubDivisionFactory implements AutoPopulatingList.ElementFactory<SubDivision> {
public String createElement(int index) {
SubDivision subDivision = new SubDivision();
return subDivision;
}
}
using AutopopulatingList from spring. And your jsp will look the same, you can iterate over as many as you want.