passing dropdown's selected value from view to controller in mvc3? - asp.net-mvc

I have mvc3 web application.
In that i have used EF and populate two dropdownlists from database.
Now when i select values from those dropdownlists i need to show them inside webgrid
how can i do this?
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Mapping</legend>
<div class="editor-label">
#Html.Label("Pricing SecurityID")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.ID,
new SelectList(Model.ID, "Value", "Text"),
"-- Select category --"
)
#Html.ValidationMessageFor(model => model.ID)
</div>
<div class="editor-label">
#Html.Label("CUSIP ID")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.ddlId,
new SelectList(Model.ddlId, "Value", "Text"),
"-- Select category --"
)
#Html.ValidationMessageFor(model => model.ddlId)
</div>
<p>
<input type="submit" value="Mapping" />
</p>
</fieldset>
}
when i clicked on Mapping button it will goes to new page called Mapping.cshtml and have to show webgrid with those two values.

I would create a ViewModel
public class YourClassViewModel
{
public IEnumerable<SelectListItem> Securities{ get; set; }
public int SelectedSecurityId { get; set; }
public IEnumerable<SelectListItem> CUSIPs{ get; set; }
public int SelectedCUSIPId { get; set; }
}
and in my Get Action method, I will return this ViewModel to my strongly typed View
public ActionResult GetThat()
{
YourClassViewModel objVM=new YourClassViewModel();
objVm.Securities=GetAllSecurities() // Get all securities from your data layer
objVm.CUSIPs=GetAllCUSIPs() // Get all CUSIPsfrom your data layer
return View(objVm);
}
And In my View Which is strongly typed,
#model YourClassViewModel
#using (Html.BeginForm())
{
Security :
#Html.DropDownListFor(x => x.SelectedSecurityId ,new SelectList(Model.Securities, "Value", "Text"),"Select one") <br/>
CUSP:
#Html.DropDownListFor(x => x.SelectedCUSIPId ,new SelectList(Model.CUSIPs, "Value", "Text"),"Select one") <br/>
<input type="submit" value="Save" />
}
and now in my HttpPost Action method, I will accept this ViewModel as the parameter and i will have the Selected value there
[HttpPost]
public ActionResult GetThat(YourClassViewModel objVM)
{
// You can access like objVM.SelectedSecurityId
//Save or whatever you do please...
}

Post the form to mapping actionresult. in the actionresult mapping receive dropdown in parameters as mapping(string ID, string ddID). Take these values to view using ViewData.
A better approach will be to make a viewmodel for grid view and make your mapping view strongly typed and use value on grid as you required

Related

ASP.Net MVC 4.0 - Validation Issues With array based properties on ViewModel

