How to show data from two ViewModels in one View - c#

I would like to fill 2 divs in View with data from 2 ViewModels, but I have a problem.
My 2 viewModels:
public class ChatLogsNameTimeViewModel
{
public UserProfile UserProfile { get; set; }
public string Message { get; set; }
public DateTime Time { get; set; }
}
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public bool IsOnline { get; set; }
public virtual ICollection<ChatLogs> ChatLogs { get; set; }
}
Which means I want to show data from ChatLogsNameTimeViewModel in one div in View and data from UserProfile in other div in View.
This is my ViewModel that uses both viewModels above:
public class ChatLogsUsersViewModel
{
public IEnumerable<ChatLogsNameTimeViewModel> ChatLogs { get; set; }
public IEnumerable<UserProfile> Users { get; set; }
}
And this is my Index() action in controller:
var chatLogs = db.getChatLog().ToList();
var users = dba.getOnlineUsers().ToList();
var view = new ChatLogsUsersViewModel(chatLogs, users);
return View(view);
My problem is that I can not access to ViewModel attributes at all.
When I create foreach loop in view all I can access is this:
Which means I cannot access attributes at all to print them in foreach.
I have this in View:
#model IEnumerable<Chat.Models.ChatLogsUsersViewModel>
I assume that I am not doing something right in my controller. I have methods getChatLog() and getOnlineUsers() implemented in Model, they work alone no problem. I just don't know how to make them work together in one view.

You need to update the type of you view.
You are not passing the view a list of Chat.Models.ChatLogsUsersViewModel, you only have one and this model has two lists.
So update it to:
#model Chat.Models.ChatLogsUsersViewModel

Your model is strongly typed towards the wrong model. As Queti put it, your model should be typed #model Chat.Models.ChatLogsUsersViewModel.
As is, your model is attempting to access a collection of these models. You should find that if you do:
#for each (var x in Model) {
x.
}
x is then a single ChatLogsUsersViewModel and should display its properties in your dev environment. But again, this is not how you want to strongly type your model here.
If I'm not mistaken, this is what you are trying to do, and you can still access your data using a for each loop:
#model Chat.Models.ChatLogsUsersViewModel
for each (var log in Model._chatLogs) {
#<div>#log.Message</div>
}
...
for each (var user in Model._users) {
#<div>#user.UserName</div>
}

Related

MVC 5 Help Understanding ViewModel

