I am trying to include a list of Clients in a drop down box. I am including this list in a form (the Html.BeginForm()) so that I can pass the selected value to my POST controller. I think I am missing something, I have the following classes:
my Invoice ViewModel:
public class InvoiceViewModel
{
public InvoiceViewModel()
{
// makes sure InvoiceItems is not null after construction
InvoiceItems = new List<PrelimInvoice>();
}
public List<PrelimInvoice> InvoiceItems { get; set; }
public List<Client> ClientId { get; set; }
public Client Client { get; set; }
public decimal InvoiceTotal { get; set; }
}
My Client Model:
public class Client
{
public string ClientId { get; set; }
public string Name { get; set; }
}
My SaveInvoice method:
public ActionResult SaveInvoice()
{
var invoice = new Invoice();
TryUpdateModel(invoice);
try
{
invoice.ClientId = User.Identity.Name;
invoice.DateCreated = DateTime.Now;
//Save invoice
proent.Invoices.Add(invoice);
proent.SaveChanges();
//Process the invoice
var preliminvoice = InvoiceLogic.GetInvoice(this.HttpContext);
preliminvoice.CreateInvoice(invoice);
return RedirectToAction("Complete", new { id = invoice.InvoiceId });
}
catch
{
//Invalid - redisplay with errors
return View(invoice);
}
}
And my Index.cshtml is strongly typed to the InvoiceViewModel class.
Index.cshtml is where I generate the form.
I am not sure of the code for creating the Html.DropDownList, and whether or not I need to include a List or something of my Clients. I have dropdownlists in other places but they are strongly typed to models, not viewmodels, hence my confusion.
Can anyone assist me?
Start by adding to your ViewModel the following 2 properties:
SelectedClientId: which stores the selected value
ClientItems: stores the collection of SelectListItems which populates your drop down.
E.G.
public class ClientViewModel
{
public List<Client> Clients;
public int SelectedClientId { get; set; } // from point 1 above
public IEnumerable<SelectListItem> ClientItems // point 2 above
{
get { return new SelectList(Clients, "Id", "Name");}
}
}
Then on your View index.cshtml you would add the following:
#model ClientViewModel
#Html.DropDownListFor(m => m.SelectedClientId, Model.ClientItems)
Related
I'm building a website in ASP.Net, using MVC, and need to list a set of results
but i get error in the code
model:
public class Customers
{
public int Id { get; set; }
public string Name { get; set; }
public List<Customers> Itemlst { get; set; }
}
controller:
public ActionResult List()
{
Customers itemobj = new Customers();
return View(itemobj);
}
view:
#foreach(var item in Model.Itemlst)
{
<tr>
<td>Items ID:</td>
<td>#item.ID</td>
<td>Items Name:</td>
<td>#item.Name</td>
</tr>
}
</table>
From the NullReferenceException that you are receiving we can see that the issue is because of the Itemlst not being initialised. One of the ways to solve this is just to make sure that there is a valid list when you create the object:
public class Customers
{
public Customers()
{
Itemlst = new List<Customers>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Customers> Itemlst { get; set; }
}
So you can add values to the list in your action if need:
public ActionResult List()
{
Customers itemobj = new Customers();
var example = new Customers ();
example.Id = 1;
example.Name = "Example";
itemobj.Add();
return View(itemobj);
}
I don't know if you are just using this as an example for your question, but I can't help but notice that there is something weird. You could use something different like:
public class ViewModel // Name to what makes sense to you
{
// Some other properties...
public List<Customer> Customers { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
Or you could just use List<Customer> as your model in the view directly (yes, your model can be a object which is simply a list of objects).
When you pass the Customers list to the view, this list itself is the model.
Change Model.Itemlst —> Model inside the foreach loop.
This will iterate the list of customers.
My Model class is below:
I have three classes two of them are partial class and one is simple class.......
[MetadataType(typeof(RegistrationMetaData))]
public partial class Registration
{
}
public class RegistrationMetaData
{
public string Id { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public virtual ICollection<Images> Images { get; set; }
}
[MetadataType(typeof(ImagesMetaData))]
public partial class Images
{
}
public class ImagesMetaData
{
public string id { get; set; }
public string stuid { get; set; }
public string stuimg1 { get; set; }
public virtual ICollection<Registration> Registrations { get; set; }
}
public class EmployeeViewModel
{
public string Name { get; set; }
public string stuimg1 { get; set; }
}
public class NotificationViewModel
{
public Registration registration { get; set; }
public Notification notification { get; set; }
public IEnumerable<EmployeeViewModel> EmployeeViewModel { get; set; }
public Images images { get; set; }
}
Then I have used the below code in controller class to fetch Images record with foreign key in registration table.
IEnumerable<EmployeeViewModel> model1 = null;
model1 = (from e in db.Registrations
join j in db.Images on e.Id equals j.stuid
where e.Email == Email
select new EmployeeViewModel
{
Name = e.Name,
stuimg1 = j.stuimg1
}).ToList();
var mixmodel = new NotificationViewModel
{
EmployeeViewModel = model1
};
return View(mixmodel);
Atlast my view page is like this:-
#model IEnumerable<Amar.Models.NotificationViewModel>
#foreach (var item in Model)
{
#item.EmployeeViewModel.stuimg1
}
But I am getting an error
System.Collections.Generic.IEnumerable' does not contain a definition for 'stuimg1' and no extension method 'stuimg1' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found (are you missing a using directive or an assembly reference?)
I have gone through debugging my code is fine till controller page...but from view page the values are not showing.I think there is some little mistake i have made...
Please someone help me..I am trying to solve this problem since 2 weeks....
I want to fetch data from one more class on the same view page thats why I am using NotificationViewModel class.
return View(mixmodel);
Your view is expecting a type of IEnumerable<NotificationViewModel> but mixmodel is just a NotificationViewModel
I'm not seeing what you are achieving by having this additional class 'NotificationViewModel'. If your view were to be changed to expect an IEnumerable<EmployeeViewModal> you could pass in model1 directly.
You could then change your view to:
#foreach (var item in Model)
{
#item.stuimg1
}
If you do indeed need this extra layer of abstraction for some other part of your view then you need to sit and think about what is a a single instance and what is a list. Try drawing it if you're having trouble.
Hope someone can help - this has been bugging me for around 2 hours - its probably something simple :)
Kendo UI Grid sends a request to my controller
http://localhost:1418/user/update?UserID=1&UserName=Admin&RoleName=Admin&Email=c.j.hannon%40gmail.com&Active=true&Company%5BCompanyID%5D=1&Company%5BCompanyName%5D=asd
However, the controller class 'Company' isnt bound by the binder? Can any one help my view model and controller action signature are below:
[HttpGet]
public JsonResult Update(UserViewModel model)
{
svcUser.UpdateUser(new UpdateUserRequest() {
UserID=model.UserID,
RoleID = model.RoleName,
Email = model.Email,
Active = model.Active.GetValueOrDefault(false),
UserName = model.UserName
});
return Json("", JsonRequestBehavior.AllowGet);
}
public class UserViewModel
{
public int UserID { get; set; }
public string UserName { get; set; }
public string RoleName { get; set; }
public string Email { get; set; }
public bool? Active { get; set; }
public CompanyViewModel Company { get; set; }
}
Cheers
Craig
A few things. Your immediate problem is that Company is mapped to a complex object not a primitive type. Kendo Grid just does not do this (as of this writing). Just guessing, but you probably want to setup a foreign key binding on the Grid and just pass back the Id of the company from a listbox. This is not as bad as you think and it will immediatly fix your problem and look nice too.
Maybe personal taste but seems to be a convention. Use the suffix ViewModel for the model that is bound to your View and just the suffix Model for your business objects. So a Kendo Grid is always populated with a Model.
Ex.:
public class UserModel
{
public int UserID { get; set; }
public string UserName { get; set; }
public string RoleName { get; set; }
public string Email { get; set; }
public bool? Active { get; set; }
public int CompanyID { get; set; }
}
public class CompanyModel
{
public int ID { get; set; }
public string Name { get; set; }
}
public class UserViewModel
{
public UserModel UserModel { get; set; }
public IList<CompanyModel> Companies { get; set; }
}
public ActionResult UserEdit(string id)
{
var model = new UserViewModel();
model.UserModel = load...
model.Companies = load list...
return View(model);
}
#model UserViewModel
...
column.ForeignKey(fk => fk.CompanyId, Model.Companies, "ID", "Name")
(Razor Notation)
BUT! This is just an example, you are better off Ajax loading the Grid with the IList becuase I assume you have many Users in the Grid at once, though you could server bind off the ViewModel with a List too. But the list of Companies is probably the same every time, so map it to the View just liek this rather than Ajax load it every time you do a row edit. (not always true)
I have a question abou view models and adding information to a database.
Let's say i have these two classes:
public class Ad {
public int Id { get; set; }
public int CategoryId { get; set; }
public string Headline { get; set; }
public string Text { get; set; }
public int Type { get; set; }
public Category Category { get; set; }
}
public class Category {
public int CategoryId { get; set; }
public int CategoryName { get; set; }
public IColletion<Ad> Ads { get; set; }
}
Context class:
public DbSet<Ad> Ads { get; set; }
public DbSet<Category> Categories { get; set; }
The models are really over simpified but i just want to get a grasp of the context. Lets say i want to create a view model for the view that are suppose to add entries to the db. How do i go about adding info to the "Ads" database table from a view model. Lets say the view model looks something like:
namespace Website.Models
{
public class CreateViewModel
{
public Ad Ad { get; set; }
public ICollection<Categories> Categories { get; set; }
public Dictionary<int, string> AdTypes { get; set; }
public CreateViewModel()
{
// to populate a dropdown on the "Create" page
this.Adtypes= new Dictionary<int, string>
{
{1, "For sale"},
{2, "Want to buy"},
{3, "Want to trade"},
{4, "Have to offer"}
};
}
}
}
The only thing i really need when adding to the db is the parameters in the Ad class (although i need the view model to render the dropdowns). But how do I extract this from the CreateViewModel to add to the db.
This is my code at the moment:
[HttpPost]
public ActionResult Create(Ad ad)
{
if (ModelState.IsValid)
{
db.Ads.Add(ad);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(ad);
Since this is expecting a Ad class, how do i extract only the Ad paramaters from the view model and insert it to the db.
Sorry, very long post and probably some serious newbie stuff. I just didn't know how to explain it better.
I would appreciate if someone could explain about view models, or direct me to some site that does.
/m
You can use Viewmodels when you need more data on the website like values for dropdowns. So lets say you want to create a car.
Car object (Car.cs)
public class Car
{
public int Id {get;set;}
public string Color {get;set;}
public string Name {get;set;}
}
But you don't want to type color by yourself in a textbox. Let's say you want to pick color from dropdown. If so you need to add somehow list (SelectList) of colors to a dropdown.
Viewmodel is helpful in this situation (CreateCarViewModel.cs)
public CreateCarViewModel
{
public Car Car {get;set;}
public SelectList Colors{ get; set; } //List of colors for dropdown
}
Controller
ActionResult CreateCar()
{
CreateCarViewModel CCVM = new CreateCarViewModel();
List<string> colors = new List<string>{"Black","White"};
CCVM.Colors = new SelectList(colors);
//Your view is expecting CreateCarViewModel object so you have to pass it
return View(CCVM);
}
CreateCar (CreateCar.cshtml)
#model YourSolutionName.ModelsFolder.CreateCarViewModel
//form etc.
{
#Html.DropDownListFor(x => x.Car.Color, Model.Colors)
#Html.TextBoxFor(x => x.Car.Name)
}
Controller Again
[HttpPost]
//Again: but now controller expects CreateCarViewModel
ActionResult CreateCar(CreateCarViewModel CCVM)
{
if (ModelState.IsValid)
//update database with CCVM.Car object and redirect to some action or whatever you want to do
else
{
//populate your colors list again
List<string> colors = new List<string>{"Black","White"};
CCVM.Colors = new SelectList(colors);
return View (CCVM);
}
}
I've been looking into view models for mvc and I'm looking for the best way to do them. I've read loads of different articles but none seem to be clear as the "best way." So far example I might have a Customer model with the following properties:
First Name
Last Name
Title
Location
Where location is a foreign key to a location table in the database.
I want to be able to edit this customer but only the first name, last name and location. I'm not bothered about the title in the edit. So in my view I will need to pass a customer and a selected list.
Now from what I've read I have the following options (there's probably many more).
So my question is basically which is the best one?
1)
Add a select list to the ViewData["Location"] and just create a strongly typed view of customer?
2)
Create a view model where I pass a customer and select list (the data access is done in the controller):
public class ViewModelTest
{
public Customer Customer { get; set; }
public SelectList Locations { get; set; }
public ViewModelTest(Customer customer, SelectList locations)
{
Customer = customer;
Locations = locations;
}
}
3)
Create a view model where I pass a customer and list of locations and create the select list in the view model.
public class ViewModelTest
{
public Customer Customer { get; set; }
public SelectList Locations { get; set; }
public ViewModelTest(Customer customer, List<Location> locations, string selectedLocation)
{
Customer = customer;
Locations = new SelectList(locations, "LocationID", "LocationName", selectedLocation);
}
}
4)
Pass a customer and repository and do the data access in the view model.
public class ViewModelTest
{
public Customer Customer { get; set; }
public SelectList Locations { get; set; }
public ViewModelTest(Customer customer, IRepository repository, string selectedLocation)
{
Customer = customer;
Locations = new SelectList(repository.GetLocations(), "LocationID", "LocationName", selectedLocation);
}
}
5)
Create the view model with just the properties I need:
public class ViewModelTest
{
public string FirstName { get; set; }
public string LastName { get; set; }
public SelectList Locations { get; set; }
public ViewModelTest(Customer customer, SelectList locations)
{
FirstName = customer.FirstName;
LastName = customer.LastName ;
Locations = locations;
}
}
6)
Or some other combination of the above or another way.
All opinions welcome.
Here's what I may suggest: have a view model which reflects the fields of strongly typed view:
public class SomeViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Location { get; set; }
public IEnumerable<SelectListItem> PossibleLocations { get; set; }
}
And in your controller action populate this view model:
public ActionResult Index()
{
var customer = Repository.GetCustomer();
var locations = Repository.GetLocations();
var viewModel = new SomeViewModel
{
FirstName = customer.FirstName,
LastName = customer.LastName,
Location = customer.Location,
PossibleLocations = new SelectList(locations, "LocationID", "LocationName", customer.Location);
};
return View(viewModel);
}
[HttpPost]
public ActionResult Index(SomeViewModel viewModel)
{
// TODO: Handle the form submission
return View(viewModel);
}
Of course doing the mapping between the model and the view model manually as shown my example could become quite cumbersome and in this case I would recommend you looking at AutoMapper.
I'd have my ViewModel as this
public class SomeViewModel
{
public Customer Customer { get; set; }
public IEnumerable<Location> PossibleLocations { get; set; }
}
My controller like this:
public ActionResult Index()
{
var viewModel = new SomeViewModel
{
Customer = Repository.GetCustomer(),
PossibleLocations = Repository.GetLocations()
};
return View(viewModel);
}
and then you can access everything in your Customer object in the view like this:
Customer name - <%: Model.Customer.FirstName %> <%: Model.Customer.LastName %>
Location - <%: Html.DropDownList("LocationID", new SelectList(Model.PossibleLocations as IEnumerable, "LocationID", "LocationName", Model.Location.LocationID))%>