passing property value using javascript - java

I am new to struts 2. I have a jsp page which will send a column ID to another jsp page which will send it to the action class where i will get the comments entered by user and return it to my second jsp page to display it as a popup to the user. problem is my javascript is not accepting the value of the column.
//THIS IS WHERE THE PROBLEM IS IN THE JAVA SCRIPT
<display:column title="Commentaire" sortable="true" sortProperty="Commentaire" class="alerte_td_commentaire">
<s:if test="#attr.row.Commentaire != null && #attr.row.Commentaire != ''">
<a href='#' onclick='javascript:var xx = (%{#attr.row.id}).val(); CommenatireToGet(xx);'><img src='/img/icons/ico_comment.png'></a>
</s:if>
</display:column>
//THIS IS MY SECOND JSP PAGE
function CommenatireToGet(value){
$('#divShowCommAcqui').dialog('option', 'position', 'center');
$('#divShowCommAcqui').dialog('open');
var path = buildURL("/valorisation/ajax/CommenatireToGet.do");
$.getJSON(
path,
{idAlerte:value},
function(json){
$('#commentaireAqui').val=getElementbyId(json.hello);
}
)
};
//THIS IS MY ACTION CLASS
public String getComment() throws ServiceException{
jsonData = new LinkedHashMap<String, Object>();
idAlerte= (Integer) getActionSession("idAlerte");
Alerte alerte =svc.retrieve(idAlerte);
if (alerte !=null){
jsonData.put("hello",alerte.getCommentaire());
}
return SUCCESS;
}
//THIS IS MY STRUS TAG
<action name="CommenatireToGet" class="ihm.valorisation.AlerteAction" method="getComment">
<result name="success" type="json">
<param name="root">jsonData</param>
</result>
</action>

You can't use OGNL expressions anywhere in the JSP, only in Stuts2 tag's attributes, even not all of them. So, change
<a href='#' onclick='javascript:var xx = (%{#attr.row.id}).val(); CommenatireToGet(xx);'><img src='/img/icons/ico_comment.png'></a>
to
<a href='#' onclick='CommenatireToGet(<s:property value="%{#attr.row.id}"/>);'><img src='/img/icons/ico_comment.png'></a>

Related

Struts2 - How to repopulate form having dynamically generated fieldnames (via expression) with submitted values after validation error

