MVC3 project.
I have several classes: Account, Address, Phone etc. which I set up in a view model
namespace ViewModels
{
public class AccountVM
{
public Account Account { get; set; }
public Address Address { get; set; }
public Phone Phone { get; set; } }
In the controller GET action I just call the view
public ActionResult Create()
{ return View(); }
In the View I pass the View Model
#model AccountVM
I then use #Html.EditorFor's to populate all the fields and successfully pass it to the POST Action and create the records in the db. So all that code is working.
#Html.EditorFor(z => z.Account.Number)
The problem arises when I try and pre-populate some of the properties. I do the following in the GET action.
public ActionResult Create()
{ var viewModel = new AccountVM();
viewModel.Account.Number = 1000000;
return View(viewModel); }
The code passes Intellisense but when I run I get the "NullReferenceException was unhandled by user code - Object reference not set to an instance of an object" error.
I get the same error if I try and populate using code in the View.
#{ Model.Account.Number = 1000000; }
I need to be able to programatically populate properties in both the controller and the View. I've read several SO posts on how to populate a view model in the controller and modeled my code on them but for some reason my code is not working. What am I'm doing wrong here? How should I go about it in both the Controller and the View? I get that the objects are null when created but can't figure out how to get around that.
Thanks
You've instantiated the VM, but not its Account property... try this:
public ActionResult Create()
{
var viewModel = new AccountVM();
viewModel.Account = new Account();
viewModel.Account.Number = 1000000;
return View(viewModel);
}
The same goes for the view:
#{
if (Model.Account == null) {
Model.Account = new Account();
}
Model.Account.Number = 1000000;
}
Though there are few times that this probably belongs in the view. It looks like something that should be set in the controller instead.
Related
I'm trying to do that:
Create a Model, add it on a session and send it to the view.
Change Model fields on my view
Get the Model from session updated on my controller
The problem is that my model is never updated when I'm changing values on textboxes, I'm sure that I'm missing something with razor,
View:
#model MvcTestApp.Models.Car
<div class="b1">
<div class="b2">#Html.EditorFor(e => e.KM)</div>
<div class="b2">#Html.EditorFor(e => e.RegistrationNumber)</div>
</div>
#Html.ActionLink("Car", "sendCar")
Controller:
On SendCar, I would like to get the model updated.
namespace MvcTestApp.Controllers
{
public class CarController : Controller
{
public ActionResult Show()
{
var model = new MvcTestApp.Models.Car()
{
RegistrationNumber ="12345",
KM = "12345"
};
Session["temp"] = model;
return View("Show",Session["temp"]);
}
public ActionResult sendCar()
{
return View("Show", Session["temp"]);
}
}
}
Model:
namespace MvcTestApp.Models
{
public class Car
{
[DataType(DataType.Text)]
public string KM { get; set;}
[DataType(DataType.Text)]
public string RegistrationNumber { get; set;}
}
}
You need to make your sendCar controller to update the model. Currently, all the changes you do will only persist locally until you navigate away from the page. You need to post the changed model back to the server.
Take a look at the "Handling edits" part of this example to see how it can be done:
Asp.net tutorials
The way to do this is by wrapping your model details in a form with a submit function. Then in your sendCar method take in a Car object and the model binding will take care of setting everything on the new object.
If you're wanting to persist this (I assume this is just for testing purposes?) then perhaps make your car that you're returning in your show method a class variable.
You should read a beginner tutorial about ASP.NET MVC, which will explain you how to send data from a form to a controller, as it seems you are absolutely not aware of how to do this.
You are not missing 'something', you are missing all about sending data from forms to controllers.
I have a constants values such as "Required","Optional", and "Hidden". I want this to bind in the dropdownlist. So far on what I've done is the below code, this is coded in the view. What is the best way to bind the constant values to the dropdownlist? I want to implement this in the controller and call it in the view.
#{
var dropdownList = new List<KeyValuePair<int, string>> { new KeyValuePair<int, string>(0, "Required"), new KeyValuePair<int, string>(1, "Optional"), new KeyValuePair<int, string>(2, "Hidden") };
var selectList = new SelectList(dropdownList, "key", "value", 0);
}
Bind the selectList in the Dropdownlist
#Html.DropDownListFor(model => model.EM_ReqTitle, selectList)
Judging by the property EM_RegTitle I'm guessing that the model you're using is auto-generated from a database in some way. Maybe Entity Framework? If this is the case, then you should be able to create a partial class in the same namespace as your ORM/Entity Framework entities and add extra properties. Something like:
public partial class MyModel
{
public SelectList MyConstantValues { get; set; }
}
You can then pass your SelectList with the rest of the model.
There are usually hangups from using ORM/EF entities through every layer in your MVC app and although it looks easy in code examples online, I would recommend creating your own View Model classes and using something like AutoMapper to fill these views. This way you're only passing the data that the views need and you avoid passing the DB row, which could contain other sensitive information that you do not want the user to view or change.
You can also move the logic to generate your static value Select Lists into your domain model, or into a service class to help keep reduce the amount of code and clutter in the controllers.
Hope this helps you in some way!
Example...
Your View Model (put this in your "Model" dir):
public class MyViewModel
{
public SelectList RegTitleSelectList { get; set; }
public int RegTitle { get; set; }
}
Your Controller (goes in the "Controllers" dir):
public class SimpleController : Controller
{
MyViewModel model = new MyViewModel();
model.RegTitle = myEfModelLoadedFromTheDb.EM_RegTitle;
model.RegTitleSelectList = // Code goes here to populate the select list.
return View(model);
}
Now right click the SimpleController class name in your editor and select "Add View...".
Create a new view, tick strongly typed and select your MyViewModel class as the model class.
Now edit the view and do something similar to what you were doing earlier in your code. You'll notice there should now be a #model line at the top of your view. This indicates that your view is a strongly typed view and uses the MyViewModel model.
If you get stuck, there are plenty of examples online to getting to basics with MVC and Strongly Typed Views.
You would prefer view model and populate it with data in controller.
class MyViewModel
{
public string ReqTitle { get; set; }
public SelectList SelectListItems { get; set; }
}
Then you can use:
#Html.DropDownListFor(model => model.EM_ReqTitle, model.SelectListItems)
I am using MVC3. I'm binding the dropdown with the Data coming from a service. But after the page posts back and a filter applies to list, the dropdown shows the filter record value in the grid because I always bind the list coming from the service.
However, I want the dropdown to always show all the Records in the database.
I don't understand your question that clearly. But it seems that it is a dropdown that you have on your view? I also have no idea what you are trying to bind so I created my own, but have a look at my code and modify it to fit in with your scenario.
In your view:
#model YourProject.ViewModels.YourViewModel
On the view there is a list of banks in a dropdown list.
Your banks dropdown:
<td><b>Bank:</b></td>
<td>
#Html.DropDownListFor(
x => x.BankId,
new SelectList(Model.Banks, "Id", "Name", Model.BankId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.BankId)
</td>
Your view model that will be returned to the view:
public class YourViewModel
{
// Partial class
public int BankId { get; set; }
public IEnumerable<Bank> Banks { get; set; }
}
Your create action method:
public ActionResult Create()
{
YourViewModel viewModel = new YourViewModel
{
// Get all the banks from the database
Banks = bankService.FindAll().Where(x => x.IsActive)
}
// Return the view model to the view
// Always use a view model for your data
return View(viewModel);
}
[HttpPost]
public ActionResult Create(YourViewModel viewModel)
{
if (!ModelState.IsValid)
{
// If there is an error, rebind the dropdown.
// The item that was selected will still be there.
viewModel.Banks = bankService.FindAll().Where(x => x.IsActive);
return View(viewModel);
}
// If you browse the values of viewModel you will see that BankId will have the
// value (unique identifier of bank) already set. Now that you have this value
// you can do with it whatever you like.
}
Your bank class:
public class Bank
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
This is simple as it gets. I hope this helps :)
PS: Please remember with future posts, always give as much detail as possible so that we can help you better. Also don't forget to display code samples so that we can see what you have already done. The more details that we can have the better.
When you post the model back to the create[Http Post] action is it not possible to have the list of dropdown list values for the banks binded back to the model. I see that if the model is invalid, you call the code
viewModel.Banks = bankService.FindAll().Where(x => x.IsActive);
to get a list of all the banks again which I assume you need to hit the database again.
Thanks
I have an action that creates a List and returns it to my view..
public ActionResult GetCustomers()
{
return PartialView("~/Views/Shared/DisplayTemplates/Customers.cshtml", UserQueries.GetCustomers(SiteInfo.Current.Id));
}
And in the "~/Views/Shared/DisplayTemplates/Customers.cshtml" view I have the following:
#model IEnumerable<FishEye.Models.CustomerModel>
#Html.DisplayForModel("Customer")
Then I have in the "~/Views/Shared/DisplayTemplates/Customer.cshtml" view:
#model FishEye.Models.CustomerModel
#Model.Profile.FirstName
I am getting the error:
The model item passed into the dictionary is of type System.Collections.Generic.List`1[Models.CustomerModel]', but this dictionary requires a model item of type 'Models.CustomerModel'.
Shouldn't it display the Customer.cshtml for every item in the collection in the Customers.cshtml?
Help!
I am not sure why you are calling a partial view like this. If it is a Customer Specific view, why not put it under Views/Customer folder ? Remember ASP.NET MVC is more of Conventions. so i would always stick with the conventions (unless abosultely necessary to configure myself) to keep it simple.
To handle this situation, i would do it in this way,
a Customer and CustomerList model/Videmodel
public class CustomerList
{
public List<Customer> Customers { get; set; }
//Other Properties as you wish also
}
public class Customer
{
public string Name { get; set; }
}
And in the action method, i would return an object of CustomerList class
CustomerList customerList = new CustomerList();
customerList.Customers = new List<Customer>();
customerList.Customers.Add(new Customer { Name = "Malibu" });
// you may replace the above manual adding with a db call.
return View("CustomerList", customerList);
Now there should be a view called CustomerList.cshtml under Views/YourControllerName/ folder. That view should look like this
#model CustomerList
<p>List of Customers</p>
#Html.DisplayFor(x=>x.Customers)
Have a view called Customer.cshtml under Views/Shared/DisplayTemplates with this content
#model Customer
<h2>#Model.Name</h2>
This will give you the desired output.
Your view is expecting a single model:
#model FishEye.Models.CustomerModel // <--- Just one of me
You're passing it an anonymous List:
... , UserQueries.GetCustomers(SiteInfo.Current.Id) // <--- Many of me
You should change your view to accept the List or determine which item in the list is supposed to be used before passing it into the View. Keep in mind, a list with 1 item is still a list and the View is not allowed to guess.
Can I return List to my View from my Controller, or do I need to wrap my List in another class, just for the sake of returning only a class?
If this is possible, how do I iterate over the list? I'm trying this (Razor), but Visual Studio isn't happy about it:
#model List<QueueItem>
.
.
.
#foreach (item in #Model)
You can do it that way, but I never return my domain objects directly to a view. Normally I have a view model for a view containing only the fields that I need on that view.
Given your scenario I would have this list in a view model:
public class MyViewModel
{
public IEnumerable<QueueItem> QueueItems { get; set; }
}
In your action method you will populate these items from a service/repository call and then this view model would be returned to the view:
public ActionResult List()
{
MyViewModel viewModel = new MyViewModel
{
QueueItems = queueItemRepository.GetAllQueueItems()
};
return View(viewModel);
}
In your view you would loop through the items and do what needs to be done:
#foreach (var item in Model.QueueItems)
{
}
I hope this helps.