ASP.Net MVC 4.0 - Validation Issues With array based properties on ViewModel .
Scenario :
When a ViewModel has a string array as a property type,the default Scaffolding template for say, Edit, does not render the that property in the markup.
Say, I have ViewModel setup like this :
Employee.cs
public class Employee
{
[Required]
public int EmpID
{
get;
set;
}
[Required]
public string FirstName
{
get;
set;
}
[Required]
public string LastName
{
get;
set;
}
[Required]
public string[] Skills
{
get;
set;
}
}
}
The (strongly typed) Edit View generated by the scaffolding template, as shown below, typically skips the portion relevant to field Skills.
**Employee.cshtml**
#model StringArray.Models.Employee
#{
ViewBag.Title = "EditEmployee";
}
<h2>EditEmployee</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Employee</legend>
<div class="editor-label">
#Html.LabelFor(model => model.EmpID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.EmpID)
#Html.ValidationMessageFor(model => model.EmpID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
The corresponding Controller code is
..
[HttpGet]
public ActionResult EditEmployee()
{
Employee E = new Employee()
{
EmpID = 1,
FirstName = "Sandy",
LastName = "Peterson",
Skills = new string[] { "Technology", "Management", "Sports" }
};
return View(E);
}
[HttpPost]
public ActionResult EditEmployee(Employee E)
{
return View(E);
}
To get the missing section for the Skills field, I added
Snippet to the View
<div class="editor-label">
#Html.LabelFor(model => model.Skills)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Skills)
#Html.ValidationMessageFor(model => model.Skills)
</div>
Corresponding UIHint to the ViewModel
[UIHint("String[]")]
public string[] Skills ...
EditorTemplates inside relevant folder as
~\View\shared\EditorTemplates\String[].cshtml
and
~\View\shared\EditorTemplates\mystring.cshtml
string[].cshtml
#model System.String[]
#if(Model != null && Model.Any())
{
for (int i = 0; i < Model.Length; i++)
{
#Html.EditorFor(model => model[i], "mystring")
//Html.ValidationMessageFor(model => model[i])
}
}
mystring.cshtml
#model System.String
#{
//if(Model != null)
{
//To resolve issue/bug with extra dot getting rendered in the name - like
//Skills.[0], Skills.[1], etc.
//ViewData.TemplateInfo.HtmlFieldPrefix=ViewData.TemplateInfo.HtmlFieldPrefix.Replace(".[", "[");
#Html.TextBoxFor(model => model)
}
}
But despite this all, the Validations for the Skills section [with 3 fields/elements - refer the EditEmployee method in Controller above.]
are entirely skipped, on postback.
I tried below changes inside the mystring.cshtml EditorTemplate :
//to correct the rendered names in the browser from Skills.[0] to Skills for all the 3 items in the
//Skills (string array), so that model binding works correctly.
string x = ViewData.TemplateInfo.HtmlFieldPrefix;
x = x.Substring(0, x.LastIndexOf("."));
#Html.TextBoxFor(model =>model, new { Name = x })
Postback WORKS But Validations DON'T, since the "data-valmsg-for" still points to <span class="field-validation-valid" data-valmsg-for="Skills" data-valmsg-replace="true"></span>
and thus doesn't apply at granular level - string element level.
Lastly, I tried removing #Html.ValidationMessageFor(model => model.Skills) from the Employee.cshtml and correspondingly adding the
same to string[].cshtml as #Html.ValidationMessageFor(model => model[i]).
But this led to data-valmsg-for getting rendered for each granular string element like
data-valmsg-for="Skills.[0]" ,
data-valmsg-for="Skills.[1]" and data-valmsg-for="Skills.[2]", respectively.
Note: Validations work for other fields - EmpID, FirstName LastName, BUT NOT for Skills.
Question
How do I set the data-valmsg-for="Skills" for each of the above three granular elements related to Skills property.
I am stuck on this for quite some time now. It would be nice if some one can point out the issue, at the earliest.
Thanks, Sandesh L
This is where you like to change
[Required]
public string[] Skills
{
get;
set;
}
You are giving validation on the array.
you might want to have a new string class call Skill
[Required]
public string Skill
{
get;
set;
}
And you can change to you model with
[Required]
public List<Skill> Skills
{
get;
set;
}
I prefer using List instead of array. Then, you can change you skill view according to the model updated
you template view can be something like
#model IEnumerable<Skill>
<div class="editor-label">
<h3>#Html.LabelFor(model=> model.Skills)
</h3>
</div>
<div class="editor-field">
#foreach (var item in Model)
{ #Html.Label(model => item)
#Html.TextBoxFor(model => item) <br/>
}
#Html.ValidationMessageFor(model => item)

Custom update method in MVC 4 with WCF

I am a newbie in MVC and currently using MVC 4 + EF Code First and WCF in my web project. Basically, in my project, WCF services will get the data from database for me, and it will take care of updating data as well. As a result, when I finish updating a record, I have to call the service client to make the change for me other than the "traditional" MVC way. Here is my sample code:
Model:
[DataContract]
public class Person
{
[Key]
[DataMember]
public int ID{ get; set; }
[DataMember]
public string Name{ get; set; }
[DataMember]
public string Gender{ get; set; }
[DataMember]
public DateTime Birthday{ get; set; }
}
Controller:
[HttpPost]
public ActionResult Detail(int ID, string name, string gender, DateTime birthday)
{
// get the WCF proxy
var personClient = personProxy.GetpersonSvcClient();
//update the info for a person based on ID, return true or false
var result = personClient.Updateperson(ID, name, gender, birthday);
if (result)
{
return RedirectToAction("Index");
}
else
{
//if failed, stay in the detail page of the person
return View();
}
}
View:
#model Domain.person
#{
ViewBag.Title = "Detail";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Detail</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Gender)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Gender)
#Html.ValidationMessageFor(model => model.Gender)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Birthday)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Birthday)
#Html.ValidationMessageFor(model => model.Birthday)
</div>
<p>
<input type="submit" value="Update"/>
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
The controller is the part I am confused of. The Detail function takes multiple parameters, how can I call it from the View? Also, what should I put into this return field in the controller:
//if failed, stay in the detail page of the person
return View();
We usually put the model in, but the model seems to be not changed, since I am updating the database directly from my WCF service.
Any suggestion would be really appreciated!
UPDATE:
I know I can probably get it works by change the update method to take only one parameter which is the model itself, but this is not an option in my project.
you call the Details action in the controller when you hit "Update"
//sidenote : use single parameter in your function that accepts the values it makes life easier
The form will call the post method in the controller that has the same name as the get method that rendered the view when it is submitted.
You can alter this default behavior by specifying parameters in the BeginForm method
#using (Html.BeginForm("SomeAction", "SomeController"))
Also, you are using a strongly typed view (good!), so you can change the signature of your post method to accept the model object
[HttpPost]
public ActionResult Detail(Person person)