We have a Struts2 application where we are building survey feature using which application users will be able to create surveys by adding different questions.
These questions are comprised of question text and an html control for getting response.
The html controls so far supported are single and multi-select list, text field, textarea, checkbox and radiobox.
So the survey form renders displaying all questions added by the user where each question has its question text displayed followed by the html field control selected for that question.
Basically, it is a dynamic form where form field names are being dynamically generated as all surveys will be different and therefore there are no properties in the Action class backing survey form fields.
We are generating form field name using prefix question_ appended with database id of the question to represent each question response input field uniquely. Here is a snippet from our JSP page to make things clear.
<s:form id="surveyForm" action="survey/submitFeedback">
<s:iterator value="surveyQuestions">
<p class="form-group <s:if test="%{fieldErrors.get('question_' + surveyQuestionId).size() > 0}">has-error</s:if>" >
<label class="control-label" >
<s:property value="questionText"/>
</label>
<s:if test="required" ><span style='color:red'>*</span></s:if>
<br>
<s:if test="surveyQuestionType.type == #com.reach150.enumeration.SurveyQuestionTypeEnum#OPENENDED_TEXTFIELD" >
<s:textfield name="question_%{surveyQuestionId}" cssClass="form-control" maxlength="charactersLimit" />
</s:if>
<s:elseif test="surveyQuestionType.type == #com.reach150.enumeration.SurveyQuestionTypeEnum#OPENENDED_TEXTAREA" >
<s:textarea name="question_%{surveyQuestionId}" style="height: 150px; width: 400px;" cssClass="form-control" maxlength="charactersLimit" />
</s:elseif>
<s:elseif test="surveyQuestionType.type == #com.reach150.enumeration.SurveyQuestionTypeEnum#SINGLESELECTDROPDOWN || surveyQuestionType.type == #com.reach150.enumeration.SurveyQuestionTypeEnum#MULTISELECTDROPDOWN" >
<s:select name="question_%{surveyQuestionId}" list="orderedSelectOptions" listKey="optionValue" listValue="optionLabel" emptyOption="true" multiple="true" cssClass="form-control" />
</s:elseif>
<s:else>
<s:radio name="question_%{surveyQuestionId}" list="#{'true':'Yes','false':'No'}" cssClass="radioMarginRight" />
</s:else>
<span class="help-block" for="question_${surveyQuestionId}">
<s:fielderror cssClass="font-bold text-danger">
<s:param>question_<s:property value="surveyQuestionId" /></s:param>
</s:fielderror>
</span>
<br/>
</p>
</s:iterator>
<button type="submit" class="btn btn-primary btn-lg pull-right "><s:if test="survey.requestReferral == true">Next</s:if><s:else>Done</s:else></button>
</s:form>
On form submit, in the action class we are using HttpServletRequest to get submitted form field values. The way we identify which question the answer belongs to is through the request parameter name which as can be seen in the above JSP snippet starts with prefix 'question_' followed by question Id. So we split the parameter name to get the question id and associate value against that question.
The problem we are facing is with repopulating survey form with submitted values when the page is presented back to the user in case of validation error as the parameter names are dynamic and cannot be backed by properties defined in Action class.
I have tried to populate radio button and textarea fields using the below code and several other ways but to no avail
<s:textarea name="question_%{surveyQuestionId}" style="height: 150px; width: 400px;" cssClass="form-control" maxlength="charactersLimit" value="#parameters.%{'question_' + surveyQuestionId}" />
<s:radio name="question_%{surveyQuestionId}" value="#parameters.%{'question_' + surveyQuestionId}" list="#{'true':'Yes','false':'No'}" cssClass="radioMarginRight" />
Below is the action mapping for survey submit action
<action name="survey/submitFeedback" class="surveyAction" method="submitFeedback">
<result name="success" type="tiles">survey.submit</result>
<result name="error" type="tiles">survey.view</result>
<param name="public">true</param>
</action>
Here is the code in Action class handling the submit logic:
private Integer npsScore = 0;
private Map<String, String[]> surveyResponseQuestionAnswerMap = new HashMap<>();
public String submitFeedback() {
try {
if (requestId == null) {
addActionError("Request Id missing! Invalid Request!");
throw new Exception("Invalid Request!");
}
surveyRequest = surveyService.getSurveyRequestByUUID(requestId);
if (surveyRequest == null) {
addActionError("Request Id Invalid! Invalid Request!");
throw new Exception("Request Id Invalid! Invalid Request!");
}
loadQuestionAnswersMap();
validateSurveyFeedback();
if (hasErrors()) {
throw new Exception("Error submitting response!");
} else {
surveyService.parseAndSaveSurveyResponse(surveyRequest, surveyResponseQuestionAnswerMap);
setSurveyCustomMessages(surveyService.getSurveyCustomMessagesSettingBySurveyId(survey.getSurveyId()));
}
return SUCCESS;
} catch (Exception e) {
addActionError("Error submitting response!");
logger.error(e);
loadSurvey();
return ERROR;
}
}
private void loadQuestionAnswersMap() {
HttpServletRequest httpRequest = ActionUtil.getRequest();
Enumeration<String> parameterNames = httpRequest.getParameterNames();
while (parameterNames.hasMoreElements()) {
String parameterName = parameterNames.nextElement();
if (parameterName.startsWith("question_")) {
String[] values = httpRequest.getParameterValues(parameterName);
if (values != null) {
surveyResponseQuestionAnswerMap.put(parameterName, values);
}
}
}
}
private void validateSurveyFeedback() throws Exception {
HttpServletRequest httpRequest = ActionUtil.getRequest();
Survey survey = surveyRequest.getSurvey();
if (survey.isUseNetPromotorScore()) {
String npsScoreStr = httpRequest.getParameter("npsScore");
if (StringUtils.isBlank(npsScoreStr)) {
this.addFieldError("npsScore", "Answer is required");
} else {
setNpsScore(Integer.valueOf(npsScoreStr));
}
}
List<SurveyQuestion> requiredQuestions = surveyQuestionService.getRequiredSurveyQuestionsForSurvey(surveyRequest.getSurvey());
for (SurveyQuestion requiredQuestion : requiredQuestions) {
Integer requiredQuestionId = requiredQuestion.getSurveyQuestionId();
String requiredQuestionFieldParameterName = "question_" + requiredQuestionId;
logger.info("Required Question Field Parameter Name: " + requiredQuestionFieldParameterName);
String[] answers = httpRequest.getParameterValues(requiredQuestionFieldParameterName);
if (answers == null) {
this.addFieldError(requiredQuestionFieldParameterName, "Answer is required");
} else {
boolean noValue = true;
for (String answer : answers) {
if (StringUtils.isNotBlank(answer)) {
noValue = false;
break;
}
}
if (noValue) {
this.addFieldError(requiredQuestionFieldParameterName, "Answer is required");
}
}
}
}
We have finally solved the problem. The initial implementation was heading in a completely wrong direction but thanks to the clue from #RomanC, we re-factored the code and removed the direct use of HttpServletRequest to finally have a working solution. Core idea was to use a Bean for capturing response and have a List of those beans in the Action class corresponding to each survey question. On form submit, response is captured into the bean objects behind the scene by framework itself and thus available for further logic processing in submit handler action method.

