taking input from button in thymeleaf - html

I am displaying a form to user with some details and then user clicks approve and reject. In the backend, I want to take this in one property - userAction, which can be "approve" or "reject".
How can I add input to the buttons that user clicks? And then this input is part of the object requestDto.
<form th:action="#{/mission/store/{uuid}(uuid=${uuid})}" th:object="${requestDto}" method="post" class="mission_form">
<div class="wizard-header">
<h3 class="wizard-title">
Approve Mission
</h3>
<h5>Should you chose to accept this mission, press approve.</h5>
</div>
<div class="wizard-footer">
<!--<div class="pull-right">-->
<input type='button' class="btn btn-success" name='approve' value='Approve' />
<!--</div>-->
<div class="pull-left">
<input type='button' th:field="*{}" class='btn btn-danger' name='previous' value='Decline' />
</div>
<div class="clearfix"></div>
</div>
</form>

First define a proper DataTransferObject:
public class MyRequestDto {
private String userAction;
// don't forget getters and setters
}
Then add a object of that class to your model
// if you are return a M&V-object:
ModelAndView mv = new ModelAndView("viewName")
ModelAndView.addObject("requestDto", new MyRequestDto());
// if you define a Model-Object as input-parameter:
Model.addAttribute("requestDto", new MyRequestDto());
Define a form like this (I used button-elements). The point is not to use the th:field attribute:
<form th:action="...." method="POST" th:object="${requestDto}">
<button name="userAction" value="approve" >Approve</button>
<button name="userAction" value="reject" >Reject</button>
</form>
Recieve the DataTransferObject by adding this to your controllers input-paramters (the controller that handels the post request):
... #Valid RequestDto requestDto, BindingResult bindingResult, ....
Now you can access requestDto's userAction-Attribute. The value is approve if you click the first button and it is reject if you click the second button. First you can check if there are binding errors by checking bindingResults.hasErrors().

Related

EditForm in Blazor app have multiple submit buttons

I have a simple Blazor Editform where i have multiple buttons with different navigations & toast notifications. I have OnValidSubmit attached to Editform. Now the validations are working for all the buttons. I have added onclick() to trigger button functions but I want onclick to be triggered only if user has entered all the details. Hope I have explained well. Please let me know for additional input.
Current output for Forward or Next buttons are : if No values entered -> Correct validation(asked to fill in details) -> forward notification displayed.
Expected output :
if No values entered -> Correct validation(asked to fill in details).
if All values entered -> Correct validation -> forward notification displayed.
Here is some code:
<EditForm EditContext="#editContext" OnValidSubmit="HandleValidSubmit" #onreset="HandleReset">
<DataAnnotationsValidator />
<div class="form-row">
<div class="form-group col">
<label>Role</label><br />
<InputRadioGroup #bind-Value="model.Role" class="form-control">
#foreach (var option in rdOptions)
{
<InputRadio Value="option" /> #option
<text> </text>
}
</InputRadioGroup>
<ValidationMessage For="#(() => model.Role)" />
</div>
<div class="form-group col">
<label>Company Name</label>
<InputSelect id="txtCompanyName" class="form-control" #bind-Value="#model.CompanyName">
<option selected value="-1">-Select-</option>
<option value="CompanyName1">CompanyName1</option>
<option value="CompanyName2">CompanyName2</option>
</InputSelect>
<ValidationMessage For="#(() => model.CompanyName)" />
</div>
</div>
<div class="form-row">
<div class="text-left col-3">
<button type="submit" class="btn btn-primary btn-success">Save</button>
</div>
<div class="text-right col-3">
<button type="submit" class="btn btn-primary" #onclick="#Forward">Forward</button>
</div>
<div class="text-right col-3">
<button type="submit" class="btn btn-primary" #onclick="#Review">Next</button>
</div>
<div class="text-right col-3">
<button type="reset" class="btn btn-secondary">Clear</button>
</div>
</div>
</EditForm>
code section:
#code {
private Model model = new Model();
private EditContext editContext;
List<Model> models = new();
protected override void OnInitialized()
{
editContext = new EditContext(model);
}
private void HandleValidSubmit()
{
var modelJson = JsonSerializer.Serialize(model, new JsonSerializerOptions { WriteIndented = true });
JSRuntime.InvokeVoidAsync("alert", $"SUCCESS!! :-)\n\n{modelJson}");
toastService.ShowSuccess("saved successfully!");
}
private void Forward()
{
toastService.ShowInfo("Forwarded!!");
}
private void Review()
{
toastService.ShowInfo("Review!!");
}
private void HandleReset()
{
model = new Model();
editContext = new EditContext(model);
}
}
Change type="submit" to type="button"
Except maybe for the Save button.
You can do validation manually in your button event handlers and then not use the EditForm OnValidSubmit, and set the button types to button.
...
if (editContext.Validate())
go
else
alert
...
FYI - The relevant bit of code from EditForm looks like this:
private async Task HandleSubmitAsync()
{
Debug.Assert(_editContext != null);
if (OnSubmit.HasDelegate)
{
// When using OnSubmit, the developer takes control of the validation lifecycle
await OnSubmit.InvokeAsync(_editContext);
}
else
{
// Otherwise, the system implicitly runs validation on form submission
var isValid = _editContext.Validate(); // This will likely become ValidateAsync later
if (isValid && OnValidSubmit.HasDelegate)
{
await OnValidSubmit.InvokeAsync(_editContext);
}
if (!isValid && OnInvalidSubmit.HasDelegate)
{
await OnInvalidSubmit.InvokeAsync(_editContext);
}
}
}
In my opinion you will need to use JavaScript to check the inputs were filled or not and based on that you can disable or enable the submit button

