<form jwcid="#Form" listener="listener:updateStaff">
<select jwcid="staffselect#Select" multiple="ognl:false" validators="validators:required" onchange="this.form.submit()" listener="listener:updateStaff">
<span jwcid="#For" source="ognl:hrStaff" value="ognl:currentHrStaff" index="ognl:currentHrStaffIndex">
<option class="text11" jwcid="#Option" selected="ognl:hrStaffSelection[currentHrStaffIndex]" label="ognl:currentHrStaff"/>
</span>
</select>
</form>
when onchange on selectbox, this form will be submitted and my pageValidate() will be called follow by upadteStaff() listener method. I wonder, when such submission is fired, can onchange='' pass a flag ('selectboxisfired' string) that i able to capture inside pagevalidate() 'selectboxisfired'? this will allow my logic inside pagevalidate to indicate is triggered by selectbox.
onchange="window.submitTrigger=this; this.form.submit();"
Then you can read the window.submitTrigger variable in your validation routines to work out which element triggered the submission, for example
/* somewhere in pagevalidate() routine */
/* note here that I am assuming the html id of the selectbox is "staffselect"
-> I'm not familiar with Tapestry so simply had to make the assumption
that this is the correct id - if not, change the string you're searching
for accordingly */
if (window.submitTrigger.id = "staffselect") {
//do something here
}
Of note, is that I think it's bad style to use onchange in this way, however not understanding Tapestry, I'm just giving you the most simple change to what's already there which I assume will work...
Related
For some reasons, I need to create a form with two submit buttons which are going to call different actions after submission.
I found the following example in Multiple Submit Buttons:
<s:form method="post" action="mySubmitAction">
<s:submit value="Submit"/>
<s:submit value="Clear" action="myClearAction"/>
</form>
As my project is using Struts 2.3.16.3, struts.mapper.action.prefix.enabled = true is needed.
However, is there any risk to enable it back in struts 2.3.16.3?
Will it share the same security problem in 2.3.15.2?
If yes, would you mind providing some alternatives to make the multiple submit buttons work on single form? if-else solution is not preferred.
The vulnerabilities discovered in versions Struts 2.0.0 - Struts 2.3.15.2 related to the OGNL injection attack. In fact the action: prefix opens a door for this kind of attacks.
Previously it's discovered in S2-016, the fixed version was 2.3.15.1. Lately S2-018 was introduced and they disabled the action: prefix. Recommended upgrade was 2.3.15.3.
This means that using action: prefix is discouraged and you can enable in on your own risk. In S2-019 the DMI was disabled by default too, so you can't use method: prefix because it works only if DMI is enabled.
These restrictions made side effect on multiple button usage where action or method attributes used to bind s:submit buttons to the action other than in the s:form action attribute. To use multiple buttons to execute its own methods of the action class you can pass a parameter that holds a method name. It could be a hidden field or submit field, etc.
When execute method is called this information should be already available and you can use Java to call the method by the name. Another approach is most popular to use javascript to modify the form's action attribute in the onclick event handler before the form is submitted.
<s:form name="myForm" method="post" action="mySubmitAction" >
<s:submit value="Submit"/>
<s:submit value="Clear" onclick="myClearAction()"/>
</form>
<script>
function myClearAction(){
document.forms["myForm"].action = "<s:url action='myClearAction' />";
}
</script>
There is a jsp file calling 2 different js files. I had a button(assume ButtonA) in jsp which when clicked it load a function(Function1) which fill jsp form with values. There is another button in page (ButtonB) which when clicked it load another function where this function(Function2) calculate a figure based on result that Function1 populated in form. So the action was user click ButtonA first, field values loaded, then click ButtonB to get calculated figure. Now I dont want two button clicks here. I tried to put two functions in one button as example below
<td colspan=3><center><INPUT TYPE="Button" VALUE="Query Package Info" TARGET="bottom" onClick="generateReport('MK07FormPackageInfo'); computeMarkFormat(document.MK07Form.markSurf.value);"></td>
but it only correctly run first one but the second one with gives empty values.
Please help.
Why dont you have the Javascript Function1 just call Function2.
If Function 1 and 2 are used by other JSP's:
Function 1 could be overloaded or modified to take in a parameter that says call function2 or not. Other JSP's can still keep calling Function1 as is. This particular button can call Function1 with parameter to trigger
Function 2 call.
function1 (callFunction2) {
function1();
function2();
}
function1 (){
}
function2 () {
}
Is there another reason you need this to be two seperate calls?
Thanks,
Paul
I tried to execute your scenario, it is working actually.
Here is my code
<script language="javascript">
function loadValues(){
document.getElementById('a').value = '2';
document.getElementById('b').value = '2';
}
function calc(){
document.getElementById('c').value = document.getElementById('a').value + document.getElementById('b').value;
}
</script>
HTML
<input type="text" id="a"/>
<input type="text" id="b"/>
<input type="text" id="c"/>
<input type="button" onClick="loadValues(); calc();" />
Only place where it fails is, if your first method executed successfully then only the second function will be executed. If you have any exception or problem in first function, the second one will not work, you may try to give 'b1' instead of 'b' After then nothing will be executed. Correct me if something wrong. Thanks..
Why don't you have a close tag for <center> ?
You may need to debug or add console.log to debug your second function if the result is not what you expected(Since you said it returned empty val, which means it actually got called, right?). Also, try to open console on browser's developer tool and see if any Exception/Error.
Btw, just like other guys says:
onClick="generateReport('MK07FormPackageInfo'); computeMarkFormat(document.MK07Form.markSurf.value);"
Isn't really pretty and is not a recommend way to do this...
You may want to add multiple event Listener to your using jQuery:
<script src="//code.jquery.com/jquery-1.11.2.min.js" />
<!-- watever here -->
<INPUT id="queryPackageInfoBtn" TYPE="Button" VALUE="Query Package Info" TARGET="bottom" />
<!-- watever here -->
<!--
Binding the even
-->
<script>
jQuery('#queryPackageInfoBtn').click(function(){generateReport('MK07FormPackageInfo'); });
jQuery('#queryPackageInfoBtn').click(function(){computeMarkFormat(document.MK07Form.markSurf.value);});
</script>
<!--
actually you can just do:
jQuery('#queryPackageInfoBtn').click(function(){
generateReport('MK07FormPackageInfo');
computeMarkFormat(document.MK07Form.markSurf.value);
});
but I want to make it obvious how you can add multiple event handler to the buttons without using inline onClick which will be messy.
-->
So I have a .jsp page which has a form on it, like this (naturally this is a massive simplification):
<form:form commandName="myCommand" method="post">
<form:select path="values" class="select-tall" multiple="multiple" id="mySelect">
<option>first</option>
<option>second</option>
<option>third</option>
</form:select>
<button type="submit" class="button">Save</button>
</form:form>
When the submit button is pressed, the form is submitted(somehow) and the path= attributes are used to bind the data inside the form elements to the properties of an instance of a plain old java object. I understand how this POJO is specified, and I understand how the POST request is routed to the correct controller, but I don't understand where or how the form values are mapped to the given POJO.
What I don't understand is:
How does the spring tag library modify the form such that this binding takes place?
How would one go about doing this in a manual or ad-hoc fashion(using a Javascript onSubmit() method, say)?
Essentially my question is: How does the spring-form.tld tag library work?
Any resources, or even a high-level explanation in your own words, would be extremely helpful.
I've implemented a work-around solution in the mean time (dynamically adding items to a hidden form element), but I feel like this is hack-y and the wrong solution.
I am using the following code to have different submit buttons for my form. The problem is that if I change the value of the Value attribute of each of the submit buttons I have to change the Java code too as if conditions are based on these values.
I am looking for an alternative solution to avoid this problem, so back-end and front-end would be independent.
JSP
<s:form name="myform" method="POST" action="myformActions">
.....
<input id="sub1Btn" type="submit" name="action" value="mysubmit1"/>
<input id="sub2Btn" type="submit" name="action" value="mysubmit2"/>
</s:form>
Java
{
....
private String action;
....
public void myformActions(){
if(action.equalsIgnoreCase("mysubmit1") //if I change the value need to change this as well
{
do whatever is required to fulfill the request of mysubmit1 ...
}
if(action.equalsIgnoreCase("mysubmit2") //if I change the value need to change this as well
{
do whatever is required to fulfill the request of mysubmit2 ...
}
}
}
I didn't go through all the comments, but from your question , I have an idea like you can use some javascript functions to set the action for the form depending on the criteria you want.So when the form is submitted , corresponding action will be invoked. You can even use a single action class and different methods like edit , add etc , which you can map in the struts.xml file. In this case mapping can be done like action="*user" method="{1}" so the method edit() in the action class will be invoked for action editUser and delete() for deleteUser ...
This solution may not be good in all cases and will not directly answer the question. My solution depends on the fundamental of your actions. If your button defines different actions on a object, you can do below.
This will not move buttons out of your action, but put them in the place they should be.
Consider a page with a form, the user can complete the form and submit it to result page. The result page will have export buttons to let user save the form in html,pdf,excel formats.
Your jsp
<s:submit button="true" key="form.btn.export.pdf" name="export" />
<s:submit button="true" key="form.btn.export.excel" name="export"/>
<s:submit button="true" key="form.btn.export.html" name="export" />
Then in your action the export setter will be if/else or switch statements (not a simple setter):
public void setExport(String exportBtn) {
if (exportBtn.toUpperCase().contains("PDF")) {
this.export = "PDF";
} else if (exportBtn.toUpperCase().contains("EXCEL")) {
this.export = "XLSX";
} else if (exportBtn.toUpperCase().contains("CVS")) {
this.export = "CVS";
} else if (exportBtn.toUpperCase().contains("HTML")) {
this.export = "HTML";
}
LOG.debug("Exporting to is " + this.export);
}
Then in your action doesn't need any if/else.
#Action(value = "export-action")
public String exportMethod(){
ExportHelper ex= new ExportHelper("report",export);//No if is required
inputStream = new ByteArrayInputStream( ExportHelper);
}
This easy solution make your actions more easy to maintenance.
Hint.
In this solution the backend and front end are not coupled! We are coupling the front end(jsp) to Controller(Struts Action). Which is not a bad approach.
use method or action attributes of the submit tag to redirect each to different method / action.
This is a continuation of an issue I was having yesterday so if it looks familiar, thats why :) It IS a different question tho!
So I have another dijit.form.Select initially created on the page like so;
<c:set var="clazzId" value="${verification.clazz.id}" />
<div id="clazzOptions">
<select id="clazz" name="clazz" style="width:22em" dojoType="dijit.form.Select" maxHeight="140">
<option value="-1" label=" " />
<c:forEach items="${requestScope.clazzes}" var="clazzItem">
<c:choose>
<c:when test="${clazzId eq clazzItem.id}">
<option value="${clazzItem.id}" selected = "true">${clazzItem.name}</option>
</c:when>
<c:otherwise>
<option value="${clazzItem.id}">${clazzItem.name}</option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
</div>
I then have some javascript that I'm trying to use to swap the contents of the div "clazzOptions" depending on the value chosen from a different drop down (not seen here). If its a certain value, replace the div with a text message, if its any other value, re-show the original dijit.form.Select;
<script type="text/javascript">
var classDropDown;
var classPhDMessage = "PhD's do not require a Class or Grade";
dojo.addOnLoad(function() {
classDropDown = dojo.byId('clazzOptions').innerHTML;
});
function checkForPHD() {
var awardOption = dijit.byId('qualification').attr('displayedValue');
if(awardOption == "PhD"){
dojo.byId('clazzOptions').innerHTML = classPhDMessage;
} else {
dojo.byId('clazzOptions').innerHTML = classDropDown;
}
}
</script>
As you can see I'm trying to capture the innerHTMLof the div as it is when the page loads and then depending on the value chosen in the other drop down (not seen) change between a predefine message and the captured div contents.
The issue is that after the original div contents have been replaced with the message and then the selection changes again away from "PhD" and the original div innerHTML is placed back into the div, the dijit.form.Select re-appears but is completely empty and in fact doesn't appear usable at all? If I remove the dijit.form.Select dojoType and just leave it as a normal select this whole operation works perfectly but I kinda need it to be a dijit.form.Select.
Why won't dijit.form.Select work in this case whereas a normal select does?
You shouldn't use innerHTML to add/remove dijits, especially if you're trying to re-use them.
A dijit is a combination of HTML and Javascript and can be thought of as 'more complex' than simply the contents of a specific node.
You have a number of options:
Disable your dijit.form.Select and add a small note under it (or set it's value) explaining why it's disabled (this is generally a better UI paradigm than removing controls). Depending on your UI this is what I'd try and do
Create a <span> as a sibling of your dijit.form.Select and use CSS to show/hide one of them at a time.
Obviously you'll still get the value of the dijit.form.Select when you submit your form, but because you do server side validation as well as client side validation (I hope :) this won't be a problem
Use the dojo.data API to create a datastore from your "${requestScope.clazzes}" iterator. Use this store when you (programatically) create the dijit.form.Select. Keep track of the current value of said Select somewhere. When you don't need it, call yourSelect.destroy() to properly destroy it, then when you need it again create a new one and set it's value to the saved value from before.
This seems unnecessarily expensive to me tho.