Unable to implement Struts 2 token interceptor with hyperlink

I tried to implement token interceptor with the <s:url .. tag but its showing error on the first click. i.e.
The form has already been processed or no token was supplied, please try again.
I want to implement this interceptor, because if users already deleted a row and refresh the page once again then the same action should not perform once again.
<s:url id="linkdelete" action="DeleteLatestUpload.action" namespace="/admin/insecure/upload">
<s:param name="latestUploadId" value="latestUploadId"></s:param>
<s:token name="token"></s:token>
</s:url>
Clear current Uploads
and my struts.xml:
<action name="DeleteLatestUpload" class="v.esoft.actions.UploadExcel" method="deleteUploads">
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="basicStack"></interceptor-ref>
<result name="success" type="tiles"> uploadforward</result>
<result name="invalid.token" type="tiles">uploadforward </result>
</action>
The s:token tag merely places a hidden element that contains the
unique token.
There's not need to use token with url, because the form should be submitted. If you want to pass some token as a parameter then you need to use s:param tag.
Define the parameter
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String execute() throws Exception {
Map<String, Object> context = ActionContext.getContext().getValueStack().getContext();
Object myToken = context.get("token");
if (myToken == null) {
myToken = TokenHelper.setToken("token");
context.put("token", myToken);
}
token = myToken.toString();
return SUCCESS;
}
in the JSP
<s:url var="linkdelete" namespace="/admin/insecure/upload" action="DeleteLatestUpload" ><s:param name="struts.token.name" value="%{'token'}"/><s:param name="token" value="%{token}"/></s:url>
The most simple way to use token with url is to use <s:token/> tag to set token value into session and retrieve it in <s:param> tag.
<s:token/>
<s:url var="..." action="...">
<s:param name="struts.token.name" value="'token'"/>
<s:param name="token" value="#session['struts.tokens.token']"/>
</s:url>

Retaining values between multiple JSPs and Actions in Struts 2

