skylake skylake - 2 months ago 10
ASP.NET (C#) Question

ASP.NET MVC - Delete multiplie row with MultiSelect

I wish to delete multiple data-row with MultiSelect and I've no idea where to start.

I've a details page where I have multiple Reviews, created by users. So far I can only delete one at time. How do I add MultiSelect and delete all selected at the same time?

Review model.

public System.Guid Id { get; set; }

public System.Guid CreatorId { get; set; }

[Required]
public string Title { get; set; }

[Required]
public string Description { get; set; }


View - that list all created reviews

@model IEnumerable<xxxx.Review>

<h2>Reviews</h2>

<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Description)
</th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td style="width: 20%; height: 20%">
<p>
@Html.DisplayFor(modelItem => item.Description)
</p>
</td>
<td>
@Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}

</table>


Controller

public ActionResult MyReviews(Guid? id) {
id = new Guid(Session["LoggedUserID"].ToString());

var review = db.Reviews.Where(m => m.CreatorId == id);

return View(review.ToList());

}


Delete action (where I use via View)

public ActionResult Delete(Guid? id) {
if (id == null) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Review review = db.Reviews.Find(id);
if (review == null) {
return HttpNotFound();
}
return View(review);
}

[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(Guid id) {
Review review = db.Reviews.Find(id);
db.Reviews.Remove(review);
db.SaveChanges();
return RedirectToAction("Index");
}

Answer

If the page you generating is specifically for deleting items from a collection, then generate a checkbox for each item and post back the whole collection.

Start by creating a view model to represent what you want to display in the view

public class ReviewVM
{
    public Guid ID { get; set; }
    public string Title { get; set; }
    ... // other properties you want to display in the view
    public bool IsSelected { get; set; }
}

and in the GET method

List<ReviewVM> model = db.Reviews.Where(m => m.CreatorId == id).Select(x => new ReviewVM
{
    ID = x.Id,
    Title = x.Title.
    ....
}).ToList();
return View(model);

And in the view

@model List<ReviewVM>
@Html.BeginForm())
{
    for (int i = 0; i < Model.Count; i++)
    {
        @Html.HiddenFor(m => m[i].ID)
        @Html.CheckBoxFor(m => m[i].IsSelected)
        @Html.DisplayFor(m => m[i].Title)
    }
    <input type="submit" .... />
}

and the POST method

[HttpPost]
public ActionResult MyReviews(List<ReviewVM> model)
{
    foreach (var review in Model)
    {
        if (review.IsSelected)
        {
            .... // delete the review based in the review.ID value

Note that db.SaveChanges(); only needs to be called once at the end. And since the user has already deleted all the reviews they want to, redirecting to another view seems more appropriate that returning back to the current view.

If on the other hand, the view also includes links for editing existing reviews, or displaying more details of each view, the using ajax to delete items would be more appropriate. For a typical implementation, refer this answer.

Comments