14

Consider the following markup:

<h2>Edit SAS Program</h2>
@using (Html.BeginForm("Edit", "SasProgram", FormMethod.Post))
{
    <label for="Name">Name</label>
    @Html.TextBoxFor(model => model.Name)

    using (Html.BeginForm("Delete", "SasProgram", FormMethod.Post))
    {
        <input type="submit" class="button" value="Delete" />
    }
    <input type="submit" class="button" value="Save Changes" />
}

I'd like to have the Delete button on the same view as the Edit. However, it's not letting me have nested forms. What is the appropriate way to handle this situation?

I tried leveraging this answer, How to handle nested forms in ASP.NET MVC, but it's a broken link now.

6
  • 3
    Though you can have several <form> elements in one HTML page, you cannot nest them. Commented Jul 15, 2013 at 19:56
  • You don't need a nested form for this. Just use an ActionLink for the Delete action. It deosn't have to be a Post request. Commented Jul 15, 2013 at 19:58
  • Also, there's no such a thing as nested form. You can have a single form with multiple submit buttons. Commented Jul 15, 2013 at 19:58
  • 4
    Duplicate: stackoverflow.com/a/443047/439427 Commented Jul 15, 2013 at 20:15
  • 5
    @ataravati - very very very bad idea to have destructive activity on a get. Commented Jul 15, 2013 at 20:49

8 Answers 8

17

I would use different values for button name in the same form:

@using (Html.BeginForm("Edit", "SasProgram", FormMethod.Post))
{
    <label for="Name">Name</label>
    @Html.TextBoxFor(model => model.Name)

    <button name="action" value="delete">Delete</button>
    <button name="action" value="save">Save Changes</button>
}

and then switch in controller:

[HttpPost]
public ActionResult Edit( SomeModel model, string action )
{
    switch( action ) {
        case "delete":
            // delete action
            break;
        case "save":
            // save action
            break;
    }
}

The code is written from memory but it works in production. Note that buttons are of default type - submit.

Sign up to request clarification or add additional context in comments.

2 Comments

Perfect, this is just what I needed for the scenario where I have both a "Save" button and a "Save and Close" button.
Yes, I think this is the most elegant.
15

The best and easiest way would be to use two forms but don't nest them:

<h2>Edit SAS Program</h2>
@using (Html.BeginForm("Edit", "SasProgram", FormMethod.Post))
{
    <label for="Name">Name</label>
    @Html.TextBoxFor(model => model.Name)

    <input type="submit" class="button" value="Save Changes" />
}

@using (Html.BeginForm("Delete", "SasProgram", FormMethod.Post))
{
    <input type="submit" class="button" value="Delete" />
}

This way you have:

  • Two separate forms
  • No GET requests
  • The delete button below the edit button, which makes more sense when you're on a view that allows you to edit something.

Comments

2

First of all. Every modification request should be use the post method.
I make some R&D and build the basics of a multi submit button handler in a wiki A clean solution to use multiple submit button in ASP.NET MVC.
I think it could solve your problem.

Comments

1

First, you cannot nest <form> element. The specification doesn't allow it. Since you are using the MVC pattern I have two options that came to my mind:

  1. You can retain the save button as the submit button of the form, and make the delete button a HTML link. Then the delete button will target to a different route, it could be something like: GET /program/delete/{id}.

  2. You can have two buttons inside the same form, then with JavaScript after clicking one of the buttons you will change the action attribute of the form.

Update

There is a third option, that is more clean: using two submit buttons with same name attribute and different values.

Your form will have two buttons:

public ActionResult MyAction(string submitButton) {
    switch (submitButton) {
        case "save":
            // ...
        case "delete":
            // ...
    }
}

For more details check this answer: https://stackoverflow.com/a/443047/439427

Comments

1

You can also use html 5 feature to target a form from an input button. Below I have created both a delete and save form and have the submit buttons outside of the forms but targeting them via the form attribute.

I think most browsers support this except IE.

No javascript required.

@using (Html.BeginForm("Edit", "SasProgram", FormMethod.Post, new { id = "editForm" }))
{
    <label for="Name">Name</label>
    @Html.TextBoxFor(model => model.Name)
}

@using (Html.BeginForm("Delete", "SasProgram", FormMethod.Post, new { id = "deleteForm" }))
{
    <input type="submit" class="button" value="Delete" />
}

