DropDownList in conjunction with file upload in asp.net mvc - asp.net-mvc

I have a file upload function in my asp.net mvc application that allows users to upload an xslx file containing data that should be persisted to a database. That data can be related to one of many categories. I need to be able to discern which category the data that is coming in is supposed to be related to, so I thought that a drop down list would be perfect for the job. However, I don't know how to get at the lists selected value when the user posts the data. This is what the code for the form looks like:
<form action="/Import/UploadFiles/" method="post" enctype="multipart/form-data">
<fieldset id="fileImport">
<legend>Importinställningar</legend>
<label for="file">Importfil:</label>
<input type="file" id="file" name="file" />
<%= Html.DropDownList("Name", (IEnumerable<SelectListItem>)ViewData["assignments"]) %>
<p>
<input type="submit" value="Spara"/>
<input type="button" value="Avbryt" onclick="window.location.href='/'" />
</p>
</fieldset>
</form>
Since I am dealing with a file upload scenario I don't have an action link that I can use to pass data to the controller, but rather an input with the type submit.
How should I go about reading the select value of the drop down list so that its selected value can be passed to the Controller?

There are a couple of different ways that you can make this work. First, add a string parameter named Name to your UploadFiles method. The default binder will fill it in from the form value with the same name. Alternatively, you can use the ValueProvider inside the controller -- if you use the same action for both rendering the view and responding to the post, for instance -- to extract the value of the parameter named Name.
public ActionResult UploadFiles( string Name )
{
...
}
or
public ActionResult UploadFiles()
{
string name = this.ValueProvider.ContainsKey("Name")
? this.ValueProvider[key].AttemptedValue
: null;
...
}

Related

Exclude <input type='file'> from ViewModel

I have the following file input tag in the "Create" View:
<input type="file" id="RequestFile" name="RequestFile"/>
#Html.ValidationMessage("RequestFile")
The ViewModel contains this corresponding property:
[Required(ErrorMessage="Please select a file")]
public HttpPostedFileBase RequestFile { get; set; }
This works fine in the "Create" View, but in the "Edit" View, I get ModelState.Isvalid as false. Using the same ViewModel I would like to exclude this field from validations because I would not want to upload the file again.
I tried simply disabling the input tag like this:
<input type="file" id="RequestFile" name="RequestFile" disabled/>
This has a disabled input control but the Validation still fired.
Also applying the BindAttribute in the Controller did not work (see this Question)
Ideally (I know it sounds unlikely), if there is a server-side solution to this, please post your thoughts. If there is a small client-side trick, please let me know!
The best ways are remove the property altogether, and always access it directly from the form collection (and manually validate it) or manually remove the model state error using the property name (as #cheesemacfly has in his comment, ModelState.Remove("RequestFile")). The latter makes it very easy to fix then.
You could use form.onsubmit to check to see it document.getElementById("RequestFile").value is not null/empty and cancel the submit if it is.
something like
<form onsubmit="if(!document.getElementById('RequestFile').value){alert('Please select a file.');return false;}" >
<input type="file" id="RequestFile" name="RequestFile" />
<input type="submit"/>
</form>
return false cancels the submission.
http://jsfiddle.net/Cg7HY/1/
or put it in the click event of the submit button itself
http://jsfiddle.net/Cg7HY/3/

View Control name concatenated with ClientID and masterpage control name in ASP.NET MVC

I am working with an ASP.NET MVC application.
I have one master page having one contentplaceholder.
I have one view placed in the contentplaceholder of master page.
I have a few textBoxes that say "name", "age" , "email" in them.
I also have a submit button in my master page.
when I click the submit button, postback event will be called in the controller.
//POST
public ActionResult Result(FormCollection Form)
{
}
If I try to access the value of the text box name using
Form["name"]
it will give me null value.
Instead
Form["$ct100$contentplaceholder1$name"]
will give me the correct value.
How can I get the value using only name?
Don't mix Web Forms with MVC
You shouldn't be using <asp:TextBox id="name" /> but rather
<%= Html.TextBox("name") %>
The input name was autogenerated for you, which you don't want to happen. Try to generate those inputs in MVC-style, like this:
<%=Html.TextBox("name")%>
or like this:
<input type="text" id="name" name="name" value="" />

ASP.NET MVC example of editing multiple child records

Does anyone know of any examples or tutorials of an MVC view that shows parent/child data all on one form, and allows all the child records to be editable?
For example, say I have a table of people and another containing the vehicles they own. One one form, I want to show every vehicle for a given person, and make the data elements editable (i.e. license plate number, car color, etc.) in case there are mistakes. I don't want to jump to a separate edit form for each vehicle.
My attempts thus far have gotten me to the point where I can display the data, but I can't get it to post back to the controller. I've tried to narrow down the problem as far as I could here, but I'm still not getting it, and I think a broader example may be in order. Any ideas?
You can try something like this.
Suppose you have this object :
public class Vehicle
{
public int VehicleID { get; set; }
public string LicencePlate { get; set; }
public string Color { get; set; }
}
And this is your controller action that you'll use to edit vehicle details (where you'll post the form) :
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditVehicles(int Owner, Vehicle[] vehicles)
{
//manipulate the data, then return back to the list
return RedirectToAction("YourAction");
}
Then you should set your form this way :
<!--have a form for each person, listing their vehicles-->
<form action="/EditVehicles" method="post">
<input type="hidden" name="Owner" value="25" />
<input type="hidden" name="Vehicles[0].VehicleID" value="10" />
<input type="text" name="Vehicles[0].LicencePlate" value="111-111" />
<input type="text" name="Vehicles[0].Color" value="Red" />
<input type="hidden" name="Vehicles[1].VehicleID" value="20" />
<input type="text" name="Vehicles[1].LicencePlate" value="222-222" />
<input type="text" name="Vehicles[1].Color" value="Blue" />
<input type="submit" value="Edit" />
</form>
This will help the DefaultModelBinder to correctly bind the form data to your model in your controller. Thus Response.Write(vehicles[1].Color); on your controller, will print "Blue".
This is a very simple example, but I'm sure you get the idea. For more examples about binding forms to arrays, lists, collections, dictionaries, take a look at here.
I think the best you can get around this is by using AJAX posts, Whenever the user clicks on the submit button, You can hook in that event, create a JSON array of the things you want to persist and send it across.
The other way of course is to get all the information from the "FormCollection" object in the POST action. You just need to iterate through all the keys parse the data and then process it.