ASP.NET MVC Redirect to same page after submit button is clicked

some friends and I have started a team project but we are stuck at this point. We made a function of the site to add comments under every post. The problem is that when submit is clicked it adds the comment but doesn't refresh the page which causes some problems. The author stays "anonymous" and when refresh button is clicked it shows an alert:
The page that you're looking for used information that you entered. Returning to that page might cause any action you took to be repeated. Do you wish to continue?
However, if we just type the URL again and click ENTER everything is good: the author shows up and the comment appears only once. So the only solution for us is to redirect to the same page. Here is the form:
<div style="text-align: left">
<div><i>Leave your comment</i>
</div>
<form method="post">
<fieldset>
<p>
<textarea rows="10" class="form-control" type="text" id="1" name="commentText" style="height: 100px"></textarea>
</p>
<p>
<input type="submit" name="buttonSubmit" onclick="redirect" value="Add comment" class="btn btn-default" style="" />
</p>
</fieldset>
</form>
</div>
This is how the comments are printed on the page:
<h3>Comments</h3>
<br>
<div>
#foreach (var comment in ViewBag.Comments) {
<section class="row">
<article class="post col-md-12">
<div class="about">
Posted on <i>#comment.Date</i>
#if (comment.AuthorId != null) { #: by <i>#comment.Author.FullName</i>
}else { #: by <i>anonymous</i>
}
</div>
<div class="body">#comment.Text</div>
</article>
</section>
}
</div>
Thanks in advance!
Use the #Ajax.BeginForm() helper.
In the AjaxOptions(), you'll want to set the Httpmethod to "Post", InsertionMode.InsertBefore (or After depending on where you want new comments), and UpdateTargetId = "your-comment-div".
You'll need to include jquery.unobtrusive-ajax.js so the Ajax helper works correctly. You can use the nuget package manager to pull it in. Be sure to add it to your jquery bundle.
Then, you need to create the post action in your controller to accept the comment params and return a partial view.
Doing thIs keeps the Ajax confined to a razor helper and controller method.
View:
#using (Ajax.BeginForm("AjaxAddComment",
"MyController",
/* route params */,
new AjaxOptions()
{
InsertionMode = InsertionMode.InsertBefore,
UpdateTargetId = "commentsDiv",
HttpMethod = "Post"
}, htmlAttributes: new { /* ... */ }))
{
<div class="form-horizontal">
#* comment form... *#
</div>
}
...
<div id="commentsDiv">
<div class="comment">...</div>
<div class="comment">...</div>
</div>
Controller:
[HttpPost]
//[ValidateAntiForgeryToken]
public async Task<PartialView> AjaxAddComment(string comment, /*...other params*/)
{
var newComment = ... // comment viewModel
// add comment to db
await db.SaveChangesAsync();
return PartialView("_CommentPartial", newComment);
}
_CommentPartial:
<div class="comment">
...
</div>

Pass parameter from Button to Java spring MVC controller