<input type="submit" class="button" value="Save" form="editForm"/>
<input type="submit" class="button" value="Delete" form="deleteForm" />

This allows for a nice button layout without any fancy javascript or css styling.

Comments

0

The OLD way to do this but still applicable is to have one form tag and change the action with multiple submit buttons.

<input class="btn btn-default" type="submit" value="Save" />
<input class="btn btn-default" type="submit" value="Delete" onclick="this.form.action='/SasProgram/delete/@Model.Id';" />

Comments

0

Hi dear friend you can check out this solution: https://www.dotnettricks.com/learn/mvc/handling-multiple-submit-buttons-on-the-same-form-mvc-razor

enter image description here

@using (Html.BeginForm("MultipleCommand", "Home", FormMethod.Post, new { id = "submitForm" }))
{
 <fieldset>
 <legend>Registration Form</legend>
 <ol>
 <li>
 @Html.LabelFor(m => m.Name)
 @Html.TextBoxFor(m => m.Name, new { maxlength = 50 })
 @Html.ValidationMessageFor(m => m.Name)
 </li>
 <li>
 @Html.LabelFor(m => m.Address)
 @Html.TextAreaFor(m => m.Address, new { maxlength = 200 })
 @Html.ValidationMessageFor(m => m.Address)
 </li>
 <li>
 @Html.LabelFor(m => m.MobileNo)
 @Html.TextBoxFor(m => m.MobileNo, new { maxlength = 10 })
 @Html.ValidationMessageFor(m => m.MobileNo)
 </li>
 </ol>
 <button type="submit" id="btnSave" name="Command" value="Save">Save</button>
 <button type="submit" id="btnSubmit" name="Command" value="Submit">Submit</button> 
 <button type="submit" id="btnCancel" name="Command" value="Cancel" onclick="$('#submitForm').submit()">Cancel (Server Side)</button>
 </fieldset>
} 

1 Comment

Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. Would you kindly edit your answer to include additional details for the benefit of the community?
-1

Edit : Here's how to do it with ajax using an HttpPost.

//
// POST: /Divisions/Delete
[HttpPost, ActionName("Delete"), Authorize]
public ActionResult DeleteConfirmed(int id)
{
    Division division = _db.Divisions.Single(x => x.DivisionId == id);

    string errorMessage;
    if (DbRelationEnforcer.CanDelete(_db, division, out errorMessage))
    {
        division.SetDeleted(User.Identity.Name);
        _db.SaveChanges();
        return Json(new JsonResponseCreatePartial { Success = true }, JsonRequestBehavior.AllowGet);
    }

    return Json(new JsonResponseCreatePartial { Success = false, Message = errorMessage }, JsonRequestBehavior.AllowGet);
}

Then, on the view, you must use the <input type="submit">Save changes</input> to save your changes (within the form), and a simple link/button to delete, like this:

<h2>Edit SAS Program</h2>
@using (Html.BeginForm("Edit", "SasProgram", FormMethod.Post))
{
    <label for="Name">Name</label>
    @Html.TextBoxFor(model => model.Name)

    <input id='delete-btn' type="button" class="button" value="Delete" />
    <input type="submit" class="button" value="Save Changes" />
}

Finally, you have to use JS to post to your action from the view, when the user clicks on Delete.

<script type='text/javascript'>
    $(function() {
        $("input#delete-btn").click(function(){
            $.post('@Url.Action("Delete")', '@Model.Id', function(data) {
                if(data.Success) {
                    ' ... handle the success case
                } else {
                    ' ... error management
                }
            });
        });
    });
</script>

This will work, but in order to have a better UX, it would be preferable to have the Delete button from the Index/list view, and using a JQuery UI dialog to confirm before doing the ajax post. This will skip having to load the Edit page if/when you want to delete multiple items one after the other.

4 Comments

Doing deletes via hackable and indexable get requests? That's just very bad advice!
1. The controller has an [Authorize] attribute, 2. As I mentionned in my edit, this "works" but it's much better to use a confirmation dialog and do an ajax post once the user has confirmed. 3. The form url is set from javascript so it shouldn't be indexable.
@KristofClaes not to mention that several browsers have pre-fetch; view the parent? boom: all the children are deleted
@MarcGravell Changed the answer slightly to use an ajax post. IMO this is better than passing an action identifier in the form and routing everything within the same MVC Action on the controller side of things... Using the same MVC Action to save changes or to delete is anti-cohesive.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.