My Struts project structure is as follows:
page1->action1->page2->action2->page3
What i need is for a value i entered in an input tag in page1 to be accessed in action2.
Here is my code:
page1:
<div class = "container">
<s:form id = "idinput" method = "post" action = "idEntered">
Enter id: <input id = "txtid" name = "txtid" type = "text" />
<input id = "cmdsubmit" name = "cmdsubmit" type = "submit" value = "enter details" />
</s:form>
</div>
action1:
public class AddId extends ActionSupport {
private int txtid;
//getter and setter
#Override
public String execute() throws Exception {
return "success";
}
}
page2:
<div class = "container">
<s:form id = "formvalues" method = "post" action = "formEntered">
<p>Your id entered is: <s:property value = "txtid" /></p>
First name: <input id = "txtfname" name = "txtfname" type = "text" />
Last name: <input id = "txtlname" name = "txtlname" type = "text" />
Age: <input id = "txtage" name = "txtage" type = "text" />
<input id = "cmdform" name = "cmdform" type = "submit" value = "submit form" />
</s:form>
</div>
action2:
public class AddForm extends ActionSupport {
private String txtfname;
private String txtlname;
private int txtage;
private int txtid;
//getters and setters
#Override
public String execute() throws Exception {
return "success";
}
}
and displaying everything in
page3:
<div class = "container">
ID: <s:property value = "txtid" /><br>
first name: <s:property value = "txtfname" /><br>
last name: <s:property value = "txtlname" /><br>
age: <s:property value = "txtage" />
</div>
this is where I face a problem as txtid is displayed as null, from which I inferred that the value is not passed from page2 to action2
a solution i have come up with is to use
<s:hidden value = "%{txtid}" name = "txtid2 />
in my form in page2 which will allow me to use the value of txtid as txtid2 in action2, this however seems more like a hack than an actual solution, so any other suggestions are welcome.
In the situation where you want to keep the field values passed from one action to another you could configure the scope of the field. Just place the same field with getters and setters in each action, in your case it will be action1 and action2. The field name is txtid. As well as scope interceptor doesn't include in the defaultStack you should reference it in the action configuration.
For example:
<action name="action1" class="com.package.action.AddId">
<result>/jsp/page2.jsp</result>
<interceptor-ref name="basicStack"/>
<interceptor-ref name="scope">
<param name="key">mykey</param>
<param name="session">txtid</param>
<param name="autoCreateSession">true</param>
</interceptor-ref>
</action>
<action name="action2" class="com.package.action.AddForm">
<result>/jsp/page3.jsp</result>
<interceptor-ref name="scope">
<param name="key">mykey</param>
<param name="session">txtid</param>
<param name="autoCreateSession">true</param>
</interceptor-ref>
<interceptor-ref name="basicStack"/>
</action>
Now you have the scope with the key mykey and field txtid under it. Providing accessors to the field in each action will make transfer field value from one action to another.
In the example above used the basicStack which is a skeleton for the interceptor stack and it does not include some interceptors including a validation interceptor.
If you need to have other features to your actions, you should either construct a custom stack or reference other interceptors in the action configuration.

Struts2 Repopulate form information when validation fails

