iantukic iantukic - 2 months ago 23
C# Question

Submitting two HTML forms with one submit button in Razor

First of all sorry for my bad English. I am new to ASP.NET MVC and currently I am doing small "Rent-a-car" project on it.

I want to make a form where administrator of the page can add Cars on page with details like

name
,
year of production
and
picture
. Following some tutorials I made a form to create a car with name and year of production and I made separately a form where administrator can upload a picture of the car.

Now I have two HTML forms with two submit buttons, one for creating a car and second for uploading an image of the car. I want to combine those two forms into one where Administrator could type name of the car, year of production, select a picture which he want's to upload and then submitting all that with one button.

I have no idea how to do that so please review my code below and tell me what changes do I have to make, I will appreciate any help

This is my Car model:

public class Car
{
[Key]
public int CarID { get; set; }
public string Model { get; set; }
public int YearOfProduction { get; set; }
public string Price { get; set; }
public string Photo { get; set; }
public string AlternateText { get; set; }
[NotMapped]
public HttpPostedFileBase File { get; set; } //for image upload
}


This is my Create (car) Action Method in the "Cars" controller:

[Authorize(Roles = "Administrator")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CarID,Model,YearOfProduction")] Car car)
{
if (ModelState.IsValid)
{
db.Cars.Add(car);
db.SaveChanges();
return RedirectToAction("Index");
}

return View(car);
}


This is my Upload (image of the car) Action Method in the "Cars" controller:

[HttpPost]
public ActionResult Upload(Car picture)
{
if (picture.File.ContentLength > 0)
{
var fileName = Path.GetFileName(picture.File.FileName);
var path = Path.Combine(Server.MapPath("~/Images/Cars"), fileName);
picture.File.SaveAs(path);
}

return RedirectToAction("Index");
}


This is my HTML form for creating a car:

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
<h4>Car</h4>
<hr/>
@Html.ValidationSummary(true, "", new {@class = "text-danger"})
<div class="form-group">
@Html.LabelFor(model => model.Model, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(model => model.Model, new {htmlAttributes = new {@class = "form-control"}})
@Html.ValidationMessageFor(model => model.Model, "", new {@class = "text-danger"})
</div>
</div>

<div class="form-group">
@Html.LabelFor(model => model.YearOfProduction, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(model => model.YearOfProduction, new {htmlAttributes = new {@class = "form-control"}})
@Html.ValidationMessageFor(model => model.YearOfProduction, "", new {@class = "text-danger"})
</div>
</div>

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default"/>
</div>
</div>
</div>
}


This is my HTML form for uploading an image of the car:

@using (Html.BeginForm("Upload", "Cars", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr>
<td>File:</td>
<td><input type="file" name="File" id="File"/></td>
</tr>

<tr>
<td>&nbsp;</td>
<td><input type="submit" name="submit" value="Upload"/></td>
</tr>
</table>
}

Answer

You can use the command name in your <input> tag as shown below:

@Html.BeginForm()
{
  @Html.AntiForgeryToken()

  <!-- Your Razor code for the input form goes here  -->

  <!-- Now your Upload button -->
  <table>
    <tr>
        <td>File:</td>
        <td><input type="file" name="File" id="File"/></td>
    </tr>

        <tr>
            <td>&nbsp;</td>
            <td><input type="submit" name="commandName" value="Upload"/></td>
        </tr>
  </table>

  <!-- Finally, your form submit button -->
   <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" name="commandName" value="Create" class="btn btn-default"/>
        </div>
   </div>

}

And in your controllers' action method accept it as a parameter.

public ActionResult Create(Car car, string commandName)
{
    if(commandName.Equals("Create"))
    {
      // Call method to create new record...
    }
    else if (commandName.Equals("Upload"))
    {
      // Call another method to upload picture..
    }
}

If you research, there is another elegant generic solution, where you can just apply a multiple-button attribute on the Action method and it will automatically call the controller action. However, you need to be careful about getting values in that case ( *It's out of scope for this question). You can refer: How do you handle multiple submit buttons in ASP.NET MVC Framework?

Comments