How should I handle delete-situations in ASP.NET MVC - asp.net-mvc

How should I initiate a delete action from my view?
Creating a new form-tag for each entity just doesn't seem right :-)
<% foreach (var subscriber in group.Subscribers) { %>
<tr>
<td><%= subscriber.Email %></td>
<td><%= Html.ActionLink("[edit]", "edit", "subscriber", new {id=subscriber.SubscriberId}, null) %></td>
<td>
<form id="delete-subscriber-form" method="post" action="<%= Url.Action( "delete", "subscriber", new { #subscriberId = subscriber.SubscriberId }) %>">
<input type="submit" value="Delete" />
</form>
</td>
</tr>
<% } %>
How would you do it?

I normally use checkboxes on the side of the items. Then I can have action links (buttons, whatever) that apply an action to the selected items (such as delete).

you can use CSS and Javascript , add 'forDel' css class for all the elments you want to delete , if you are going to use jquery you can do it like this:
$(".element").each(function(){
$(this).data("id","the id of the element in db")
});
$(".element").toggle(function(){
$(this).addClass("forDel");
},function(){
$(this).removeClass("forDel");
});
and then on pressing the delete button:
var idsForDel;
$(".forDel").each(function(){
idsForDel = $(this).data("id"); + ";";
})
you can pass the idsForDel to the Controller ... and split it in the server side.

It depends on the situation, if you are doing CRUD operations you would normally go with one <form> tag per operation (delete,edit,new). If, however, you are displaying a list and you want to be able to 'multiple delete' items with one click then you will have to approach it from a different angle as you need to encapsulate all the required information into one form.
EDIT
Having had another look at your post above I notice you are providing a 'Delete Button' against each element in the list. For atomic actions like this (i.e. the user expects something to happen straight after they have clicked a button) I would definitely use one form per item.
What I wrote above still applies...

Related

Show the last object with some condition Rails