I've been looking for something that might help me to solve this without success. What I need is just to call a Spring Controller by pressing a Button element, and pass from it a RequestParam("statusId" in this specific case). Is there a way to do this without using JavaScript?
I have the next html:
<div class="tablero col-lg-4 col-md-4 col-sm-6">
<div class="inner-content">
<div class="rate">
<div class="number">
<span>${package}</span>
<span class="text">REFERRALS</span>
</div>
</div>
<div class="description">
<h3>
<i class="fa fa-shopping-bag"></i>
PACKAGE
</h3>
<label>Paquete</label>
<button class="btn-primary" onclick="location.href='listReferred.htm' id="package">GO TO LIST</button><!--The parameter should be send from this button-->
</div>
</div>
</div>
And the Spring MVC Controller:
#SuppressWarnings("unchecked")
#RequestMapping(value="/listReferred", method=RequestMethod.GET)
public String getListReferredPage(#RequestParam int statusId, Model model) {
RestTemplate restTemplate = new RestTemplate();
String url = URL_REFERREDTYPE_JSON+statusId;
List<SearchProspectTO> searchProspectToList = restTemplate.getForObject(url, List.class, statusId);
model.addAttribute("searchProspectToList", searchProspectToList);
return "portalInternoReferidos";
}
Surround at least the button element with a form, like this:
<form action="listReferred" method="get">
<button...
</form>
Add a name and value attribute to the button:
<button name="yourButton" value="[provide status id here]">GO TO LIST</button>
Alter #RequestParam int statusId to #RequestParam(value="yourButton") int statusId.
This will work except for older IE browsers - below Version 10 I think. These versions will return 'GO TO LIST' instead of the value.
As workaround you could use a hidden input, that has to be placed inside the form section as well.

Html.BeginForm inside of Html.BeginForm MVC3