Okay, so i have my ViewModel and I understand what the controller does, I'm just having difficulty implementing it. I don't know how to code a controller for the ViewModel, i've tried researching it myself and can't find anything.
Here is my viewModel, how would I go about constructing the controller? Not asking you to do it for me, just how to do it
public class ViewOrderViewModel
{
//From ORDER Table
public int OrderId { get; set; }
public System.DateTime OrderDate { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Email { get; set; }
public decimal Total { get; set; }
//from Products
public List<Product> Products { get; set; }
}
UPDATE
public class ViewOrderController : Controller
{
// GET: ViewOrder
public ActionResult ViewOrders()
{
var order = new Order();
var viewModel = GetViewModel(order);
return View(viewModel);
}
public ViewOrderViewModel GetViewModel(Order orderObject)
{
ViewOrderViewModel viewModel = new ViewOrderViewModel();
viewModel.OrderId = orderObject.OrderId;
viewModel.OrderDate = orderObject.OrderDate;
viewModel.FirstName = orderObject.FirstName;
viewModel.LastName = orderObject.LastName;
viewModel.City = orderObject.City;
viewModel.Address = orderObject.Address;
viewModel.Country = orderObject.Country;
viewModel.Email = orderObject.Email;
viewModel.PostalCode = orderObject.PostalCode;
viewModel.Total = orderObject.Total;
return viewModel;
}
}
Still unsure about how to map the List of products in the ViewModel class to the list of products in the db
Typically, your view is going to be "bound" to the ViewModel. It's like saying "Ok, I'm the view for an 'Order' and I only need to worry about the properties that you defined in ViewOrderViewModel".
The controller is not required for that binding to happen. The binding is declared at the top of your view:
Order.cshtml
#Model MyProject.Web.ViewModels.ViewOrderViewModel
<div>
<!-- Html for the view-->
</div>
This allows you to access properties on that model within the view. Razor has some functions that make life easy. For example, if you want to display the OrderId it might look like this:
<span>OrderId: #Model.OrderId </span>
The view doesn't care what values are set for each of those properties, it only cares that the properties exist. Where the controller comes into play is populating those properties with the values you want and then passing the ViewModel to the view:
public ActionResult Order()
{
var viewModel = new ViewOrderViewModel();
// Load data into each property
viewModel.OrderId = 123; // etc..
// Return it to the view. Asp.net knows to return
// it to the Order.cshtml view because the view
// and the controller action share the same name.
return View(viewModel);
}
Edit: In response to your questions in the comments: If you need to populate your ViewModel with values from a different model (such as a database model) you can create a mapper like so:
public ViewOrderViewModel GetViewModel(Order orderObject)
{
ViewOrderViewModel viewModel = new ViewOrderViewModel();
viewModel.OrderId = orderObject.OrderId;
viewModel.FirstName = orderObject.FirstName;
// etc...
return viewModel;
}
and then in your controller you would do something like this:
// var order = new Order()
var viewModel = GetViewModel(order);

How to use multiple models in a controller/view mvc?

I have two models; one holding the values of the fields that are displayed on the page and the other holding the required fields for that page depending on a user variable.(think of it as a combo box that for on each variable, different fields are rendered for the page). My question is what is the most efficient and manageable way to use those two models in a single view/controller? I tried to tuple them but I get that I need to create a parameter-less constructor error. Thank you.
As tarzanbappa said, one of the best approaches would be for you to add the extra fields in each ViewModel.
In order for you to not go into each ViewModel and add all the properties you need, you can add a variable instance of your other ViewModel.
For example: (Your ViewModels)
public class MyViewModel()
{
public T PropertyOne { get; set; }
public T PropertyTwo { get; set; }
public MyOtherViewModel PropertyThree { get; set; }
}
public class MyOtherViewModel()
{
public T PropertyOneCheck { get; set; }
public T PropertyTwoCheck { get; set; }
}
Then in your DataModel call, set your variable.
For Example: (LINQ)
...
PropertyThree = (from r in context.Table
where conditionIsMet
select new MyOtherViewModel
{
PropertyOneCheck = r.PropertyOneCheck,
PropertyTwoCheck = r.PropertyTwoCheck
}).FirstOrDefault();
...
And in your View You can toggle the visibility of fields as follows:
#if(Model.PropertyThree.PropertyOneCheck)
{
//Show Field
}else
{
//Hide Field
}
The best approach would be to have a view model designed specifically for the UI which, by the sounds of things, would be a hybrid of your two current models.
You can use DataAnnotations to add metadata to each property and then Validate your model e.g.
public class ViewModel
{
[Required]
public string PropertyOne { get; set; }
[Required]
public string PropertyTwo { get; set; }
}
...
var model = new ViewModel();
var results = new List<ValidationResult>();
if (!Validator.TryValidateObject(model, new ValidationContext(model), results)) {
Console.WriteLine("Model is not valid:");
foreach (var r in results) {
Console.WriteLine(r.ErrorMessage);
}
} else {
Console.WriteLine("Model is valid");
}
Live Example

MVC 4 - View inside a form

I'm new to MVC. I have this view model:
public class ABCView
{
public string Name { get; set; }
public List<orders> Order { get; set; }
public int Version { get; set; }
public string Message { get; set; }
}
I want a view where the top of the form will contain Name and Message. In the bottom, I need only TWO orders side-by-side. How can I achieve this for Create/Edit operations. Any links will be helpful, thanks.
I would simply pass this model to a view, then output using #Html.TextBoxFor Name and Message where you want them. On the bottom of the form have a foreach loop which goes through the List and outputs the orders.
Great, simple example:
http://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/examining-the-edit-methods-and-edit-view

Passing ViewModel - View to Controller When JavaScript disabled

It's difficult for me for developping an functionality without JavaScript..
I have a ViewModel :
public class AccountRegisterViewModel
{
#region Properties
public User User { get; set; }
public ExternalAccounts ExtAccounts { get; set; }
public LocalPassword Password { get; set; }
public Company CompanyARegister { get; set; }
public Company CompanyBRegister { get; set; }
public bool SameCompanies { get; set; }
public int NbCompanies { get; set; }
...
}
In view, i have a link with checkbox for copying the first company with the second
But I don't know how pass this viewModel (View to Controller) for keeping my data and return the same View with the copie of company..
i try this, in view :
#Html.ActionLink("Click", "CopyCompanies","Account", new { model = Model })
#Html.CheckBoxFor(model => model.SameCompanies)
In Controller :
[AllowAnonymous]
public ActionResult CopyCompanies(AccountRegisterViewModel model)
{
...
if (model.SameCompanies)
{
// copie
}else //clear
...
return View("Step2Register", model);
}
Any idea ?? Thank you for your help
If the CopyCompanies action method requires the AccountRegisterViewModel object, then you will need to provide it. Unfortunately, you will not be able to provide the value using the approach you are following when creating the link.
Your two options would be to have a hidden field for each property in AccountRegisterViewModel and then let the model binding create the object, but even this would not be ideal, since the viewModel is composed of complex objects, so you would have way too many hidden fields.
Your second option, which I think is a better approach, would be to pass in some kind of Id that corresponds to the AccountRegisterViewModel that CopyCompany can use to look up the values it would need.

Is it possible to validate an MVC-3 model without validating "sub-models"?

I have a class that requires another class to be specified, but I don't want the MVC ModelState validator to check whether the secondary model is valid. Is this possible?
Here's a brief overview:
My entities look something like this:
public class WidgetType
{
public long Id { get; private set; }
[Required]
public string Name { get; set; }
...
}
public class Widget
{
public long Id { get; private set; }
[Required]
public string Name { get; set; }
[Required]
public WidgetType WidgetType { get; set; }
...
}
I have them encapsulated in a WidgetViewModel class that I'm passing to/from the View like this:
public class WidgetViewModel
{
public Widget Widget { get; set; }
public ICollection<WidgetType> WidgetTypes
{
get
{
return _repository.GetWidgets();
}
}
...
}
My view looks something like this:
...
#Html.DropDownListFor( m => m.Widget.WidgetType.Id, new SelectList( new EquipmentViewModel().EquipmentTypes, "Id", "Name" ) )
...
All of this works except for validation. ModelState.IsValid is always false because "Widget.WidgetType.Name" is required. I need the user to select a WidgetType, but I don't want ModelState to be validated deeper than "Widget.WidgetType.Id" (which should be all that Widget needs for its foreign key?).
Is there a better way to do this? I feel like there should be some way to validate without recursively inspecting deeper into the properties, but I can't find it. What am I missing...?
public class WidgetViewModel
{
[Required]
public string Name { get; set; }
[Required]
public WidgetType WidgetTypeId { get; set; }
public SelectList WidgetTypes
{
get
{
//This should be popuplated in your controller or factory not in the view model
retun new SelectList{ _repository.GetWidgets(),"Id","Name");
}
}
}
In your view
#Html.DropDownListFor( m => m.WidgetTypeId, Model.WidgetTypes)
And in your controller
public ActionResult Create(WidgetViewModel model)
{
Widget widget = new Widget{
Name = model.Name,
WidgetType = yourManager.GetWidgetTypeByID(model.WigetTypeId);
};
yourManager.Create(widget);
//...
}
If all you need in your view is the WidgetID then you don't need to include the entire Widget in the WidgetViewModel. Just have property called WidgetID. View model classes should have only the data the is necessary for the view.
In the controller action method that is called when you submit the form, you can use the WidgetID to fetch the Widget object from the database if it is needed.
http://blog.stevensanderson.com/2010/02/19/partial-validation-in-aspnet-mvc-2/ gives an example of partial validation

Categories

Resources