I have this code in my JSP:
<%#taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
..
..
<html:form action="update" >
..
..
<html:submit value="delete" />
<html:submit value="edit" />
<html:sumit value="update" />
</html:form>
And this in the struts-config.xml file:
<action path="/delete" name="currentTimeForm" input="/viewall.jsp" type="com.action.DeleteProduct">
<forward name="success" path="/viewall.jsp" />
<forward name="failure" path="/viewall.jsp" />
</action>
Like the delete action, I have edit and update. It works fine, if I give the name specifically like <html:form action="delete"> but, how to make it dynamically work for update and edit?
You have one form and multiple submit buttons. The problems is that a form can only submit to one action, no matter how many submit buttons you have inside the form.
Three solutions come to mind right now:
1. Have just one action where you submit everything. Once inside the Action class check what button was used to submit the form and perform the appropriate treatment based on that.
<html:form action="modify">
..
..
<html:submit value="delete"/>
<html:submit value="edit" />
<html:sumit value="update" >
</html:form>
In the ModifyAction.execute(...) method have something like:
if (request.getParameter("delete") != null || request.getParameter("delete.x") != null) {
//... delete stuff
} else if (request.getParameter("edit") != null || request.getParameter("edit.x") != null) {
//...edit stuff
} else if (request.getParameter("update") != null || request.getParameter("update.x") != null) {
//... update stuff
}
2. Have the action attribute of the HTML form changed using JavaScript before submitting the form. You first change the submit buttons to plain ones with click handlers attached:
<html:form action="whatever">
..
..
<html:button value="delete" onclick="submitTheForm('delete.do')" />
<html:button value="edit" onclick="submitTheForm('edit.do')" />
<html:button value="update" onclick="submitTheForm('update.do')" />
</html:form>
With the handler:
function submitTheForm(theNewAction) {
var theForm = ... // get your form here, normally: document.forms[0]
theForm.action = theNewAction;
theForm.submit();
}
3. Use a DispatchAction (one Action class similar to point 1) but without the need to test for what button was clicked since that's treated by the DispatchAction.
You just provide three execute methods properly named delete, edit and update. Here is an example that explains how you might do it.
In conclusion: For number 1, I don't really like those ugly tests.... for number 2, I don't really like the fact that you have to play with the action form using JavaScript, so I would personally go for number 3.
There is another simpler way to do this as follows:
In the ActionForm currentTimeForm, add a String property (example: buttonClicked).
In the jsp, in each of the html:submit tags add this property.
Now in the action execute method simply check the value of this property, ie.
if(currentTimeForm.getButtonClicked().equals("delete"){
}
else if((currentTimeForm.getButtonClicked().equals("edit"))
and so on...
Related
Let's say that i have a navbar with a search bar, and it appears on every single page, so when the user click on the search button, it could happend 2 things:
Refresh the page if the input is empty
Redirect to a SearchResult.cshtml and show the results...
So the controller and action who handle the HTTP POST Request are Search - SearchResult respectively. I want to get the URL from the caller because the action method will need it to decide what page should redirect it.
PD: I'm using ASP.NET CORE MVC 3.1
In the Layout page, you could add a hidden field to store the current page URL, then, when click the Search button, in the SearchResult action, you could get the previous URL from the hidden field. Code as below:
_Layout.cshtml page,
<div class="search">
#{
//get current url
Uri currenturl = new Uri(String.Format("{0}://{1}{2}{3}", Context.Request.Scheme, Context.Request.Host, Context.Request.Path, Context.Request.QueryString));
}
<form asp-controller="Search" asp-action="SearchResult">
<input class="text-body" type="text" value="" name="search" />
<input name="returnurl" type="hidden" value="#currenturl" />
<input type="submit" class="btn btn-info" value="Search" />
</form>
</div>
Code in the SearchResult action:
public IActionResult SearchResult()
{
//get the returned url
var returnurl = HttpContext.Request.Form["returnurl"].ToString();
//do something
return Redirect(returnurl);
}
The screenshot as below:
What you probably want to do is submit the current path/query along with your query.
You could accomplish that by having your search form be something like this.
<form asp-controller="Search" method="get">
<input name="q" value="#Context.Request.Query["q"]" />
<input name="r" type="hidden" value="#Context.Request.GetEncodedPathAndQuery()" placeholder="Search the thing" />
</form>
Notice im using a get method here. This is to keep the search state in the browser but you can manage that however you need too. Im also using GetEncodedPathAndQuery which will need to be installed, but again the important part is to maintain the path/query(and more if this will be cross domain).
My controller will then look something like this.
[Route("/search")]
public class SearchController : Controller
{
[HttpGet]
public IActionResult Index(
[Bind(Prefix = "q")] string query,
[Bind(Prefix = "r")] string referrer)
{
IActionResult result = null;
if (string.IsNullOrWhiteSpace(query))
{
result = this.Redirect(referrer);
}
else
{
result = this.View(); // do search and return view.
}
return result ?? this.Redirect("/");
}
}
This can obviously be adjusted in anyway you need. The main thing is accepting the two values from the request and handling them properly. You might also want to validate that the referrer is an actual url since the redirect action will throw if its not.
[See updates at bottom]
I have a Razor page with a form on it. I want to have two buttons on that form, that perform a slightly different action - both using the same posted form data.
I tried using the asp-page-handler helper on the second button, but it doesn't seem to add anything to the HTML (I would expect it to add a formaction attribute to the <button> element, but it doesn't add anything at all).
Here's an example page:
#page "{id?}"
#model IndexModel
#tagHelperPrefix x:
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<p>Current value is #Model.Foo</p>
<x:form method="post">
<input type="text" name="foo" />
<button type="submit">Default</button>
<button type="submit" x:asp-page-handler="Alternative">Alternative</button>
</x:form>
... and here's the corresponding page model:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace MyWebApplication.Pages
{
public class IndexModel : PageModel
{
[BindProperty]
public string Foo { get; set; }
public void OnGet(int? id)
{
}
public void OnPostAsync(string foo)
{
Foo = foo;
}
public void OnPostAlternativeAsync(string foo)
{
Foo = foo.ToUpper();
}
}
}
This is rendered as:
...where the generated HTML for the form is:
<form method="post">
<input type="text" name="foo" />
<button type="submit">Default</button>
<button type="submit" x:asp-page-handler="Alternative">Alternative</button>
</form>
The fact that the x:asp-page-handler attribute is still in the generated HTML makes me think that the Razor engine hasn't recognized it. I've tried taking off the x: prefix, but that didn't help.
What am I doing wrong?
UPDATE
OK, I tried removing the tag prefix and removing the #tagHelperPrefix line, and that made a difference. A formaction is added to the second <button> element as expected.
However:
that's really annoying - the #tagHelperPrefix is not something I want to lose, and
now both buttons are triggering the "Alternative" action, even though only one of them has the formaction!
Here's the new generated HTML:
<form method="post">
<input type="text" name="foo" />
<button type="submit">Default</button>
<button type="submit" formaction="/?handler=Alternative">Alternative</button>
</form>
SECOND UPDATE
OK, so If I put asp-page-handler="" on the "default" button, then each button goes to the correct handler, which is fine.
The last question that remains, then, is: how can I make this work with the tag helper prefix?
[Answering my own question in case this helps others.]
It turns out that:
The tag-helper-prefix only applies to elements, not attributes, so it should be asp-page-handler="..." rather than x:asp-page-handler="..." even if the tag-helper-prefix is x:.
Those asp- attributes are only recognized within a tag that is tag-helper-enabled - which is all elements when no tag-helper-prefix is specified, or only elements with the tag-helper-prefix where one is specified. In my case, I had to change <button ...> to <x:button ...>.
If you specify asp-page-handler for one button, you need to specify it on all the buttons, even if you specify it as "" to get the default action.
I would like to have two buttons in my view (called Create), one that submits the form and takes the user back to home page if they are finished and one that submits the form but reloads the rating page to be able to add additional ratings.
Here is the problem that I have right now-
Currently I have one button that has an action result in my controller:
public ActionResult Create(Rating rating)
{
if (ModelState.IsValid)
{
db.Ratings.Add(rating);
db.SaveChanges();
return RedirectToAction("Index");
}
**Additional code that is irrelevant here
}
The problem that I am faced with is that this ActionResult has a Redirect in it to the homepage so when I submit my other button and use this same ActionResult class it is being redirected to the homepage. I am using the javascript onclick event in the view to redirect to the Ratings page when the button is clicked and the form is submitted but if I use this same Action Result class for both buttons it redirects the button I want to keep me on the page to the index page.
How do I create two Action Result classes from the same view, one for each submit button?
Well, how do you determine what the user wants to do?
Both buttons submit the form, so they may as well still use the same action. But you need to differentiate somehow. You can do that with the buttons.
Let's say you have these two buttons:
<input type="submit" name="redirect" value="true" />
<input type="submit" name="redirect" value="false" />
Then you can bind that in your action method:
public ActionResult Create(Rating rating, bool redirect)
{
// other logic
if (redirect)
return RedirectToAction("Index");
else
return View(rating);
}
If you are ever going to have more than two possible options then you might use a string instead of a boolean. Something like:
<input type="submit" name="action" value="redirect" />
<input type="submit" name="action" value="reload" />
And then in the controller:
public ActionResult Create(Rating rating, string action)
{
// other logic
if (action.Equals("redirect"))
return RedirectToAction("Index");
else if (action.Equals("reload"))
return View(rating);
else if //...
//... and so on
}
The point is that the client-side code needs to tell the server-side code what to do somehow. Including that on the form submission itself makes the form submission self-describing and allows the server-side code to handle it easily.
Example of how it use
Html, inside form:
<button type="submit" name="TaskSubmitAction" value="ActionReject" class="btn btn-danger pull-left">Reject</button>
<button type="submit" name="TaskSubmitAction" value="ActionSubmit" class="btn btn-success">Accept</button>
Controller:
public ActionResult TaskSubmit(int? id, string TaskSubmitAction)
{
switch (TaskSubmitAction)
{
case "ActionSubmit":
break;
case "ActionReject":
break;
default: throw new Exception();
}
In your html give both buttons the same 'name' attribute but assign two different values.
<button name="submitBtn" value="valueX"> Button 1 </button>
<button name="submitBtn" value="valueY"> Button 2 </button>
In your server side code get the value of the input button and based on this value carry out different actions
String choice = request.getParamter("submitBtn");
if(choice.equals("valueX"))
//do something
else if(choice.equals("valueY"))
//do something else
I have been working on disabling the content and ignoring data that is populated in a selection field that forms part of multifield that comes with CQ5 dialog
below is the code that is not working
<medicineType
jcr:primaryType="cq:Widget"
fieldLabel="medicine Type : "
name="./medicinetype"
blankText="medicine Type"
type="radio"
xtype="selection">
<options jcr:primaryType="cq:WidgetCollection">
<inactive
jcr:primaryType="nt:unstructured"
text="medicine Lead"
value="medicinelead" />
<active
jcr:primaryType="nt:unstructured"
text="doctor Lead"
value="doctorlead" />
</options>
<listeners jcr:primaryType="nt:unstructured"
selectionchanged="function(box,value){
if(value == 'medicinelead'){
var ans = box.findParentByType('dialog').form.findField('./medicinedoctorset');
ans.setDisabled(true);
ans.getEl().up('.x-form-item').setDisplayed(false);
}
"/>
</medicineType>
<medicinedoctorset
fieldLabel="doctor cards"
jcr:primaryType="cq:Widget"
name="./medicinedoctorset"
xtype="multifield">
<fieldConfig
jcr:primaryType="cq:Widget"
type="select"
options="/apps/doctor-api/components/medicineview/doctorcards.json"
optionsRoot="doctorcards"
optionsTextField="label"
optionsValueField="id"
xtype="selection" />
</medicinedoctorset>
Not sure what exactly you are trying to do in the code, but it seems to me that you are trying to disable a particular field medicinedoctorset. Try adding id to the field you want to disable, get and disable the field as CQ.Ext.getCmp("idOfTheFieldToBeDisabled").setDisabled(true); Hope this helps.
I want to be able to reset all text fields to their default values when a button is clicked.
What I've done so far is query for all text fields and bind a function I wrote called 'textChanged' to the change event as follows:
require(["dojo/on","dojo/query"], function(on,query){
query(".Text").on("change",textChanged);
});
The function is defined as follows:
function textChanged(newVal)
{
...
}
I found I can reset the value in the body of the function by doing the assignment:
newVal.target.value = newVal.target.defaultValue;
If this function is triggered by a change event.
What I want to do is if a button is clicked, then I want to execute the newVal.target.value = newVal.target.defaultValue and am having trouble getting the context correct.
I've tried preserving the 'this' variable when it is called as well as preserving the 'newVal' parameter. If I try setting the value outside of the the context, then the update doesn't preserve. I've tried setting the 'this' value to some other value (nt = this) and the newValue to another variable (nv = newValue) and then I want to execute:
nv.target.value = nv.target.defaultValue;
and although it clears the field on the form, when the form is submitted, its actual value is still the manually modified value. I noticed that the 'this' is different from when I textChanged is called from the change event verses when I call it directly in my button clicked context.
I tried calling it using 'hitch' to set the context of this to its value that it had from the change event, but that doesn't seem to set the correct context:
require(["dojo/on", "dojo/_base/lang"], function(on, lang) {
lang.hitch(nt, textChanged(nv));
});
To be precise - inside textChanged I display the value of 'this' using console.log(this);
When textChanged is invoked when the text changes from the UI, 'this' is:
Yet when it is invoked from clicking my button that calls it via the
lang.hitch(nt, textChanged(nv));
'this' is:
Window fauxRedirect.lsw?applicationInstanceId=guid%3A1eae6af09bf6f543%3A-6644aeb4%3A13a8a4c429e%3A-7ffe&zWorkflowState=2&zTaskId=p1&applicationId=2&zComponentName=CoachNG&zComponentId=3028.b1094dc3-da2b-461a-8d56-f6444891c174&zDbg=2#%20%20
I've confirmed that 'nt' is indeed the same '
So, I'm trying to execute the textChanged function such that 'this' is set to that value.
Or, if there is a better way to reset a field to its default from another control - that would work as well.
Thanks in advance.
I'm not sure of the full context of what you are trying to do, so don't know if this answers your question?
You can reset all of the widgets within a form to their default value as long as they are wrapped in a dijit/form/Form widget. If all the widgets are wrapped correctly it should be a simple matter of calling reset() on the form.
NB: This will not work for native elements (ie. standard <input> or <textarea> fields, they must be dijit/form/TextBox ...etc).
eg:
<form data-dojo-type="dijit/form/Form" data-dojo-id="theForm">
<label for="field1">Field 1:</label>
<input
type="text" id="field1" name="field1"
data-dojo-type="dijit/form/TextBox" value="default1"
/><br />
<label for="field2">Field 1:</label>
<input
type="text" id="field2" name="field2"
data-dojo-type="dijit/form/TextBox" value="default2"
/>
<br /><br />
<button
type="button"
data-dojo-type="dijit/form/Button"
onclick="theForm.reset();"
>Reset</button>
</form>
Clicking the reset button here should reset the fields to: field1="default1" and feield2="default2".
The form is calling each widget's reset() method. If you create your own widgets you need to ensure that their reset() method works correctly (as well as the _getValueAttr() method for setting their value).