How to get selected rows using checkbox in asp.net MVC

Hi i've a problem related to html.checkbox in my MVC application.
My scenario is:
I've a list(index view) page where i bind data from the database with a checkbox to select/deselect the item. when i click save button i want to get selected rows to save those items back to db.
i used
1. <input type="checkbox" id="chk2" value="<%= item.recid %>" >
// I'm not getting value of chk2 in serverside
2. <%= html.CheckBox("chk1")%>
// i'm getting chk1 in serverside with value like 'true,false,true,false...'
in my model view iteration.
So how to do that in MVC application?
This is how I do it...
In the view, give all your checkboxes the same name and a unique value.
<input type="checkbox" name="MyCheckboxes" value="<%= item.recid %>" >
In your controller action method, pass an IList with the name of the checkboxes.
public ActionResult MyActionMethod(IList<string> MyCheckboxes)
{
...
}
You'll receive in MyCheckboxes a list of the values of only those checkboxes that were selected.
For 1), you need to specify a name on the input element.
You then need to match that name to a parameter on your Action Method.

How do you handle the output of a dynamically generated form in ASP.NET MVC?

Say you create a form using ASP.NET MVC that has a dynamic number of form elements.
For instance, you need a checkbox for each product, and the number of products changes day by day.
How would you handle that form data being posted back to the controller? You can't set up parameters on the action method because you don't know how many form values are going to be coming back.
Just give each checkbox a unique name value:
<input class="approveCheck" id="<%= "approveCheck" + recordId %>"
name="<%= "approveCheck" + recordId %>" type="checkbox" />
Then parse the list of form values in the Action, after submit:
foreach (var key in Request.Form.Keys)
{
string keyString = key.ToString();
if (keyString.StartsWith("approveCheck", StringComparison.OrdinalIgnoreCase))
{
string recNum = keyString.Substring(12, keyString.Length - 12);
string approvedKey = Request.Form["approveCheck" + recNum];
bool approved = !String.IsNullOrEmpty(approvedKey);
// ...
You don't need to pass form values as arguments; you can just get them from Request.Form.
One other option: write a model binder to change the list into a custom type for form submission.
Per Craig's answer.. that is safer. There are quirks to posting multiple form elements with the same name. I would add that it would be wise to wrap the logic that makes the "collection" of controls in a way similar to WebForms. Web Forms prepend the container control's name and adds an index. For example, in a Repeater the form elements inside would be named (something like) RepeaterName_Element1, RepeaterName_Element2. When you go to get the elements out, you have to use FindControl or something of the sort.
Depending on the binders you are using, this should work:
<%var i = 0;
foreach (var product (IList<ProductSelection>)ViewData["products"]) {%>
<%=Html.Hidden(string.Format("products[{0}].Id", i), product.Id)%>
<%=Html.Checkbox(string.Format("products[{0}].Selected", i))%>
<%=product.Name%><br/>
<%}%>
...which will result in HTML something like this (notice the array notation on the names):
<input name="products[0].Id" type="hidden" value="123">
<input name="products[0].Selected" type="checkbox">
Widget
<input name="products[1].Id" type="hidden" value="987">
<input name="products[1].Selected" type="checkbox">
Gadget
...and the controller method that handles the post:
public ActionResult SelectProducts(IList<ProductSelection> products)
{
...
}
Upon binding, products parameter will contain two instances of ProductSelection.
One caveat is that I have not used the new default binding for complex objects. Rather I am using either the NameValueDeserializer or CastleBind, both from MvcContrib. They both behave this way. I am guessing binding in the Beta will work the same way.
Depending on your data, you could either output a 'CheckboxList' (which is not possible in the newer versions any more) and use a string[] parameter, or you could set up multiple forms and just modify the action.

Resources