In Rails I want to put a link in the view to the last object with some condition, I know how to found the object, like this code
Equipment.where(name: "Bulldozer").last
But I donĀ“t know the right syntax to put in the href to go to the show of the last Equipment with name Bulldozer
<td> text </td>
Thanks in advance!!!!
you're almost there, you need to assign the object to an instance variable, it'll be available within the view. So, in the controller action:
#equipment = Equipment.where(name: "Bulldozer").last
then, in your view:
<td>
<%= link_to "text", equipment_path(#equipment) %>
</td>
link_to helper will generate the <a> tag for you

Html.BeginForm and POST method without button

I have found the answer to the question "how to execute POST method using hyperlink (actionlink) instead of button" in this topic.
I have used form's submit method in this way - looks straightforward:
#foreach (var item in Model)
{
using (Html.BeginForm("Delete", "Area", new { id = item.id }, FormMethod.Post))
{
<tr>
...
<td>
Delete
<input id="sbmt" type="submit" style="visibility: hidden" />
</td>
</tr>
}
}
Typical declaration without button declaration
Delete
will not work.
The questions are:
1/ Is it possible to do the same operation but without hiding the button? I mean I don't want to use (and hide) button in my code at all.
2/ What are pros and cons of the solution listed above?
It is possible without button.One of the way is Just simply giving id to your form like
using (Html.BeginForm("Delete", "Area", new { id = item.id }, FormMethod.Post,new {id="frm"}))
{
}
and then
and if not jquery then
What is the problem with button I don't know. I can not see any cons except dirty coding(bad way) to submit a form.

dynamic grid style form that lets you update multiple rows in a single post in asp.net mvc

I'm starting out with MVC but not sure it's the best option.
I need to create a form that is based upon a collection. Eg it might look like this:
product Price
Item 1 [textbox]
Item 2 [textbox]
[submit button]
where "item" is pulled from the database and textbox allows users to update the price.
essentially this is a type of datagrid but i don't want webforms style update each row one at a time i need to update the entire set of text boxes in one post.
Ideally I don't want a javascript based solution as it has to work without javascript.
Is this possible in MVC or should I stick to webforms (where I could do this in a repeater by iterating through he repeater items on postback)
I wrote blog entry about it: ASP.NET MVC - Binding model to a list
To summarize:
For every row you have to generate inputs with proper prefixes. Sample:
<% foreach (var item in Model)
{ %>
<tr>
<td>
<%= Html.Hidden("contacts[" + i + "].ID", item.ID)%>
<%= Html.TextBox("contacts[" + i + "].Name", item.Name)%>
</td>
<td>
<%= Html.TextBox("contacts[" + i + "].Surname",item.Surname)%>
</td>
<td>
<%= Html.TextBox("contacts[" + i + "].Phone",item.Phone)%>
</td>
</tr>
<%
i++;
} %>
And then in controller:
[HttpPost]
public ActionResult List(IEnumerable<Contact> contacts)
{
//Here we have populated contact list, contacs parameter is filled with data from form. You save it here to your repository.
return RedirectToAction("List");
}

ASP.NET Collection Model Binding Nested Form Problem

I have a partial view that is bound to an object Cart. Cart has a collection of CartLines. My view is below:
<tbody>
<% foreach (var line in Model.Lines) { %>
<tr>
<td align="center"><%=Html.CatalogImage(line.Product.DefaultImage, 80) %></td>
<td align="left">
<%=Html.ActionLink(line.Product.Name, "Product", "Catalog",
new { productId = line.Product.Id }, new { title = "View " + line.Product.Name })%>
</td>
<td align="right"><%= line.Product.Price.ToString("c")%></td>
<td align="center">
<%=Html.Hidden("lines[" + i + "].key", line.Product.Id) %>
<%=Html.TextBox("lines[" + i + "].value", line.Quantity, new { #class = "quantity" })%>
</td>
<td align="right"><%= (line.LineTotal).ToString("c")%></td>
<td>
<%using (Ajax.BeginForm("RemoveFromCart", "Cart",
new {ProductId = line.Product.Id, returnUrl = ViewData["returnUrl"]},
new AjaxOptions { UpdateTargetId="cart", LoadingElementId="loading" }))
{%>
<input type="image" src="<%=AppHelper.ImageUrl("delete.gif")%>" value="Remove item" />
<%} %>
</td>
</tr>
<% i++; } %>
</tbody>
There are two things to note. The first is that I am using a form per line for removing items.
The second is that I had attempted to allow users to change the quantity of line items and then click an update button to pass all the changes to the controller action:
// POST: /Cart/Update
[HttpPost]
public ActionResult Update(Cart cart, IDictionary<int,int> lines, string returnUrl)
{
foreach (var line in lines) {
Product p = _catalogService.GetProduct(line.Key);
cart.UpdateItem(p, line.Value);
}
if (Request.IsAjaxRequest())
return PartialView("Cart", cart);
else
return RedirectToAction("Index", new { returnUrl });
}
Note that I am using a dictionary since I am only concerned about the product and quantity. I don't really like the fact that I am having to retrieve the product again before calling cart.UpdateItem but I couldn't figure out how to pass the Product from the model to my action instead of the id.
The main problem however, is rather stupidly I wrapped the entire cart in a form so that I could post back the values and then spent a good hour wondering why things were not working correctly in IE - doh! nested forms
So I am stuck on how to get round this. I want the ability to remove items individually but allow a user to change item quantities and then pass all changes at once to the controller. I can't use links for my remove action as I would need to use javascript to force a post and everything must work without javascript enabled.
[Update]
Would a better solution be to allow updates on my custom model binder? This way I could make changes inside my view and post the cart object back to the controller - although I'm not sure whether this is possible with child collections (Cart.CartItems).
I've had a look on sites like Amazon and it would appear they wrap the entire cart in a form and both global update buttons and indidivual remove item buttons post back to the same action when javascript is disabled.
Any help would be appreciated.
Thanks,
Ben
There is only one way here and thats the ugly way. Have 1 form around everything.
Then in the action you have to check which button was pressed (you get the name of the button in the request).
It gets even more ugly with differences in firefox and ie. If you have a button pressed ie or firefox (Dont remember which one) not only sends the name of the pressed button, but also the location where the button was pressed.
You have more options if your solution can rely on JS enabled browsers. But thats another story.

Checkbox HTML Helper

I've been working on an ASP.net MVC project that uses checkbox HTML Helpers in one of the views. The problem I'm trying to resolve is maintaining the checkbox state on a page refresh or when a user hits to he back button on their browser. I'm trying to use the HTML helper as a start, but I lack a complete understanding of how it works. I'm stuck on the third parameter that asks for HTML attributes. A snippet from a form that I have is as follows:
<tr>
<td><label for="Name">Name</label></td>
<td><%= Html.Encode(entity.CONTACT_NAME)%></td>
<td><input type="checkbox" name="Name" value="<%= Html.Encode(entity.CONTACT_NAME)%>"/> </td>
<td><%= Html.CheckBox("Name", false, new {#name = Html.Encode(entity.CONTACT_NAME)}) %></td>
</tr>
To avoid confusion, I have an object called entity that I declare before my form, that has several string values, one of which is CONTACT_NAME. I have a separate, standard, html checkbox right above the HTML Helper for testing purposes. When my form POSTs, I get the value if I select the standard checkbox, if I select the helper I get only true.
What I want to know is, how I can get
the value like I do when I select the
standard checkbox?
And how can I
maintain the checkbox state on page
refresh??
Any help is appreciated, thanks.
UPDATE:
#NickLarsen - Looked at the HTML code that was generated, the value is "false"
Made changes as per anthonyv's and JonoW's suggestions, my View is now as follows:
<tr>
<td><label for="Name">Name</label></td>
<td><%= Html.Encode(entity.CONTACT_NAME)%></td>
<td><%= Html.CheckBox("Name", false, new {#value = Html.Encode(entity.CONTACT_NAME)}) %></td>
</tr>
But the generated HTMl still shows the value as a boolean "false" instead of the actual CONTACT_NAME.
As per NickLarsen's suggestion, here is the code in my controller that checks the values.
public ActionResult ProcessRequest(Request request, FormCollection form)
{
var aChangeRequest = new ChangeRequest();
TryUpdateModel(aChangeRequest, new string[] { "Name" },form.ToValueProvider());
//Way more follows
}
should "#name" be "#value"? It looks like you are trying to set the name twice...
I'm pretty sure you want to have the following:
<%= Html.CheckBox("Name", false, new {#value = Html.Encode(entity.CONTACT_NAME)}) %>
If you have 2 inputs with the same name, they will be posted as a list of values (which MVC is going to try convert to a boolean value). So it's probably going to distort your test by having 2 elements with the same name, would suggest changing one of the names.

Resources