MVC3 - How to add dropdown to a form (Post) populated with different entity

Hi I am working in a MVC 3 application. I have a Create Form with following code.
#model Xrm.Student
#{
ViewBag.Title = "Create Student Record";
}
#using (Html.BeginForm("Create", "Student", FormMethod.Post))
{
<div class="editor-label">
#Html.LabelFor(model => #Model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => #Model.FirstName)
#Html.ValidationMessageFor(model => #Model.FirstName)
</div>
<div>
<input id="Submit1" type="submit" value="Submit" />
</div>
}
I want to add a new drop down under Firsname field which should be populated with pubjects. Subject is different Entity. I could be very easy, but I am newbie with MVC so I just stuck here. Can anyone please suggest me the way to achieve it.
Thanks and Regards
I would define a view model:
public class MyViewModel
{
public Student Student { get; set; }
[DisplayName("Subject")]
[Required]
public string SubjectId { get; set; }
public IEnumerable<Subject> Subjects { get; set; }
}
and then have your controller populate and pass this view model to the view:
public ActionResult Create()
{
var model = new MyViewModel();
model.Student = new Student();
model.Subjects = db.Subjects;
return View(model);
}
and finally have your view strongly typed to the view model:
#model MyViewModel
#{
ViewBag.Title = "Create Student Record";
}
#using (Html.BeginForm())
{
<div class="editor-label">
#Html.LabelFor(x => x.Student.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(x => x.Student.FirstName)
#Html.ValidationMessageFor(x => x.Student.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(x => x.SubjectId)
</div>
<div class="editor-field">
#Html.DropDownListFor(
x => x.SubjectId,
new SelectList(Model.Subjects, "Id", "Name"),
"-- Subject --"
)
#Html.ValidationMessageFor(x => x.SubjectId)
</div>
<div>
<input type="submit" value="Submit" />
</div>
}
The "Id" and "Name" values I used for the SelectList must obviously be existing properties on your Subject class that you want to be used as respectively binding the id and the text of each option of the dropdown.

ViewModel IEnum<> property is returning null (not binding) when contained in a partial view?

