1

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");
    }
skylake
  • 409
  • 2
  • 9
  • 24
  • 1
    The easiest way would be to generate each item with an associated checkbox and then postback the collection to delete all the checked items. Another alterative is to use ajax to post back the ID of the item to delete (and in the success callback remove the item from the DOM (its a bit unclear how you think a `MultiSelectList` would help) –  Oct 01 '16 at 10:26
  • @StephenMuecke I've to go for with first option as I've never used Ajax before. So are the steps : **1**. create `Checkbox` inside `foreach`-loop in `Review`-View. **2**. Collect all `Ids` once a "delete" button is pressed. **3**. Use e.g. `foreach` loop to delete each `Ids` in the collection? Never used `MultiSelect` before but I thought (by assuming the sound of it) it was the way to do it. – skylake Oct 01 '16 at 14:13

2 Answers2

3

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.

Community
  • 1
  • 1
1

I managed to solve this issue by:

Adding checkbox for each data-row inside foreach-loop:

<input type="checkbox" class="chkCheckBoxId" value=@item.Id name="chkReviewId"/>

Adding button <input type="submit" value="Delete" onclick="return confirm('Are you sure?')"/> somewhere in the view.

Adding this in controll:

        [HttpPost]
        public ActionResult MyReviews(FormCollection formCollection)
        {    
            string[] ids = formCollection["chkReviewId"].Split(new char[] {','});

            foreach (var id in ids)
            {
                var review = db.Reviews.Find(Guid.Parse(id));
                db.Reviews.Remove(review);
                db.SaveChanges();
            }    

            var description = db.Reviews.Where(m => m.Id == new Guid(Session["LoggedUserId"].ToString()));    
            return View(description.ToList());      
        }
skylake
  • 409
  • 2
  • 9
  • 24