In my web page, I need to populate button according to parameter value called ButtonType.
let's say that If ButtonType == "Edit" then I need to hide every buttons but butUpdate.
I want to know how to show/hide html buttons via MVC Action method.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SupplierDetail(int SupplierID, string ButtonType)
{
var Supplier = supplierListRepository.Supplier_SelectByID(SupplierID);
return View(Supplier);
}
I am using Asp.net Mvc Razor form.
#using (Html.BeginForm("SupplierDetail_SubmitClick", "Supplier", FormMethod.Post, new { id = "frmSupplierDetail" }))
{
#Html.ValidationSummary(true)
<table cellpadding="0" cellspacing="0" border="0" style="width:450px; height:auto">
.....
<tr>
<td>#Html.LabelFor(model => model.Phone)</td>
<td>#Html.EditorFor(model => model.Phone)
#Html.ValidationMessageFor(model => model.Phone)</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>
<input type="submit" id="butSave" name="butSave" value="Save" style="width:100px; height:auto" />
<input type="submit" id="butUpdate" name="butUpdate" value="Update" style="width:100px; height:auto" />
<input type="submit" id="butDelete" name="butDelete" value="Delete" style="width:100px; height:auto" />
<input type="submit" id="butReset" name="butReset" value="Reset" style="width:100px; height:auto" />
</td>
</tr>
</table>
</div>
<div id="content">
#Html.ActionLink("Back to List", "Index")
</div>
}
Every Suggestions will be appreciated.
It is not a controller action responsibility to show/hide buttons. A controller action doesn't/shouldn't even know what a button means. That's a concept that exists on the view. A controller action on the other hand is supposed to communicate with the model and prepare a view model that it passes to the view for displaying. So you could define a view model that will contain properties defining the visibility of the buttons and based on the value of the ButtonType parameter set those properties accordingly. Then the controller action will pas this view model to the view instead of the supplier object that you are currently passing. Obviously the view model will also have a property to hold this supplier. Now all that's left for the view is based on the values of the view model properties decide how to display the buttons.
in your controller add the buttontype to viewdata:
ViewData["ButtonType"] = ButtonType
Then, in the view itself, you can add if/else statements, or any other logic that suits all of ur cases, to decide what to render:
#if (ViewData["ButtonType"].ToString() == "Edit")
{
<input type="submit" id="butUpdate" name="butUpdate" value="Update"
style="width:100px; height:auto" />
}
Of course, this is but a demo of what can be done, Yuo should adapt the code to ur buisness logics
Related
I have an application that shows a checklist with a dynamic list of tasks. For now all the tasks have 2 radio buttons: one for Done and one for Not Done. I will be adding new task types (textboxes etc.) later.
The main view calls an editor template that creates each task. The checklist model keeps the tasks in a property "Tasks" of type List<Task>. This is fine for display, but has trouble on form submit.
I want to have each task save independently, so I have placed a <form> element around the controls in the editor template.
Controller
public class CheckController : Controller
{
[HttpGet]
public ActionResult Index()
{
var checklist = new Checklist();
GetData(checklist);
return View(checklist);
}
[HttpPost]
public ActionResult Index(Task model)
{
var task = (Task)model;
return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}
}
Models
public class Checklist
{
public List<Task> Tasks { get; set; }
public Checklist()
{
Tasks = new List<Task>();
}
}
public class Task
{
public int TaskId { get; set; }
public string TaskName { get; set; }
public bool IsDone { get; set; }
}
Views
#model Checkpoint.Models.Checklist
<table>
#Html.EditorFor(x => x.Tasks);
</table>
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#{
using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId)
#Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
}
</td>
</tr>
Rendered HTML
<tr>
<td>First thing</td>
<td>
<form action="/Checklist" method="post">
<input id="Tasks_0__TaskId" name="Tasks[0].TaskId" type="hidden" value="1" />
<input checked="checked"id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="False" />
<span>Incomplete</span>
<input id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="True"
<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
</form>
</td>
</tr>
<tr>
<td>Second thing</td>
<td>
<form action="/Checklist" method="post">
<input id="Tasks_1__TaskId" name="Tasks[1].TaskId" type="hidden" value="2" />
<input checked="checked" id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="False" />
<span>Incomplete</span>
<input id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="True" />
<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
</form>
</td>
</tr>
This does submit the request, but the data looks like this:
Tasks[1].TaskId: 1
Tasks[1].IsDone: True
When it reaches the controller action (which accepts type Task), the property values are null.
How can I get my task data correctly in the controller action?
Or am I going about this in the totally wrong way?
Bonus: what would be the best approach for adding the new task types?
Since you're not trying to post the collection all in one submission you'll need to lose the index on the model name.
Tasks[0].TaskId
Adjust your views. The variable name "task" needs to match the action parameter because the HtmlHelpers will generate name attributes based off this string.
#model Checkpoint.Models.Checklist
<table>
#foreach(Task task in Model.Tasks)
{
#Html.EditorFor(m => task)
}
</table>
The rendered html looks something like
<input id="task_TaskId" name="task.TaskId" type="hidden" value="1">
...
The action needs a "task" parameter to match to bind its values
[HttpPost]
public ActionResult Index(Task task)
{
return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}
If we use a partial view instead of an editor template we can somewhat relax the name dependency on "task".
#model Checkpoint.Models.Checklist
<table>
#foreach(Task t in Model.Tasks)
{
#Html.PartialView("_TaskForm", t)
}
</table>
And your editor template content will work just the same.
_TaskForm
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#{
using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId)
#Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
}
</td>
</tr>
And the rendered html
<input id="TaskId" name="TaskId" type="hidden" value="1">
...
The gotcha with all of the above is the html id attributes will not be unique. So if that's critical you'll need to manually iterate the collection to build each form manually so you can exactly specify the id values. That is, you'd lose the small modular editor templates.
Letting the framework auto-generated "unique" ids... we override the name attribute (mind the capitalization for "Name") we have:
#model Checkpoint.Models.Checklist
<table>
#for(int i = 0; i < Model.Tasks.Count; i++)
{
<tr>
<td>#Model.Tasks[i].TaskName</td>
<td data-ftid="#Model.Tasks[i].TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => Model.Tasks[i].TaskId, new { Name="TaskId" })
#Html.RadioButtonFor(x => Model.Tasks[i].IsDone, false, new { Name="IsDone" })<span>Incomplete</span>
#Html.RadioButtonFor(x => Model.Tasks[i].IsDone, true, new { Name="IsDone" })<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
</td>
</tr>
}
</table>
I was able to make this work with the Editor Template by dropping the helpers and creating the controls manually.
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
<input name="TaskId" type="hidden" value="#Model.TaskId" />
<input name="IsDone" type="radio" value="True" #Html.Raw(Model.IsDone ? "checked=checked" : null) />
<span>Complete</span>
<input name="IsDone" type="radio" value="False" #Html.Raw(!Model.IsDone ? "checked=checked" : null) />
<span>Incomplete</span>
<button role="button" type="submit" name="taskAction" value="#Model.TaskId">Submit</button>
}
</td>
</tr>
I wasn't overly happy with this and opted instead for #Jasen's partial view solution.
I was able to obtain unique element IDs by overriding the 'id' attribute in the helper.
I used the TaskId since it's unique, but could otherwise have passed in a loop index from the main view.
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId, new { id = "Task_" + Model.TaskId + "_hidIsDone" })
#Html.RadioButtonFor(x => x.IsDone, false, new { id = "Task_"+ Model.TaskId + "_radIsDoneF" })<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true, new { id = "Task_" + Model.TaskId + "_radIsDoneT" })<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
</td>
</tr>
I have a view in my asp.net (Core) app, which displays a shopping cart. Typical shopping cart stuff - it lists the items in the cart. Each row has an editable field to allow changing the quantity, and an editable checkbox to allow the user to mark the row as "Delete".
I want two buttons at the bottom of the view, one for "Update Cart" (this will delete rows, and update quantities, etc). The other is for "Create Order", which will do the same as "Update Cart", but also create the order.
I have been able to create one button, and have it call the appropriate method in the controller, but I'm having trouble adding a second button, and have it call a different method.
At the moment, my view looks like this:
#model CustomerPortal.Models.StoreViewModels.CartViewModel
#{
ViewData["Title"] = "View";
}
<h2>Shopping Cart</h2>
<form asp-action="UpdateCart">
<table class="table">
<thead>
<tr>
<th>Item</th>
<th>Size</th>
<th>Colour</th>
<th>Quantity</th>
<th>Unit Price Inc. GST</th>
<th>Line Amount Inc. GST</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.CartLines.Count; i++)
{
<tr>
#Html.HiddenFor(modelItem => modelItem.CartLines[i].CartLine.ID)
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].CartLine.Item.Description)</td>
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].CartLine.ItemSize.Name)</td>
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].CartLine.ItemColour.Name)</td>
<td>#Html.EditorFor(modelItem => modelItem.CartLines[i].CartLine.Quantity)</td>
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].UnitPriceInecTax)</td>
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].LineAmountIncTax)</td>
<td>#Html.EditorFor(modelItem => modelItem.CartLines[i].Delete)</td>
</tr>
}
</tbody>
</table>
<div class="form-group">
<input type="submit" value="Update Cart" class="btn btn-default"/>
<input type="submit" value="Create Order" class="btn btn-default"/>
</div>
</form>
And the methods in the ShoppingCartController look like this:
[HttpPost, ActionName("UpdateCart")]
[Authorize]
public async Task<IActionResult> UpdateCart(CartViewModel cart)
{
// Need to do some stuff here
return RedirectToAction("Index");
}
[HttpPost, ActionName("CreateOrder")]
[Authorize]
public async Task<IActionResult> CreateOrder(CartViewModel cart)
{
// Need to do some stuff here
return RedirectToAction("Index");
}
I've tried using "#using(Html.BeginForm" without success. The current format (as above) is the only way that it "kind of" works (both buttons call one function).
So - how can I do this? How can I make both buttons call different methods? Or maybe call the same method with a different second parameter (indicating if I create order or not).
Thanks.
You can use html5 formaction attribute to submit to two different urls from the same form.
<form asp-action="UpdateCart">
<!-- your form elements -->
<div class="form-group">
<input type="submit" value="Update Cart" formaction="#Url.Action("UpdateCart")"/>
<input type="submit" value="Create Order" formaction="#Url.Action("CreateOrder")"/>
</div>
</form>
When you specify the formaction attribute on a submit button, it will overrides the parent form's action attribute value.
Another option is hijack the button click event in javascript and set the parent forms action attribute value to the one you want and trigger a submit event, as explained in this post
This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 6 years ago.
I am developing MVC 4 application in which I need to pass the updated value from the view to controller.
#foreach (var item in Model)
{
<tr>
<td>#item.ProductId</td>
<td>#item.Product.ProductName</td>
<td>#item.Product.UnitPrice</td>
<td>
#Html.TextBox("QuantityBox", item.Quantity)
</td>
</tr>
}
//Update Button
#using (Html.BeginForm("UpdateCart", "Cart", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input type="submit" id="submit" name="Update" value="Update" />
}
The values could be entered different for different rows.
I need to pass these values from quantity textbox to controller.
Try using a for loop
#using (Html.BeginForm("UpdateCart", "Cart", FormMethod.Post))
{
#for(int idx = 0;idx < Model.Length;idx++)
{
<tr>
<td>#Model[idx].ProductId</td>
<td>#Model[idx].Product.ProductName</td>
<td>#Model[idx].Product.UnitPrice</td>
<td>
#Html.TextBoxFor(_ => Model[idx].Quantity)
</td>
</tr>
}
#Html.AntiForgeryToken()
<input type="submit" id="submit" name="Update" value="Update" />
}
When you post the above back to the controller, the MVC model binder will see the textboxes for Model[0].Quantity, Model[1].Quantity, etc and try to bind them to the incoming model. Using a foreach loop will result in none of that data being passed back to the controller.
I do not know what #model you are using on your view, but I'm assuming the MVC model binder will be able to deal with this.
Write like this..
#using (Html.BeginForm("UpdateCart", "Cart", FormMethod.Post))
{
#Html.AntiForgeryToken()
#foreach (var item in Model)
{
<tr>
<td>#item.ProductId</td>
<td>#item.Product.ProductName</td>
<td>#item.Product.UnitPrice</td>
<td>`enter code here`
#Html.TextBox("QuantityBox", item.Quantity)
</td>
</tr>
}
<input type="submit" id="submit" name="Update" value="Update" />
}
I would move the entire Foreach Codeblock
#foreach (var item in Model)
{
<tr>
<td>#item.ProductId</td>
<td>#item.Product.ProductName</td>
<td>#item.Product.UnitPrice</td>
<td>
#Html.TextBox("QuantityBox", item.Quantity)
</td>
</tr>
}
Into the Using statement : Otherwise your model back in the controller would not include the updated values that the user submmitted in the view.
In other words : the values that you want in your controller has to be in your Using statement where your submit button is located.
Your code should be like below
#using (Html.BeginForm("UpdateCart", "Cart", FormMethod.Post))
{
#for(i=0;i< Model.item.count ;i++)
{
<tr>
<td>#item.ProductId</td>
<td>#item.Product.ProductName</td>
<td>#item.Product.UnitPrice</td>
<td>
#Html.TextBoxFor(m=>m.item[i].Quantity)
</td>
</tr>
}
//Update Button
#Html.AntiForgeryToken()
<input type="submit" id="submit" name="Update" value="Update" />
}
Then you will get those values in controller through posting
Need to use form tag properly let me know if it works
If you want to know about url rewriting in MVC-4 please visit http://grandhah.blogspot.in/
View:
#using (#Html.BeginForm("Show", "test", FormMethod.Post))
{
<fieldset>
<table >
<tr>
<td>
#Html.LabelFor(model=> model.Show)
</td>
<td>
#Html.TextBox("txtvalue", null)
</td>
</tr>
</table>
<input type="button" value="Show" onclick = "#("location.href='"+ #Url.Action("Show", "test")+"'" )" />
<input type="button" value="Go" onclick ="#("location.href='"+ #Url.Action("Go", "test")+"'" )"/>
</fieldset>
}
and two action methods in the controller,
public ActionResult Show(string txtvalue)
{
...
}
public ActionResult Go(string txtvalue)
{
...
}
based on which button been click , it should go to the corresponding action method and pass the value of the textbox.
Can anyone suggest me the way to do it. I wrapping my head around couldn't figure out.
Try this,
<input type="button" value="Show" onclick = "location.href='#Url.Action("Show", "Foo")'"/>
<input type="button" value="Go" onclick = "location.href='#Url.Action("Go", "Foo")'"/>
UPDATE:
As type="button" does not submit the values in the form, its not directly possible to do what you have asked, the better idea is to Identify the Button that has been clicked in the controller method as show in this link
Try this
<input type="button" value="Show" onclick="location.href='<%: Url.Action("Show", "Controller") %>'" />
<input type="button" value="Go" onclick="location.href='<%: Url.Action("Go", "Controller") %>'" />
Try something like:
<input type="button" value="Show" onclick="location.href='<%:Url.Action("Show", "ControllerName")%>'"/>
<input type="button" value="Go" onclick="location.href='<%:Url.Action("Go", "ControllerName")%>'"/>
If you are posting more form data you can use Ajax, see Making a Simple Ajax call to controller in asp.net mvc
I am trying to lookup an employee by their ID using a jQuery modal. My Modal has an input text box for the employee ID and a Search button. Once the search button is clicked I have the value looked up in a db and if no result exists I am looking for an error message to display on that same modal.
My controller looks like this:
[AcceptVerbs(HttpVerbs.Post)]
[ActionName("CreateEmpLookup")]
public ActionResult CreateEmpLookupPost(string empIDSearch)
{
List<spGetEmployeeDataByEIDResult> res = new List<spGetEmployeeDataByEIDResult>(_service.GetUserFromDB(empIDSearch));
if (res.Count > 0)
{
ViewData["Status"] = true;
return RedirectToAction("Create", new { empID = empIDSearch });
}
else
{
ViewData["Status"] = "false";
return Content("False");
}
}
I'm just not sure how to relay the information back to the pop up modal that there is no result. I'm thinking I have to replace this line return Content("False"); with the message that will go back to the jQuery pop up modal.
In my pop up modal I have the following line that will display any error messages:
<input type="hidden" id="Status" value="<%= (ViewData["Status"] == null) ? "true" : ViewData["Status"].ToString() %>" />
Here is a snippet of my jQuery code:
$('#login_form').modal();
And the div that jQuery targets:
<div id="login_form" style='display: none'>
<div id="status" align="left">
<center>
<h1>
<img src="../../Content/modal_images/Search48.png" alt="Key" id="modal_img" />
<label id="modal_title">
Employee Search</label>
</h1>
<br class="modal_br" />
<div id="login_response">
<input type="hidden" id="Status" value="<%= (ViewData["Status"] == null) ? "true" : ViewData["Status"].ToString() %>" />
</div>
</center>
<% using (Html.BeginForm("CreateEmpLookup", "", FormMethod.Post))
{ %>
<form id="login" action="javascript:alert('success!');">
<%--<input type="hidden" name="action" value="user_login" />
<input type="hidden" name="module" value="login" />--%>
<table class="modal_table">
<tr>
<td>
<label id="modal_label">
Employee ID:</label>
</td>
<td>
<%= Html.TextBox("empIDSearch", "", new { #maxlength = "6" })%>
</td>
</tr>
<tr>
<td>
</td>
<td>
<input value="Search" name="Search" id="submit" type="submit" />
<div id="ajax_loading">
<img src="../../Content/modal_images/spinner.gif" alt="Processing" /> Processing...
</div>
</td>
</tr>
</table>
</form>
<% } %>
</div>
</div>
Any advice on how to make this easier or fix this problem would really help.
Thank you.
#GB, I can think of a couple of ways to do this. However, given you are using a Modal dialog and you want to display it in there that kinda limits your options.
If you're doing a post using a submit button, as it looks like you are, then on return back to the page you need to display the popup again and then fill in the details.
One nifty way of doing that might be to use PartialViews (PV). If you get back a result then you could render on PV and if not then you render another one. Not great but it would work.
The best way, IMHO, is to use jQuery to do a partial postback. Then you could do your search and on return from the partial post back you could render either a list or the error.
So;
Allow user to enter the search
criteria
Do a jQuery/AJAX call to do your
search
If you fail, then return a PV that
contains your error and render that
to a parent DIV.
If you succeed, and it's not clear
what you're doing at this point,
show another PV with the user
details / List.
An AJAX postback can return a PV. The return value in this case is html that can simply be inserted into a Div or something.
This would be ideal as you don't get the annoying screen flicker effect.
If you want code samples, post a comment and I'll provide some.