I have a ViewModel that contains a Product type and an IEnumerable< Product > type. I have one main view that displays the ViewModel.Product at the top of the page but then I have a partial view that renders the ViewModel.IEnumerable< Product > data. On the post the first level product object comes back binded from the ViweModel whereas the ViewModel.IEnumerable< Product > is coming back null.
Of course if I remove the partial view and move the IEnumerable< Product > view to the main View the contents comes back binded fine. However, I need to put these Enumerable items in a partial view because I plan on updating the contents dynamically with Ajax.
Why is the IEnumerable< Prouduct> property not getting binded when it's placed in a partial view? Thx!
Models:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class ProductIndexViewModel
{
public Product NewProduct { get; set; }
public List<Product> Products { get; set; }
}
public class BoringStoreContext
{
public BoringStoreContext()
{
Products = new List<Product>();
Products.Add(new Product() { ID = 1, Name = "Sure", Price = (decimal)(1.10) });
Products.Add(new Product() { ID = 2, Name = "Sure2", Price = (decimal)(2.10) });
}
public List<Product> Products { get; set; }
}
Views:
Main index.cshtml:
#model ViewModelBinding.Models.ProductIndexViewModel
#using (#Html.BeginForm())
{
<div>
#Html.LabelFor(model => model.NewProduct.Name)
#Html.EditorFor(model => model.NewProduct.Name)
</div>
<div>
#Html.LabelFor(model => model.NewProduct.Price)
#Html.EditorFor(model => model.NewProduct.Price)
</div>
#Html.Partial("_Product", Model.Products)
<div>
<input type="submit" value="Add Product" />
</div>
}
Parial View _Product.cshtml:
#model List<ViewModelBinding.Models.Product>
#for (int count = 0; count < Model.Count; count++)
{
<div>
#Html.LabelFor(model => model[count].ID)
#Html.EditorFor(model => model[count].ID)
</div>
<div>
#Html.LabelFor(model => model[count].Name)
#Html.EditorFor(model => model[count].Name)
</div>
<div>
#Html.LabelFor(model => model[count].Price)
#Html.EditorFor(model => model[count].Price)
</div>
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
BoringStoreContext db = new BoringStoreContext();
ProductIndexViewModel viewModel = new ProductIndexViewModel
{
NewProduct = new Product(),
Products = db.Products
};
return View(viewModel);
}
[HttpPost]
public ActionResult Index(ProductIndexViewModel viewModel)
{
// work with view model
return View();
}
}
When you use #Html.Partial("_Product", Model.Products) your input fields do not have correct names. For example instead of:
<input type="text" name="Products[0].ID" />
you get:
<input type="text" name="[0].ID" />
Just look at your generated markup and you will see the problem. This comes from the fact that when you use Html.Partial the navigational context is not preserved. The input fields names are not prefixed with the name of the collection - Products and as a consequence the model binder is not able to bind it correctly. Take a look at the following blog post to better understand the expected wire format.
I would recommend you using editor templates which preserve the context. So instead of:
#Html.Partial("_Product", Model.Products)
use:
#Html.EditorFor(x => x.Products)
and now move your _Product.cshtml template to ~/Views/Shared/EditorTemplates/Product.cshtml. Also since the editor template automatically recognizes that the Products property is an IEnumerable<T> it will render the template for each item of this collection. So your template should be strongly typed to a single Product and you can get rid of the loop:
#model Product
<div>
#Html.LabelFor(model => model.ID)
#Html.EditorFor(model => model.ID)
</div>
<div>
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
</div>
<div>
#Html.LabelFor(model => model.Price)
#Html.EditorFor(model => model.Price)
</div>
Now everything works by convention and it will properly bind.

No value for the dropdownlist when my form is submitted

I try to use a dropdownlist in my view for showing a list of authors (users). I'm able to populate this dropdown and see the content in my view. When submitting my form, I debug my action in my controller and when inspecting my model, the value of the field associated with my dropdown is null.
Here is my action controller (before showing my view):
public ActionResult Create()
{
IEnumerable<User> authors = m_AccountBusiness.GetAllUsers();
PageCreateViewModel viewModel = new PageCreateViewModel
{
PageToCreate = new PageFullViewModel(),
Authors = authors.Select(x => new SelectListItem { Text = x.UserName, Value = x.UserID.ToString() })
};
return View(viewModel);
}
Here is (a portion of) my view:
#model MyBlog.ViewModels.PageCreateViewModel
<h3>Create</h3>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.PageToCreate.PageID)
<div class="editor-label">
#Html.LabelFor(model => model.PageToCreate.Title)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.PageToCreate.Title, new { #class = "titleValue" })
#Html.ValidationMessageFor(model => model.PageToCreate.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PageToCreate.Author)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.PageToCreate.Author, Model.Authors, "Please select...")
</div>
Here is my PageCreateViewModel:
public class PageCreateViewModel
{
public PageFullViewModel PageToCreate { get; set; }
public IEnumerable<SelectListItem> Authors { get; set; }
}
Any idea?
Thanks.
Thank you guys. I finally found my error: it is not Author the right property to bind to, it must be AuthorID !!
<div class="editor-field">
#Html.DropDownListFor(model => model.PageToCreate.AuthorID, Model.Authors, "Please select...")
</div>
Thanks anyway.
You have to add an extra string property to your PageCreateViewModel. In this property we will store the selected value. Lets say it's name is "Author". Edit: I noticed you have a property for it in your model but give it a try like this.
The dropdownlist filling needs to look like this on your view.
#Html.DropDownList("Author", Model.Authors)

Resources