I have an MVC3 web application. On index.cshtml I have two dropdown lists. When I select from those lists I need to click on a next button and I want to display the selected values. How can i do this?
homecontroller.cs
DataRepository objRepository = new DataRepository();
public ActionResult Index()
{
ViewModel objViewModel = new ViewModel();
objViewModel.ID = objRepository.GetPricingSecurityID();
objViewModel.ddlId = objRepository.GetCUSIP();
return View(objViewModel);
}
ViewModel.cs
public class ViewModel
{
//DDL ID
[Required(ErrorMessage = "Please select a PricingSecurityID")]
public List<SelectListItem> ddlId { get; set; }
//DropDownList Values
[Required(ErrorMessage = "Please select a PricingSecurityID")]
public List<SelectListItem> ID { get; set; }
}
index.cshtml
<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="Next" />
</p>
How can I display selected values?
If your requirement is to build some kind of wizard, you need a way of maintaining state between steps.
ViewBag is no good for this because you should be following the PRG (Post/Redirect/Get) pattern for each wizard step.
TempData would work for navigating forward between steps but will fall over if the user goes back or navigates to a step directly.
You therefore need something with a longer lifetime. The ASP.NET Session object or a database are both good candidates for this.
Here's an example:
public class WizardController : Controller
{
public ActionResult Step1()
{
var session = GetWizardSession();
if (session.Step1 == null)
{
session.Step1 = new Step1View
{
PricingSecurityIds = new SelectList(new[] { 1, 2, 3, 4, 5 }),
SomeOtherIds = new SelectList(new[] { 1, 2, 3, 4, 5 })
};
}
return View(session.Step1);
}
[HttpPost]
public ActionResult Step1(Step1View cmd)
{
var session = GetWizardSession();
// save the wizard state
session.Step1.SelectedPricingSecurityId = cmd.SelectedPricingSecurityId;
session.Step1.SelectedSomeOtherId = cmd.SelectedSomeOtherId;
// now onto step 2
session.Step2 = new Step2View
{
PricingSecurityId = cmd.SelectedPricingSecurityId,
SomeOtherId = cmd.SelectedSomeOtherId,
Name = "John Smith"
};
return RedirectToAction("step2");
}
public ActionResult Step2()
{
return View(GetWizardSession().Step2);
}
public WizardSession GetWizardSession()
{
var session = Session["wizardsession"];
if (session == null)
{
session = new WizardSession();
Session["wizardsession"] = session;
}
return session as WizardSession;
}
}
public class Step1View
{
public SelectList PricingSecurityIds { get; set; }
public SelectList SomeOtherIds { get; set; }
public int SelectedPricingSecurityId { get; set; }
public int SelectedSomeOtherId { get; set; }
}
public class Step2View
{
public int PricingSecurityId { get; set; }
public int SomeOtherId { get; set; }
public string Name { get; set; }
}
public class WizardSession
{
public Step1View Step1 { get; set; }
public Step2View Step2 { get; set; }
}
In Step1 we make a call to GetWizardSession. This returns an object from the ASP.NET Session that contains all of the information we have collected for each step in the wizard. In this example we simply store the ViewModel for each step (i.e. session.Step1).
We check to see if Step1 exists in the session and create it if it doesn't. We then pass the Step1 model to our view.
When the user submits the form we update the "Selected" values in session.Step1. This ensures that if the user navigates back to /step1, we "remember" their values. We then build the model for Step2 and save it in the session.
When we navigate to /step2 we assume that a model exists in the session (because they should have got here from step1) so we just return return View(GetWizardSession().Step2);
The views:
Step 1
#model MvcWizardDemo.Controllers.Step1View
#{
ViewBag.Title = "Step1";
}
<h2>Step1</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Step1View</legend>
<div class="editor-label">
#Html.LabelFor(m => m.PricingSecurityIds)
</div>
<div class="editor-field">
#Html.DropDownListFor(m => m.SelectedPricingSecurityId, Model.PricingSecurityIds)
#Html.ValidationMessageFor(m => m.PricingSecurityIds)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.SomeOtherIds)
</div>
<div class="editor-field">
#Html.DropDownListFor(m => m.SelectedSomeOtherId, Model.SomeOtherIds)
#Html.ValidationMessageFor(m => m.SomeOtherIds)
</div>
<p>
<input type="submit" value="Next" />
</p>
</fieldset>
}
Step 2
#model MvcWizardDemo.Controllers.Step2View
#{
ViewBag.Title = "Step2";
}
<h2>Step2</h2>
Hi, #Model.Name you selected the following values in the previous step:
<p>
<strong>Security Id:</strong> #Model.PricingSecurityId
</p>
<p>
<strong>Some other Id:</strong> #Model.SomeOtherId
</p>
Try this it should work :
[HttpPost]
public ActionResult Index(ViewModel model)
{
// put what you want to show
}
Related
I have 2 models in my MVC 3 application, CustomerOrder and OrderDetail.
My Model OrderDetail is with List.
Model
public class CustomerOrder
{
public int CustomerId { get; set; }
public int NetPrice { get; set; }
public List<OrderDetail> Orderlist { get; set; }
public CustomerOrder()
{
Orderlist = new List<OrderDetail>();
}
}
public class OrderDetail
{
public string ProductName { get; set; }
public int Quantity { get; set; }
public int Price { get; set; }
public int TotalPrice {get{ return Price*Quantity;} }
}
This is My Controller
public ActionResult CustomerOrder()
{
return View();
}
[HttpPost]
public ActionResult CustomerOrder(CustomerOrder SelectedOrder)
{
DataBase dataBase = new DataBase();
var result = dataBase.InsertData(SelectedOrder);
ViewData["result"] = result;
return View();
}
This is My View for CustomerOrder
#model MvcCustomerOrderClass4g.Models.CustomerOrder
#{
ViewBag.Title = "CustomerOrder";
}
<h2>CustomerOrder</h2>
#using (Html.BeginForm()) {
<fieldset>
<legend>CustomerOrder</legend>
<div class="editor-label">
#Html.LabelFor(model => model.CustomerId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CustomerId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.NetPrice)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.NetPrice)
</div>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
}
#{
if (ViewData["result"] != "" && ViewData["result"] != null)
{
<script type="text/javascript" lang="javascript">
alert("Data saved Successfully");
</script>
}
}
My Model OrderDetail is with List. How to use it as a list in my view?
Here I want to add OrderDetail model. I also created another view for OrderDetails, for adding it as Partial in CustomerOrder.
The easiest way would be to create an EditorTemplate:
#model OrderDetail
#Html.HiddenFor(m => m.Id)//your model doesn't seem to have an id?
#Html.DisplayFor(m => m.ProductName)
#Html.EditorFor(m => m.ProductName)
Then in your view with the CustomerOrder model just do this:
#Html.LabelFor(model => model.OrderList)
#Html.EditorFor(model => model.OrderList)
I'm new to programming so I'm still learning.
I need to add Items to Grocery from a single view. But I can't get the data to save.
When I hit save I don't get any exceptions, the page just loads but nothing is saved to the
database. Can I get some help/guidance as to what I am doing wrong?
Data Class
public class Grocery
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Item> Items { get; set; }
}
public class Item {
public int ItemId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
View Model
public class GroceryViewModel
{
public Grocery Grocery { get; set; }
public virtual Item Item { get; set; }
public GroceryViewModel(int GroceryId)
{
using (var db = new MyContext())
{
Grocery = db.Groceries
.Include("Items")
.SingleOrDefault(a => a.Id == GroceryId);
}
}
}
Controller
public ActionResult Edit(int GroceryId, GroceryViewModel groceryViewModel)
{
var model = new GroceryViewModel(GroceryId);
var plusItems = new Item
{
Name = groceryViewModel.Item.Name,
Description = groceryViewModel.Item.Description,
};
db.Items.Add(plusItems);
db.SaveChanges();
return RedirectToAction(model);
View
#model Project.Models.GroceryViewModel
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Groceries</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Item.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item.Name)
#Html.ValidationMessageFor(model => model.Item.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Add Item" />
</p>
</fieldset>
try
using (var db = new MyContext())
{
var grocery = db.Groceries.Single(a => a.Id == groceryId);
var plusItems = new Item
{
Name = groceryViewModel.Item.Name,
Description = groceryViewModel.Item.Description,
};
grocery.Items.Add(plusItems);
db.SaveChanges();
}
I have an MVC model with a property that contains a generic collection of types that inherit from a single type. It displays the editor exactly as I would expect, but when I post back the types of all the items are the base type. How do I get it to return the correct types?
Model...
public class PageEM {
public long Id { get; set; }
public virtual IList<FieldEM> Fields { get; set; }
}
public class FieldEM { // I'd really like this to be abstract.
public long Id { get; set; }
public string Caption { get; set; }
public string Value { get; set; }
}
public class TextFieldEM : FieldEM {
}
public class CheckBoxFieldEM : FieldEM {
public bool ValueData {
get { return (bool)Value; }
set { Value = (string)value; }
}
PageEM View...
#model PageEM
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Fields</legend>
#Html.HiddenFor(m => m.Id)
#Html.EditorFor(m => m.Fields)
<input type="submit" value="Submit" title="Submit" />
</fieldset>
}
TextFieldEM Editor...
#model TextFieldEM
<div>
#Html.HiddenForFor(m => m.Id)
<div>
#Html.LabelFor(m => m.Value, Model.Caption)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.Value)
#Html.ValidationMessageFor(m => m.Value)
</div>
</div>
CheckBoxFieldEM Editor...
#model CheckBoxFieldEM
<div>
#Html.HiddenForFor(m => m.Id)
<div class="editor-field">
#Html.EditorFor(m => m.DataValue)#Html.LabelFor(m => m.DataValue, Model.Caption, new { #class = "checkbox" })
</div>
</div>
Controller...
public partial class PageController : Controller {
public virtual ActionResult Edit() {
PageEM em = new PageEM() {
Id = 123,
Fields = new List<FieldEM>() {
new TextFieldEM() { Id = 1, Caption = "Text Line", Value = "This is test" },
new CheckBoxEM() { Id = 2, Caption = "Check here", ValueData = true }
}
};
return View(em);
}
[HttpPost]
public virtual ActionResult Edit(PageEM em) {
if (!ModelState.IsValid)
return View(em);
// but all of the em.Fields are FieldEM.
}
}
So how do I get it to post back with the subclassed FieldEMs?
You can't do that with the DefaultModelBinder. You'll have to create your own custom model binder in order to do what you want to do.
These might be helpful:
https://gist.github.com/joelpurra/2415633
ASP.NET MVC3 bind to subclass
ASP.NET MVC 3: DefaultModelBinder with inheritance/polymorphism
I have a model with an object that contains a collection like this:
namespace API.Example.Models
{
public class OrderTest
{
public string UserName { get; set; }
public string Token { get; set; }
public POCO.Order Order { get; set; }
}
}
namespace Supertext.API.POCO
{
public class Order
{
public List<TranslationGroup> Groups = new List<TranslationGroup>();
}
public class TranslationGroup
{
public string GroupId { get; set; }
}
}
The Order object contains a collection called Groups.
In the view I display the collection like this (with the index like explained in several examples)
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#for (int i = 0; i < Model.Order.Groups.Count; i++)
{
#Html.LabelFor(m => Model.Order.Groups[i].GroupId)
#Html.TextBoxFor(m => Model.Order.Groups[i].GroupId)
}
And this is the Controller method that gets called:
[HttpPost]
public ActionResult Index(Models.OrderTest model)
The HTML of the UserName element:
<input id="UserName" name="UserName" style="width:300px;" type="text" value="">
and the GroupId element:
<input id="Order_Groups_0__GroupId" name="Order.Groups[0].GroupId" type="text" value="1">
I can access the UserName, but there is nothing in the collection.
What am I missing?
And whats the difference between using m.UserName and Model.Order.Groups (I mean m and Model). Is that my issue?
Each property of POCO entity use like a property managed by the CLR. Let the CLR manage the create of instance and etc.. or you can generate conflicts that can throw issues like you have.
Change your Order code to this:
public class Order
{
public List<TranslationGroup> Groups { get; set; }
}
--EDIT
I create a new project and add the following class:
public class TranslationGroup
{
public string GroupId { get; set; }
}
public class Order
{
public List<TranslationGroup> Groups { get; set; }
}
public class OrderTest
{
public string UserName { get; set; }
public string Token { get; set; }
public Order Order { get; set; }
}
Here my code behind of the OrderTestController:
public ActionResult Index()
{
var orderTest = new Models.OrderTest()
{
UserName = "Vinicius",
Token = "12as1da58sd558",
Order = new Models.Order()
{
Groups = new List<Models.TranslationGroup>()
{
new Models.TranslationGroup() { GroupId = "a54s"},
new Models.TranslationGroup() { GroupId = "a87d"},
new Models.TranslationGroup() { GroupId = "2gf4"}
}
}
};
return View(orderTest);
}
[HttpPost]
public ActionResult Index(Models.OrderTest model)
{
return View();
}
And Index View:
#model TestCollection.Models.OrderTest
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>OrderTest</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Token)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Token)
#Html.ValidationMessageFor(model => model.Token)
</div>
#for (int i = 0; i < Model.Order.Groups.Count; i++)
{
<div class="editor-label">
#Html.LabelFor(m => Model.Order.Groups[i].GroupId)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => Model.Order.Groups[i].GroupId)
</div>
}
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
So, if you run, and go to OrderTest view, you 'll see all attributes filled, and when you click in create, all things will be binded (the collection as well).
I have a model class as follows:
namespace MvcApplication1.Models
{
public enum Sex { Male, Female };
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
[Required(ErrorMessage="Please select either Female or Male.")]
public Sex? Sex { get; set; }
}
}
The Edit action does :
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult Edit()
{
var Person = new Person { Id = 1, Name = "Someone", Sex = Sex.Male };
return View(Person);
}
}
}
Question 1
How to mark up the Edit view such that there is a dropdown control containing 3 options: "--Select--", "Female", and "Male". For the Person passed to the view, "Male" must be selected.
Question 2
How to make up the Create view and leave the dropdown control selecting "--Select--" by default.
Here is the Create action:
public ActionResult Create()
{
var Person = new Person();
return View(Person);
}
There is a good answer already on how to convert an Enum into a SelectList but I'll reuse that code inline to simply the answer.
public ActionResult Edit()
{
var Person = new Person { Id = 1, Name = "Someone", Sex = Sex.Male };
List<object> values = new List<object>();
values.Add(new { ID = "choose", Name = "--Select--" });
values.AddRange(from Sex sex in Enum.GetValues(typeof(Sex))
select new { ID = sex, Name = sex.ToString() });
ViewData["sexes"] = new SelectList(values, "Id", "Name", Person.Sex);
return View(Person);
}
Now the Edit.cshtml view:
#model Test.Models.Person
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#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.Sex)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Sex, (SelectList)ViewData["sexes"])
#Html.ValidationMessageFor(model => model.Sex)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Now the control action to post the form to:
[HttpPost]
public ActionResult Edit(Person person)
{
var newName = person.Name;
var newSex = person.Sex;
return RedirectToAction("index", "home");
}
Now run the project in debug mode with a break on the return RedirectToAction("index", "home"); line in the post-to Edit action. See how you can change form values in the view and then do what you need to do in the posted-to action? There are other options than using ViewData to pass the list but they complicate the example and are plentiful.
The Create action would look like this:
public ActionResult Create()
{
Person person = new Person();
List<object> values = new List<object>();
values.Add(new { ID = "choose", Name = "--Select--" });
values.AddRange(from Sex sex in Enum.GetValues(typeof(Sex))
select new { ID = sex, Name = sex.ToString() });
ViewData["sexes"] = new SelectList(values, "Id", "Name");
return View(person);
}
The default select list item will be the first one so it would show "--Select--" as the default choice.