I have a scaffold list type table in my view. Above to the table, I have two checkboxes also. When I click on Edit link I need to pass the selected Id as well as the CheckBoxes' value also.
I can use ActionLink to pass the primary key value like
#Html.ActionLink("Action","Controller", new { id=#item.Id })
I can get the CheckBoxes Value by wrapping them into a Html.Beginform like,
#using(Html.BeginForm("Action","Controller",FormMethod="Post"){
<input type="checkbox" name="Check" value="1" />
<input type="checkbox" name="Check" value="2" />
-- table
<input type="Submit" value="Edit"/>
and in my controller, I can handle this like
[HttpPost]
Public ActionResult Edit(IEnumerable<string> check)
{ }
Here, I need to get both the Primary key value as well as Checkboxes' value, I tried in these two ways, and I could get any one of these only. Can anyone help me to get both the values? Thanks in advance.
You can include id in the action parameter. Like
[HttpPost]
Public ActionResult Edit(IEnumerable<string> check, int id)
{ }
Also, you will need to post the form using a submit button not the action link.
So, for sending the id, you will need to put it in a hidden field and it will automatically be sent on post.
Make sure you name the hidden field the same as the parameter name i.e. "id".
Edit
Do like this:
Take a hidden field in form: like this:
<input type="hidden" id="hf" value="TEst" name="hid" />
Then take a edit button in each row and make it call a javascript function. Like below:
<button type="button" onclick="clickfunc(#item.UniqueId)">Edit</button>
Next Come in Javascript and set hidden field and then do a form submit. Like below:
#section scripts{
<script type="text/javascript">
function clickfunc(id) {
$("#hf").val(id);
$('form').submit();
}
</script>
}
Now you get the values in your controller action. In my example it looks like:
public ActionResult EditTry(string hid)
{
return View();
}
You will get selected value in "check" string
To get the name type jquery on submit button click and store it in hidden field and access the hidden field from form collection
var getval = $("#Check option:selected").text();
$("#hdnText").val(getval);
This is controller Code:
[HttpPost]
Public ActionResult Edit(string check, FormCollection collection)
{
string strText = collection["hdnText"].ToString();
string strValue = check;
}
Related
In Asp.net MVC, Is it possible to have a form post to two different actions based on model value when clicked on the same button?
Ex. - I want to add a new customer or update an existing customer on click of the same button "Save". Can the form be posted to two different action methods based on the customer's id value.
if the customer id value = 0 , then post it to "Create" acction method , if the customer id value is already present (not equal to 0), then post the form to "Update" action method?
Is this possible in asp.net mvc?
No You cant call multiple action on submit with fairly way,
You need to add hiddenfield for id
<input type="hidden" name="id" value="#model.Id" />
When you submit the form the value will be retrieve from model
And check the hidden field value is 0 or not
If 0 than the entity needs to create else it is for update
public ActionResult Save(Customer customer){
if(customer.id > 0){
// Update Entity
}
else{
// Create Entity
}
}
Yes. It is possible. There are multiple ways to do it.
1) You can conditionally set the form action attribute value based on your view model property value.
<form method="post" action="#(Model.Id==0?Url.Action("Create","Home")
:Url.Action("Update","Home"))">
<input type="text" name="FirstName" />
<button type="submit">Save</button>
</form>
2) Another option is, you can add html5 formaction to your submit button and the value of that attribute could be the url to create or update action method based on your Id property value.
#using (Html.BeginForm("Create", "Home"))
{
<input type="text" name="FirstName" />
<button type="submit"
formaction="#(Model.Id==0?Url.Action("Create","Home")
:Url.Action("Update","Home"))">Save</button>
}
When you specify the formaction attribute on a submit button, it will overrides the parent form's action attribute value.
3) Another option is to hijack the form submit event in javascript, prevent the default behavior (stopping the form submit) and then update the form's action attribute value to /create or /update and trigger form submit using javascript. You can keep the Id property value in a hidden field inside the form and read the value of that and use that to determine what should be the url for the form's action attribute value.
Assuming you have a hidden element for the Id of type int property in your page
#model YourViewModel
#using (Html.BeginForm("Create", "Home",FormMethod.Post,new {id="yourFormId"}))
{
#Html.TextBoxFor(a=>a.FirstName)
<button type="submit">Save</button>
#Html.HiddenFor(a=>a.Id)
}
and the javascript to hijack the form submit and update the form's action attribute value would be like
$(function () {
$("#yourFormId").submit(function(e) {
e.preventDefault(); // stop the normal form submit
var id=parseInt($("#Id").val());
var url=$(this).attr("action");
if(id===0)
{
url='/Home/Update'; // Use the Url.Action to be safe to generate this
}
// read the data attribute and update the forms action and do a submit
$(this).closest("form").attr('action', url).submit();
});
});
4) Another option is always submitting the form to Update or Create action and inside that method, based on the the Id property value, execute the code for Update or Create as needed.
Yes. This for the View case:
#mode MyModel
#{
string action = Model.Id == 0 ? "Create" : "Edit"
}
#using (Html.BeginForm(action, "MyController"))
{
// if Edit need Id
if(action == "Edit")
{
#Html.HiddenFor(model=> model.Id)
}
#Html.TextBoxFor(model >= model.Name);
<input type="submit" value="Save">
}
I use an ajax form for removing items from a list. The first time I submit something, it works but the second times, the reference of the item submitted is not correct: it is the first reference that is still used.
Here is my ajax form:
<div>
<table>
#foreach (var item in Model.ProjectTechnology)
{
<tr>
<td>#Html.DisplayFor(m => item.TechnologyID) </td>
<td>#using (Ajax.BeginForm("RemoveLinkedTechnology", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "AddedTechnologies" })) {
#Html.Hidden("projectID", item.ProjectID)
#Html.Hidden("removedTechnologyID", item.TechnologyID)
<input type="submit" value="Suppr" />
}</td>
</tr>
}
</table>
</div>
Here is the action in my controller:
[HttpPost]
public ActionResult RemoveLinkedTechnology(int projectID, string removedTechnologyID)
{
// some code here...
}
Example:
Lets say I proceed the submitting like this: first submit: AA; second submit: BB.
For the first call: removedTechnologyID contains AA.
For the second call: removedTechnologyID still contains AA.
Any idea?
Thanks
I suspect that in your controller action you are returning a partial view which updates the contents of the <table> you have shown. Now since Html helpers such as Hidden or TextBox first look for values in ModelState before binding and then in the model what happens is that #Html.Hidden("removedTechnologyID", item.TechnologyID) sees that there is a removedTechnologyID="AA" in the model state and completely ignores your model value which is item.TechnologyID. So if you have looked at the DOM after the first AJAX request you would have seen that all hidden fields have the old values inside them.
To fix this you have 3 possibilities:
Clear the item in model state in your controller action:
[HttpPost]
public ActionResult RemoveLinkedTechnology(int projectID, string removedTechnologyID)
{
...
ModelState.Remove("removedTechnologyID");
ModelState.Remove("projectID");
return View(...);
}
Don't use helpers to generate the hidden fields:
<input type="hidden" name="projectID" value="#item.ProjectID" />
<input type="hidden" name="removedTechnologyID" value="#item.TechnologyID" />
Write a custom Html.Hidden helper which will first use the values in the model before looking at modelstate (out of scope for this answer)
I have two submit buttons which call the same action method. How can I tell which of these buttons was clicked in the formcollection of the action method (without setting the value property of the buttons)?
HTML code for buttons:
<input type="submit" name="button" />
<input type="submit" name="button" />
Action method as:
public ActionResult submitted(FormCollection form)
{
}
i know how to do if we have a value property, but I just want to try like this without value property. How can this be done?
thanks,
michaeld
The best thing to do, is intercept the click action to set a hidden form variable before the form is submitted, e.g.:
<script language="text/javascript">
$("form input[submit]").click(function() {
$("#buttonSelected").val("some unique value here");
});
</script>
Where you might have a hidden input:
<input type="hidden" id="buttonSelected" name="buttonSelected" />
That way, you can then check the specific "buttonSelected" form value to figure out which button was pressed.
I have some problems with ASP.NET MVC’s default model binder. The View contains HTML like this:
<input name="SubDTO[0].Id" value="1" type="checkbox">
<input name="SubDTO[1].Id" value="2" type="checkbox">
This is my simplified ‘model’:
public class SubDTO
{
public virtual string Id { get; set; }
}
public class DTO
{
public List<SubDTO> SubDTOs { get; set; }
public DTO()
{
SubDTOs = new List< SubDTO>();
}
}
All this works fine if the user selects at least the first checkbox (SubDTO[0].Id). The controller ‘receives’ a nicely initialised/bound DTO. However, if the first check box is not selected but only, for example, SubDTO[1].Id the object SubDTOs is null. Can someone please explain this ‘strange’ behaviour and how to overcome it? Thanks.
Best wishes,
Christian
PS:
The controller looks like this:
[Transaction]
[AcceptVerbs(HttpVerbs.Post)]
public RedirectToRouteResult Create(DTO DTO)
{
...
}
PPS:
My problem is that if I select checkbox SubDTO[0].Id, SubDTO[1].Id, SubDTO[2].Id SubDTOs is initialised. But if I just select checkbox SubDTO[1].Id, SubDTO[2].Id (NOT the first one!!!) SubDTOs remains null. I inspected the posted values (using firebug) and they are posted!!! This must be a bug in the default model binder or might be missing something.
This behavior is "by design" in html. If a check-box is checked its value is sent to the server, if it is not checked nothing is sent. That's why you get null in your action and you'll not find value in the posted form either. The way to workaround this is to add a hidden field with the same name and some value AFTER the check-box like this:
<input name="SubDTO[0].Id" value="true" type="checkbox">
<input name="SubDTO[0].Id" value="false" type="hidden">
<input name="SubDTO[1].Id" value="true" type="checkbox">
<input name="SubDTO[1].Id" value="false" type="hidden">
In this way if you check the check-box both values will be sent but the model binder will take only the first. If the check-box is not checked only the hidden field value will be sent and you\ll get it in the action instead of null.
I think this post on Scott Hanselman's blog will explain why. The relevant line is:
The index must be zero-based and unbroken. In the above example, because there was no people[2], we stop after Abraham Lincoln and don’t continue to Thomas Jefferson.
So, in your case because the first element is not returned (as explained by others as the default behaviour for checkboxes) the entire collection is not being initialized.
Change the markup as follows:
<input name="SubDTOs" value="<%= SubDTO[0].Id %>" type="checkbox">
<input name="SubDTOs" value="<%= SubDTO[1].Id %>" type="checkbox">
What's being returned by your original markup is an unrelated set of parameters, i.e. like calling RedirectToRouteResult Create(SubDTO[0].id, SubDTO[1].id, ..., SubDTO[n].id) which is clearly not what you want, you want an array returned into your DTO object so by giving all the checkboxes the same name the return value to your function will be an array of ids.
EDIT
Try this:
<input name="SubDTO[0].Id" value="<%= SubDTO[0].Id %>" type="checkbox">
<input name="SubDTO[0].Id" value="false" type="hidden">
<input name="SubDTO[1].Id" value="<%= SubDTO[1].Id %>" type="checkbox">
<input name="SubDTO[1].Id" value="false" type="hidden">
You have to return something to make sure there is an element for each index, I suspect that any gap will cause a problem so I'd suggest using a 'null' ID, for example 0 or -1 and then process that out later in your code. Another answer would be a custom model binder.
There is always the alternate option of adding a property to your class that takes an array of strings and creates the SubDTO array from that.
public List<string> SubDTOIds
{
get { return SubDTO.Select(s=>s.Id).ToList(); }
set
{
SubDTOs = new List< SubDTO>();
foreach (string id in value)
{
SubDTOs.Add(new SubDTO { Id = id });
}
}
}
or something like that
I have forms in my page a get and a post and i want add pager on my get form .. so i cant page through the results..
The problem that i am having is when i move to the second page it does not display anything..
I am using this library for paging ..
http://stephenwalther.com/Blog/archive/2008/09/18/asp-net-mvc-tip-44-create-a-pager-html-helper.aspx
this my actions code.
[AcceptVerbs("GET")]
public ActionResult SearchByAttraction()
{
return View();
}
[AcceptVerbs("POST")]
public ActionResult SearchByAttraction(int? id, FormCollection form)
{....
}
and this is what i am using on my get form to page through
<%= Html.Pager(ViewData.Model)%> //but when i do this it goes to
this method
[AcceptVerbs("GET")]
public ActionResult SearchByAttraction()
instead of going to this this
[AcceptVerbs("POST")] public ActionResult SearchByAttraction(int? id, FormCollection form)
which sort of makes sence .. but i cant really think of any other way of doing this
Any help would be very appreciated..
Thanx
I'd recommend against doing paging via HTTP POST. Page and search criteria are 2 perfect examples of what querystrings are meant for. Put those values in the query string & have that load up your action args.
Think about this. You can search google for "pies", navigate to page 14, copy the link and send it to your grandma. You can't do that when your paging/search only works with form posts.
Of course it will hit the GET version of SearchByAttraction because using this control you have a links as output.
So what you need to do:
1. make form on the page:
<form id="myForm" action="your/url" method="post">
<input type="hidden" name="page" />
<input type="hidden" name="your_param1" />
<input type="hidden" name="your_param2" />
<input type="hidden" name="your_paramN" />
</form>
2. make changes to pager - it should produce something like that:
<ul id="pager">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
3. add simple javascript function on the page:
<script language="javascript" type="text/javascript">
function submitMyForm(page) {
var form = document.forms["myForm"];
form.elements["page"].value = page;
form.submit();
return false;
}
</script>
And you will be able to hit the POST version, because clicking the link will submit your form on the server using POST request.
Thanx everyone i finally got it working .. just used one form .. and did something like this
Controller Actions
[AcceptVerbs("GET")]
public ActionResult SearchByAttraction()
{
return View();
}
public ActionResult Search(FormCollection form,int? id)
{
var info = _repository.ListByLocation(city, postal, pageIndex, 2);
return View("SearchByAttraction", info);
}
View
<% using (Html.BeginForm("Search", "Home", FormMethod.Get))
{ %>
so it calls the search method every time it does a post..
Try this:
[AcceptVerbs("GET")]
public ActionResult SearchByAttraction(int? id)
{
return View();
}
id should contain the page number you need to display.
If you lose form values using this approach then you'll need to change the Html.Pager method to render each action link as a form submit link.