I have a main view that renders two partial views. The main view encompasses both of the partial views within a form. Each of the partial views also contain forms. All 3 views share the same viewmodel. What I want to do is encapsulate the data from all views with the main view, and run specific Controller action results with the partial views.
I want to know if this is even possible. When debugging I see that my content always posts to the HTTPPost of the Main views form. I have submit buttons for each of the forms accordingly. Sorry for the code post, its coming out all split up.
Main View:
#using (Html.BeginForm("Main", "Registration", FormMethod.Post,
new { #class="mainform" }))
{
<form>
<fieldset>
<div id ="option1" class="conglomerate">
#Html.Partial("_GetBusiness")
</div>
<div id ="option2" class="dealership">
#Html.Partial("_GetLocation")
</div>
<button type="submit" value="Create" class="buttonBlue" id="">
<span>Create a new dealer</span>
</button>
</fieldset>
</form>
Partial 1
#using (Html.BeginForm("CreateBusiness", "Business", FormMethod.Post,
new { #class="buisinessform" }))
{
<form>
<div class="editor-field">
#Html.DropDownListFor(m =>m.BusinessId, new SelectList(Model.Businesses,
"BusinessId", "BusinessName"), "")
</div>
<label>Your company not listed? Register yours below:</label>
<div class="editor-label">
#Html.LabelFor(model => model.BusinessName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.BusinessName)
#Html.ValidationMessageFor(model => model.BusinessName)
</div>
<button type="Button" value="" class="buttonBlue"id="TestSubmit">
<span>Add Dealer</span>
</button>
<div class ="confirm">
<button type="submit" value="Create" class="buttonBlue" id="">
<span>Click here to confirm dealer addition</span>
</button>
</div>
</form>
}
As Dave mentions, It is not valid HTML to nest forms. It's not just HTML5, but any version of HTML.
It might work in some browsers, in certain circumstances, but it is never valid. And you can never depend on what will happen even if it does seem to work. Your best course of action is to use multiple non-nested forms on a page.
Can you explain why you think you need nested forms?
No, you cannot have nested forms. Sorry.
See HTML5 guidelines
"Flow content, but with no form element descendants"

HTML button calling an MVC Controller and Action method

I know this isn't right, but for the sake of illustration I'd like to do something like this:
<%= Html.Button("Action", "Controller") %>
My goal is to make an HTML button that will call my MVC controller's action method.
No need to use a form at all unless you want to post to the action. An input button (not submit) will do the trick.
<input type="button"
value="Go Somewhere Else"
onclick="location.href='<%: Url.Action("Action", "Controller") %>'" />
Razor syntax is here:
<input type="button" value="Create" onclick="location.href='#Url.Action("Create", "User")'" />
<button type="button" onclick="location.href='#Url.Action("MyAction", "MyController")'" />
type="button" prevents page from submitting, instead it performs your action.
Try this:
#Html.ActionLink("DisplayText", "Action", "Controller", route, attribute)
This should work for you.
You can use Url.Action to specify generate the url to a controller action, so you could use either of the following:
<form method="post" action="<%: Url.Action("About", "Home") %>">
<input type="submit" value="Click me to go to /Home/About" />
</form>
or:
<form action="#">
<input type="submit" onclick="parent.location='<%: Url.Action("About", "Home") %>';return false;" value="Click me to go to /Home/About" />
<input type="submit" onclick="parent.location='<%: Url.Action("Register", "Account") %>';return false;" value="Click me to go to /Account/Register" />
</form>
This is how you can submit your form to a specific controller and action method in Razor.
<input type="submit" value="Upload" onclick="location.href='#Url.Action("ActionName", "ControllerName")'" />
Building on couple of the above answers, you could do this:
<button onclick="location.href='#Url.Action("ActionName", "ControllerName")'" />
Of all the suggestions, nobdy used the razor syntax (this is with bootstrap styles as well). This will make a button that redirects to the Login view in the Account controller:
<form>
<button class="btn btn-primary" asp-action="Login" asp-
controller="Account">#Localizer["Login"]</button>
</form>
it's better use this example
<a href="#Url.Action("Register","Account", new {id=Item.id })"
class="btn btn-primary btn-lg">Register</a>
The HTML <button> element can only postback to the form containing it.
Therefore, you need to make a form that POSTs to the action, then put a <button> or <input type="submit" /> in the form.
So, I'm using Razor but this will work using either. I'm basically wrapping a button in a link.
<a href="Controller/ActionMethod">
<input type="button" value="Click Me" />
</a>
Despite onclick Method you can also use formaction as follows:
<button type="submit" id="button1" name="button1" formaction='#Url.Action("Action", "Controller")'>Save</button>
Use this example :
<button name="nameButton" id="idButton" title="your title" class="btn btn-secondary" onclick="location.href='#Url.Action( "Index","Controller" new { id = Item.id })';return false;">valueButton</button>
In case if you are getting an error as "unterminated string constant", use the following razor syntax :
<input type="button" onclick="#("location.href='"+ Url.Action("Index","Test")+ "'")" />
When you implement the action in the controller, use
return View("Index");
or
return RedirectToAction("Index");
where Index.cshtml (or the page that generates the action) page is already defined. Otherwise you are likely encountering "the view or its master was not found..." error.
Source: https://blogs.msdn.microsoft.com/aspnetue/2010/09/17/best-practices-for-asp-net-mvc/
If you are in home page ("/Home/Index") and you would like to call Index action of Admin controller, following would work for you.
<li>Admin</li>
it's better use this example.
Call action and controller using a ActionLink:
#Html.ActionLink("Submit", "Action", "Controller", route, new { #class = "btn btn-block"})
OK, you basically need to pass the action to the button and call it when click happens, it doesn't need to be inside a from, you can use HTML onclick on button to trigger it when the button get clicked...
<button id="my-button" onclick="location.href='#Url.Action("YourActionName", "YourControllerName")'">Submit</button>
You can always play around with htmlHelpers and build some stuff
public static IHtmlContent BtnWithAction(this IHtmlHelper htmlHelper, string id, string text, string css="", string action="", string controller="")
{
try
{
string str = $"<button id=\"{id}\" class=\"{css}\" type=\"button\" ###>{text}</button>";
if (!string.IsNullOrEmpty(action) && !string.IsNullOrEmpty(controller))
{
string url = ((TagBuilder)htmlHelper.ActionLink("dummy", action, controller)).Attributes["href"];
var click = !string.IsNullOrEmpty(url) ? $"onclick=\"location.href='{url}'\"" : string.Empty;
return new HtmlString(str.Replace("###", click));
}
return new HtmlString(str.Replace("###", string.Empty));
}
catch (Exception ex)
{
Log.Error(ex, ex.Message);
var fkup = "<script>alert(\"assumption is the mother of all failures\")</script>";
return new HtmlString(fkup);
}
}
And then on the view call it like this
#Html.BtnWithAction("btnCaretakerBack", "Back", "btn btn-primary float-right", "Index", "Caretakers")