I have a page with a form that is prepopulated with user information. It is a user profile page. I have validation for some of the fields in place but currently my validation method is just hard coded to execute addFieldError("exp", "Cats"); where exp is a variable that is being validated and Cats is a random message. The form has selects and a doubleselect which I am repopulating by executing actions in the jsp. (Seen Below)
This is the entire form:
<s:form action="%{formAction}" method="post" enctype="multipart/form-data">
<div id="buttons">
<s:submit value="Save" />
</div>
<div id="left_column" class="divStyle">
<div id="picture">
<div id="picture_border">
Picture should go here 150px x 150px
</div>
<s:file name="upload" label="File" />
</div>
<hr />
<div id="contact" class="divPad">
<h3>Contact Information</h3>
<s:textfield name="email" value="%{profile.email}" required="true" />
</div>
<hr />
<div id="availabilityDuration" class="divPad">
<h3>When Available</h3>
<s:textfield name="whenAvailable" value="%{profile.whenAvailable}" />
<h3>Availability Length</h3>
<s:textfield name="availabilityLength" value="%{profile.availabilityLength}" />
<h3>Desired Credit</h3>
<s:action name="CreditSelectAction" executeResult="true" />
</div>
</div>
<div id="right_column" class="divStyle">
<div id="basic_info" class="divPad">
<h4>College & Major</h4>
<s:action name="CollegeMajorsSelectAction" executeResult="true" />
<hr />
<h4>Years of Work Experience</h4>
<s:action name="ExpYearsSelectAction" executeResult="true" /> <hr />
<h4>Undergrad</h4>
<s:action name="UndergradSelectAction" executeResult="true" /> <hr />
<h4>Graduation Year</h4>
<s:action name="GradYearSelectAction" executeResult="true" />
</div>
<hr />
<div id="aboutDescription" class="divPad">
<h3>About Me</h3>
<s:textarea name="comments" value="%{profile.comments}" cols="40" rows="10" />
</div>
<hr />
<div id="skillsNeeds" class="divPad">
<h3>Skills</h3>
<div id="userSkillList">
<s:iterator value="profile.skills" status="status">
<div>
<h5 class="formLabels">Skill Description</h5>
<s:textfield name="userSkillDescription_%{#status.count}" value="%{description}" />
<h5 class="formLabels">Years of Experience</h5>
<s:textfield name="userSkillExperience_%{#status.count}" value="%{experience}"/>
<h5 class="removeSkillLink" onclick="removeUserSkill(this);">Remove Skill</h5>
</div>
</s:iterator>
<h5 class="addSkillLink" id="addSkill" onclick="addUserSkill();">Add New Skill</h5>
</div>
</div>
</div>
</s:form>
The dropdowns are populating alright. The problem is that the values that I thought would be saved in the value stack and retained upon reloading the jsp (%{formAction}, %{profile.email}, etc.) are not being retained when I reload the jsp. How do I capture these values and present them when the page is reloaded after the failed validation? I have tried adding them to the session, but that tends to get messy and I'm not sure how to get that to work with the formAction.
Code from struts.xml:
<action name="updateProfile" class="profiles.actions.UpdateProfileAction" method="execute">
<!-- <interceptor-ref name="basicStack"/>
<interceptor-ref name="fileUpload">
<param name="allowedTypes">image/jpeg,image/gif,image/png,image/jpg</param>
</interceptor-ref>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/> -->
<result name="success">/index.jsp</result>
<result name="input">/jsp/editProfile.jsp</result>
</action>
Code snippet from the Action that loads the form:
public String execute()
{
// get the user profile
String result = "success";
//If the profile is null, then the user is new and does not yet have a profile
//NOTE: If the user's profile doesn't exist, when trying to view someone else's
//profile, they will be redirected to edit their own.
if(user.intValue() == 0)
{
logger.info("New User Detected. Returning Failure.");
result = "failure";
}
else
{
//If the userid is null, we are loading the user's profile
//Otherwise, we are viewing someone else's profile
if(userid == null)
userid = user.toString();
profile = dao.selectCurUserById(Integer.parseInt(userid));
// get all of my projects
this.setMyProjects(projectDAO.selectMyProjects(Integer.parseInt(userid)));
// get all of the projects i've been invited to
this.setJoinedProjects(projectDAO.selectJoinedProjects(Integer.parseInt(userid)));
}
return result;
}
Code snippet from that Action that updates the user profile:
public String execute()
{
// request that sent from the client
HttpServletRequest request = ServletActionContext.getRequest();
Map<String, Object> session = ActionContext.getContext().getSession();
profile = new UserProfile();
id = ((authentication.beans.User) session.get("currentUser")).getId();
profile.setId(id);
profile.setEmail(email);
profile.setAvailabilityLength(availabilityLength);
profile.setComments(comments);
profile.setUndergrad(Integer.parseInt(undergrad));
profile.setWhenAvailable(whenAvailable);
profile.setYear(year);
profile.setCredit(credit);
profile.setMajor(Major.getMajor(major));
profile.setCollege(College.getCollege(college));
profile.setExp(exp);
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yy");
profile.setModify(sdf.format(new GregorianCalendar().getTime()));
//If file is not null, then the user is uploading an image for his/her
//profile
if(file != null)
{
byte[] b = new byte[(int) file.length()];
try
{
new FileInputStream(file).read(b);
b = Base64.encode(b);
}
catch (IOException e)
{
// TODO Auto-generated catch block
profile.setComments(profile.getComments() + "\n" + e.getMessage());
}
profile.setPic(b);
}
// get all of the params and then process the user skills
HashMap<String,String[]> params = (HashMap<String,String[]>)request.getParameterMap();
// process the user skills
profile.setSkills(processSkills(params));
// add the userid to the skills
for(int i = 0; i < profile.getSkills().size(); i++){
profile.getSkills().get(i).setUserID(profile.getId());
}
//TODO: Check the result and do error handling
boolean result = dao.updateProfile(profile);
return "success";
}
UPDATE
The problem was pretty much what coding_idiot said. In the action for loading the form, I needed to have getters for the information to initially populate the form (had this). In the action for updating the information, I needed to have setters for the information put into the form AND a getter for where to get the new information if the form should be repopulated after a failed validation. I fixed this by populating the profile object in the validate() function in the update action with the data I got from the form and then providing a setter for the profile object. I did not have to make any changes to my .jsp
I don't know what you've written in your action, but from above I can infer that this is a slight misunderstanding about functionality issue. You are having fields with names - email, whenAvailable etc. but their value is fetched from profile object.
How can you expect to set it from something that doesn't exist ?
To make it more clear :
Values that go from JSP to action is email, but what comes back is profile.email, instead it
should have been just email, or you can simply skip the value attribute or you can change your
field-name to profile.email
Let me know if that helps.
[EDIT]
Reading your question again, the getters and setters for profile won't help, because what
is going into the action is just primitive fields (email etc.) So you should have getters/setters for these fields instead and then to re-populate the fields into the JSP
you can simply use for e.g. :
<s:textfield name="whenAvailable" value="%{whenAvailable}" />
OR
<s:textfield name="whenAvailable"/>

