I'm trying to pass an array from my controller to my view using my Model. My method does not work for some reason. I've posted it below.
Controller:
public ActionResult Confirmation()
{
string[] Array = new string[2] {"Pending", "07/07/2013"};
ConfirmationModel Con = new ConfirmationModel
{
Status = Array[0],
AppDate = Array[1],
};
return View();
}
Model:
public class ConfirmationModel
{
public string Status { get; set; }
public string AppDate { get; set; }
}
View:
#model site.ConfirmationModel
#{
ViewBag.Title = "Confirmation";
}
#Html.DisplayFor(Mode => Model.Status)
#Html.DisplayFor(Mode => Model.AppDate)
You aren't passing your model to your view. Change the line below:
return View();
To this;
return View(Con);
You haven't actually included the model in the result. Do this:
return View(Con);
You should return populated model to your view. In your case:
return view(con)
Then use con in your view.
You're not passing any model to the view to be rendered.
The View() method has an overload to receive an object model to render in the view.
Try this: return View(Con);
Related
I'm trying to pass a list of values from the controller to the view, but apparently I got this issue where the list cannot be passed. I already tried passing one value and it has no problem. But when I try to pass list, it show the following error -
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[vidly.Models.pelanggan]', but this
dictionary requires a model item of type 'vidly.models.pelanggan'.
I have this model -
public class pelanggan
{
public string Nama { get; set; }
}
The controller code -
// GET: Pelanggan
public ActionResult Index()
{
var name = new List<pelanggan> {
new pelanggan {Nama = "Paidi" },
new pelanggan {Nama = "Budi" }
};
return View(name);
}
This is my view file
#model vidly.Models.pelanggan
#{
ViewBag.Title = "index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Customer</h2>
#foreach(var Nama in Model.pelanggan)
{
<li>#Nama.Nama</li>
}
I already tried to create a ViewModel but it also showing same error. Can you point where the error is?
You are returning a List<T> from the controller. So, the model declared in your view should be able to receive a list and iterate over it.
Replace the model declaration in the view file with following -
#using vidly.Models;
#model IEnumerable<pelanggan>
Then you can iterate/loop over the model like -
#foreach(var p in Model) // p represents a "pelanggan" object in the list
{
<li>#p.Nama</li>
}
The problem is the missmatch of types between what you return return View(name); and what te view expects #model vidly.Models.pelanggan You could change to #model List<vidly.Models.pelanggan> but instead I'd say:
public class pelanggan
{
public List<string> Namas { get; set; }
}
Then
public ActionResult Index()
{
var model = new pelanggan {
name = new List<string> {
"Paidi",
"Budi"
}
};
return View(model);
}
And finally in your view
#foreach(var Nama in Model.Namas)
{
<li>#Nama</li>
}
MVC newbie question:
I'm picking up a URL of the form go/{mainnav}/{subnav}, which I've successfully routed to the GoController class, method:
public ActionResult Index(string mainnav, string subnav) {
return View();
}
So far, so good. But now I want the view to return different HTML, depending on the values of mainnav or subnav. Specifically, inside a javascript block, I want to include the line:
myobj.mainnav = [value of mainnav parameter];
and, only if subnav is not null or empty:
myobj.subnav = [value of subnav parameter];
How do you pass those parameters to an aspx page that doesn't have a codebehind?
You use a ViewModel class to transfer the data:
public class IndexViewModel
{
public string MainNav { get; set; }
public string SubNav { get; set; }
public IndexViewModel(string mainnav, string subnav)
{
this.MainNav = mainnav;
this.SubNav = subnav;
}
}
Your action method then comes out
public ActionResult Index(string mainnav, string subnav)
{
return View(new IndexViewModel(mainnav, subnav));
}
This means your view has to be strongly typed:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<YourNameSpace.IndexViewModel>" %>
In your view, you output the data like so:
myobj.mainnav = <%: Model.MainNav %>;
An alternative solution if you use MVC3, would be to use the dynamic ViewBag:
public ActionResult Index(string mainnav, string subnav)
{
ViewBag.MainNav = mainnav;
ViewBag.SubNav = subnav;
return View();
}
which would be accessed in the page as so:
myobj.mainnav = <%: ViewBag.MainNav %>;
However, I would recommend that you read up on unobtrusive javascript and see if you can improve your design to avoid this specific problem.
If you are using MVC3 I would suggest passing the values into the ViewBag.
ViewBag.MainNav = "xxxx";
ViewBag.SubNav = null;
then on your view page, where you define the JavaScript and add the value.
if you dont have MVC 3 if you use ViewData["MainNav"]), to store your value has the same effect.
Did you try accessing parameters from Request in your view?
i.e.
Request.Params["mainnav"]
or
Request.Params["subnav"]
Works in MVC
i'm using following approach:
ViewModel.class:
public class TitleBodyModel
{
public string Title { get; set; }
public string Body { get; set; }
public TitleBodyModel() { Title = Body = ""; }
public TitleBodyModel(string t, string b) { this.Title = t; this.Body = b; }
}
In the main View:
#Html.Partial("_TitleBody" , new XXX.Models.TitleBodyModel("title", "body" ))
Then in a partial view:
#model XXX.Models.TitleBodyModel
<div class="bl_item">
<div class="bl_title">#Model.Title</div>
<div class="bl_body">#Model.Body</div>
</div>
If i understand this can be a solution:
public ActionResult Index(string mainnav, string subnav)
{
return View(mainnav | subnav);
}
In the Html View you can use View
and after
<%=Model %>
This question already has answers here:
The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'
(6 answers)
Closed 6 years ago.
In my MVC project I pass list of currencies to the view within the drop down list. However, once I try to post the view I get the following exception:
The ViewData item that has the key 'FromCurrencyId' is of type
'System.Int32' but must be of type 'IEnumerable'.
Currency Controller
namespace Project.Controllers
{
public class CurrencyController : Controller
{
[HttpGet]
// GET: Currency
public ActionResult Index()
{
CurrenciesClient Cur = new CurrenciesClient();
var listCurrency = Cur.findAll().ToList();
Currencies model = new Currencies();
model.FromCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
model.ToCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
return View(model);
}
[HttpPost]
public ActionResult Index(Currencies cur)
{
if (ModelState.IsValid)
{
if (cur.FromCurrencyId == cur.ToCurrencyId)
{
//do something if same currecnies and return.
ModelState.AddModelError("CurrencyCountry", "Can't make the conversion for the same value");
}
else
{
some code .....
}
}
return View(cur);
}
}
}
Currencies VM
namespace Project.ViewModels
{
public class Currencies
{
public int Id { get; set; }
[Required]
public int FromCurrencyId { get; set; }
public SelectList FromCurrencies { get; set; }
[Required]
public int ToCurrencyId { get; set; }
public SelectList ToCurrencies { get; set; }
public string CurrencyName { get; set; }
public string CurrencyCountry { get; set; }
[Required]
public decimal ConversionRate { get; set; }
public decimal Value { get; set; }
public SelectList AvailableCurrencies { get; set; }
}
}
CurrencyClient web service VM
namespace Project.ViewModels
{
public class CurrenciesClient
{
private string base_Url = "http://localhost:51646/api/";
public IEnumerable<Currencies> findAll()
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(base_Url);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("currencies").Result;
if (response.IsSuccessStatusCode)
{
var resposeData = response.Content.ReadAsStringAsync().Result;
var Currency = JsonConvert.DeserializeObject<List<Currencies>>(resposeData);
return Currency;
}
return null;
}
catch
{
return null;
}
}
}
}
Index View
model Project.ViewModels.Currencies
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("Index", "Currency", FormMethod.Post))
{
#Html.TextBoxFor(m => m.ConversionRate, new { #size = "5" })
#Html.DropDownListFor(m => m.FromCurrencyId, Model.FromCurrencies as IEnumerable<SelectListItem>)
#Html.DropDownListFor(m => m.ToCurrencyId, Model.ToCurrencies as IEnumerable<SelectListItem>)
<button type="submit" class="btn btn-primary">Convert</button>
}
This problem is becuase you are passing null value from your dropdown.Means you are not selecting any value. Check that if you will pass some value from dropdown it will work fine.To solve this problem you need to add the same
code
Currencies model = new Currencies();
model.FromCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
model.ToCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
in your controller index post method.Because if selectListitem would be null the following code will be executed
IEnumerable<SelectListItem> selectList = o as IEnumerable<SelectListItem>;
if (selectList == null)
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
MvcResources.HtmlHelper_WrongSelectDataType,
name, o.GetType().FullName, "IEnumerable<SelectListItem>"));
}
Which will throw exception.
(It would be better if you will use
ViewBag.FromCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
like this.)
The better description is given here:
The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'
The whole explanation is also given in this link like how does this code work.
you will have to set the Dropdown data in the post controller as well, otherwise it will not be able to find the ViewBag values, as a result when after post action it calls the Index view, the ViewBag.FromCurrencies and ViewBag.ToCurrencies will be null which is obviously that we don't want.
For fixing the error, you will have to change you post action to be like:
[HttpPost]
public ActionResult Index(Currencies cur)
{
if (ModelState.IsValid)
{
if (cur.FromCurrencyId == cur.ToCurrencyId)
{
//do something if same currecnies and return.
ModelState.AddModelError("CurrencyCountry", "Can't make the conversion for the same value");
}
else
{
some code .....
}
}
CurrenciesClient Cur = new CurrenciesClient();
var listCurrency = Cur.findAll().ToList();
Currencies model = new Currencies();
model.FromCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
model.ToCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
return View(cur);
}
You should not return the view from your POST action or you will run into many issues. Here is the problem with that:
When you submit the form the URL is pointing to your Index. The body of your http post will have a bunch of Currencies items in it. Therefore, MVC, will submit the form to your Index method with Currencies cur parameter.
If all is well you return the same view.
If you refresh the page, your browser will simply reissue the last request and guess what, it will submit the form again. But this is not what you intended by refreshing. You wanted to get the form as it was originally presented not resubmit it.
Therefore instead of returning a view from a POST, you should always, except if AJAX was used, return a redirect.
In this case if all goes well, you may want to send the user to a success page or some other page so you should do this:
return RedirectToAction("YourActionName", "YourControllerName");
This pattern is called the PRG pattern. What this does is this:
user submits a form
If all goes well on the server side, you tell the browser to issue another request and get another page.
The browser gets the other page which may be a success page.
Now the user is on the success page. If they hit refresh they will get the success page again. They will not be submitting the same form over and over.
I have populated a dropdown list with values from Database Table. The list gets populated with correct table data but all values have ZERO index in the list. Here is the code to fill dropdown list:
//Get
public ActionResult NewBooking()
{
var db = new VirtualTicketsDBEntities2();
IEnumerable<SelectListItem> items = db.Attractions
.ToList()
.Select(c => new SelectListItem
{
Value = c.A_ID.ToString(),
Text = c.Name
});
ViewBag.Attractions = items;
return View();
}
And on Dropdown View Page:
<div class="editor-label">
#Html.LabelFor(model => model.Attraction)
</div>
<div class="editor-field">
#Html.DropDownList("Attractions")
</div>
For example if table have 3 values A,B, and C. These values are appearing in dropdown list but when I get its selected index in POST request function, it always returns ZERO. Here is the POST submit function:
//Post
[HttpPost]
public ActionResult NewBooking(BookingView booking)
{
try
{
BookingManager bookingManagerObj = new BookingManager();
bookingManagerObj.Add(booking);
ViewBag.BookingSavedSucess = "Booking saved!";
return View("WelcomeConsumer","Home");
}
catch
{
return View(booking);
}
}
booking.Attraction is always ZERO even user selected greater than ZERO index item.
Any suggestions?
I would guess that it is because you are getting a collection of SelectListItems back and not an actual SelectList. Try something like:
<div class="editor-field">
#Html.DropDownListFor(model => model.Attraction, new SelectList(ViewBag.Attractions, "Value", "Text");
It's best not to use ViewBag, you should always use a ViewModel.
Say you have a ViewModel like this:
public class AttractionViewModel
{
public int AttractionId { get; set; }
public SelectList Attractions { get; set; }
}
and modify your view like this - I presume you already have a form in there, the relevant bit is the #Html.DropDownListFor(...) and making sure you have the full namespace to the ViewModel if you haven't already included it in the Views web.config file:
#model AttractionViewModel
#using(Html.BeginForm("NewBooking", "ControllerName"))
{
<div class="editor-label">
#Html.LabelFor(model => model.AttractionId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.AttractionId, Model.Attractions)
</div>
<input type="submit" value="Submit">
}
and modify your HttpGet like this:
//Get
public ActionResult NewBooking()
{
var db = new VirtualTicketsDBEntities2();
var items = db.Attractions.ToList();
var attractionIdDefault = 0;// default value if you have one
var vm = new AttractionViewModel {
AttractionId = attractionIdDefault,// set this if you have a default value
Attractions = new SelectList(items, "A_ID", "Name", attractionIdDefault)
}
return View(vm);
}
and create an HttpPost ActionResult like this:
// Post
public ActionResult NewBooking(AttractionViewModel vm)
{
var attractionId = vm.AttractionId; // You have passed back your selected attraction Id.
return View();
}
Then it should work.
I know that you have already selected your answer but here is an alternative way of doing what you did. When I started off with ASP.NET MVC I struggled with SelectListItem and found another way of populating my drop down list. I have stuck to this way ever since.
I always have a view model that I bind to my view. I never send through a domain model, always a view model. A view model is just a scaled down version of your domain model and can contain data from multiple domain models.
I have made some modifications to your code and tips, but like I mentioned, it's just an alternative to what you already have.
Your domain model could look like this. Try and give your property names some meaningful descriptions:
public class Attraction
{
public int Id { get; set; }
public string Name { get; set; }
}
You view model could look something like this:
public class BookingViewModel
{
public int AttractionId { get; set; }
public IEnumerable<Attraction> Attractions { get; set; }
// Add your other properties here
}
Do not have your data access methods in your controllers, rather have a service layer or repository expose this functionality:
public class BookingController : Controller
{
private readonly IAttractionRepository attractionRepository;
public BookingController(IAttractionRepository attractionRepository)
{
this.attractionRepository = attractionRepository;
}
public ActionResult NewBooking()
{
BookingViewModel viewModel = new BookingViewModel
{
Attractions = attractionRepository.GetAll()
};
return View(viewModel);
}
[HttpPost]
public ActionResult NewBooking(BookingViewModel viewModel)
{
// Check for null viewModel
if (!ModelState.IsValid)
{
viewModel.Attractions = attractionRepository.GetAll();
return View(viewModel);
}
// Do whatever else you need to do here
}
}
And then your view will populate your drop down like this:
#model YourProject.ViewModels.Attractionss.BookingViewModel
#Html.DropDownListFor(
x => x.AttractionId,
new SelectList(Model.Attractions, "Id", "Name", Model.AttractionId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.AttractionId)
I hope this helps.
Controller
public ActionResult Create()
{
return View(new PageViewModel());
}
[HttpPost]
public ActionResult Create(Page page)
{
try
{
repPage.Add(page);
repPage.Save();
return RedirectToAction("Edit");
}
catch
{
return View(new PageViewModel());
}
}
PageViewModel
public class PageViewModel
{
public Page Page { get; set; }
public List<Template> Templates { get; set; }
private TemplateRepository repTemplates = new TemplateRepository();
public PageViewModel()
{
Page = new Page();
Templates = repTemplates.GetAllTemplates().ToList();
}
}
Parts of my View
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Website.Models.PageViewModel>" %>
<%= Html.TextBoxFor(model => model.Page.Name, new { #style = "width:300px;" })%>
<%= Html.DropDownListFor(model => model.Page.Template, new SelectList(Model.Templates, "ID", "Name"), new { #style = "width:306px;" })%>
Template:
ID
Name
Page:
ID
Name
TemplateID
My dropdownlist is populated correctly in the view, no problems there. My problem is that I dont get the selected value from the dropdownlist.
In my controller I i put a breakpoint in Edit and see that the Name textbox is populated with the value I type into it. But the selected from the dropdownlist is set to null.
alt text http://www.mgmweb.no/images/debug.jpg
Am I missing something, I thought it should set the correct Template value into the Page object. What am I doing wrong?
Try something like this maybe?
The key in the collection is the name of the dropdownlist control...
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
try
{
string selectedvalue = collection["Template"];
return RedirectToAction("Edit");
}
catch
{
return View(new PageViewModel());
}
}
The only thing that you get back from the web page is the id of the selected template. The default model binder doesn't know how to take this id and retrieve the correct template object from your repository. To do this you would need to implement a custom model binder that is able to retrieve the values from the database, construct a Template object, and assign it to the Page. Or... you could do this manually in the action given that, according to your comments elsewhere, you know how to get the template's id from the posted values.
Ok, I did like this:
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
Page page = new Page();
page.Name = collection["Page.Name"];
page.TemplateID = int.Parse(collection["Page.Template"]);
page.Created = DateTime.Now;
repPage.Add(page);
repPage.Save();
return RedirectToAction("Edit");
}
catch
{
return View(new PageViewModel());
}
}
And it works good, I just wanted to know if there is a better way to to this without manually getting the values from the collection.
But I guess it is not possible without making your own model binder as tvanfosson said.
Thank you everyone.
for model binding, use in the ActionResult:
partial ActionResult(FormCollection form)
{
Page page = new Page();
UpdateModel(page);
return view(page);
}
your class:
public class Page
{
public string Name {get; set;}
public int Template {get; set;}
public DateTime Created {get; set;}
public Page()
{
this.Created = DateTime.Now;
}
}
attribute names in your class should be equal to the name of the fields of view