Recieving 'null' values from a jsp page into Struts 2 Action

I have a jsp page and struts 2 Action class . When I submit the form in the jsp , I am getting null values into the action.
The JSP code looks like :
<s:form id="user" name="user" action="initUserAdmin">
<s:textfield name="userName" cssClass="txtbox" size="30" />
<div class="btn"><a href='<s:url action="searchUserAdmin"/>'
title="Search" id="button" class="btn" ><span>Search</span></a></div>
</s:form>
The struts.xml has this part
<action name="*UserAdmin" method="{1}" class="com.mphasis.im.web.action.UserAction">
<result name="init" type="tiles">user</result>
<result name="search" type="tiles">user</result>
<result name="reset" type="tiles">user</result>
<result name="createNew" type="tiles">createNewUser</result>
</action>
And the Action class has this :
public class UserAction extends BaseAction
{
public String userName;
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String search()
{
searchProcessed = true;
System.out.println("******** inside search ******");
System.out.println("username = "+ userName);
return TilesConstants.SEARCH;
}
And the output comes as below when I type a string in the text box in jsp page.
******** inside search ******
username = null
What might be the problem ? Am I missing something ?
<a href='<s:url action="searchUserAdmin"/>'
title="Search" id="button" class="btn" >
It's just a href to the URL of action and with no parameter. Therefore, the 'userName' in the action is null.
<s:form id="user" name="user" action="initUserAdmin">
<s:textfield name="userName" cssClass="txtbox" size="30" />
<div class="btn"><a href='javascript:submitme()'
title="Search" id="button" class="btn" ><span>Search</span></a></div>
</s:form>
Javascript
function submitme(){
document.user.submit()
}
Also in the action mapping you provided the action name you are using there is UserAdmin whereas in the form action you are using initUserAdmin.They must be the same

Categories