How to pass multiple model in view in ASP.NET MVC? - c#

Problem is: I want to run 3 different actions but instead of that i want to fed all data from single action in a bigger model.
I am using:
public class SearchScrapClass
{
public WClass WClass { get; set; }
public SClass SClass { get; set; }
public YClass YClass { get; set; }
}
public class WClass
{
public string title { get; set; }
public string link { get; set; }
}
public class SClass
{
public string title { get; set; }
public string link { get; set; }
}
public class YClass
{
public string title { get; set; }
public string link { get; set; }
}
I am using LINQ to add data in these models.
I am using :
var wikians = from info in document.DocumentNode.SelectNodes("//div[#id='span']")
from link in info.SelectNodes("div//a").Where(x => x.Attributes.Contains("href"))
select new SearchScrapClass //Main Bigger Class
{
WClass.link= link.Attributes["href"].Value, //ERROR: How to add to WClass's url ?
WClass.title= link.InnerText //ERROR: How to add to WClass's url ?
}
var wikians = from info in document.DocumentNode.SelectNodes("//div[#id='results']")
from link in info.SelectNodes("p//a").Where(x => x.Attributes.Contains("href"))
select new SearchScrapClass //Main Bigger Class
{
YClass.link= link.Attributes["href"].Value, //ERROR: How to add to YClass's url ?
YClass.title= link.InnerText //ERROR: How to add to YClass's url ?
}
//Also for the 3rd class (model)
return View(wikians); //and then return bigger class model so that i can access them in view
This is one way i want to add data to link and title of all the classes.
My try is to add data to all 3 classes from different sources and pass the bigger model to view so that i can access all the classes as:
#model SearchScrapClass
#using(Html.BeginForm()) {
#Html.EditorFor(o => o.WClass.link)
...
}
Please suggest a way
Thanks

To Expand on my comment, I would suggest creating a ViewModel folder for organization sake. in this add the view model
public class SearchScrapClassViewModel
{
SearchScrapClass searchScrap;
WClass wClass;
SClass sClass;
YClass yClass;
}
In your controller then you instantiate the new viewmodel
SearchScrapClassViewModel model = new SearchScrapClassViewModel
{
....add in your logic to fill your class objects here
}
return view(model);
then in your view add the using for the viewmodel.
#using SearchScrapClassViewModel

You can pass multiple model by creating a new model class which will contain multiple objects.
public class MultiModel
{
SearchScrapClass searchScrap;
WClass wClass;
SClass sClass;
YClass yClass;
}

See the tuple tutorial http://www.dotnetperls.com/tuple or this one http://msdn.microsoft.com/en-us/library/system.tuple(v=vs.110).aspx
Like controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var first = new FirstModel();
var second = new SecondModel();
return View(Tuple.Create(first,second));
}
}
And the view:
#model Tuple
<div>
#Model.Item1.FirstModelProp
#Model.Item2.SecondModelProp
</div>

SearchScrapClassViewModel model = new SearchScrapClassViewModel
{
....add in your logic to fill your class objects here
}
what logic we apply here " ....add in your logic to fill your class objects here"

Related

How to use json data in MVC view .cshtml

I hope someone can help me:
My challenge is, that I have a web service returning a json.
The format is
{"stations":[{"name":"aname","free":false},{"name":"anothername","free":true}]}
so I have one object which is an array that hold n objects with n attributes....
Now for each object in that array of the stations object I would like to render the attributes, like
<p>stations[0].name</p>
I need to use this in mvc.
So I created a model
public station(){}
public string name {get; set;}
public boolean free {get; set;}
in my contorller I use a WebClient and now I need to handle the response.
I was thinking of IEnumerable but I don't know how to put this in the view?!
my goal is to understand how i can do something like
public Actionresult Stations(){
var stations = JObject.Load(reponse);
return View(Stations);
}
but I have no idea how to the handle each object of the array and get their values in the Stations.cshtml view using for each or similar....
Any idea?
There are many ways to do that, this is my way.
Model
Create a class in which your JSON will be deserialized to:
public class RootJson
{
public IEnumerable<station> Stations { get; set; }
}
The RootJson class has a property which will contain a list of station's instances (your class):
public class station
{
public string name { get; set; }
public bool free { get; set; }
}
Controller
Then, deserialize your JSON using:
var deserialized = JsonConvert.DeserializeObject<RootJson>(json);
And pass the stations to the view:
return View(deserialized.Stations);
View
In your view you have to specify the type of the data passed, in this case IEnumerable<station>. So, at the top of your Stations.cshtml add:
#model IEnumerable<station>
You can use a foreach to iterate over the model:
#foreach(var station in Model)
{
<p>#station.name</p>
}
Edit: Full code for clarification
Model
RootJson.cs
public class RootJson
{
public IEnumerable<station> Stations { get; set; }
}
station.cs
public class station
{
public string name { get; set; }
public bool free { get; set; }
}
Controller
Inside YourController.cs
public ActionResult Stations() {
string json = YourMethodToGetJsonAsString();
var deserialized = JsonConvert.DeserializeObject<RootJson>(json);
return View(deserialized.Stations);
}
View
Stations.cshtml
#model IEnumerable<station>
#foreach(var station in Model)
{
<p>#station.name</p>
}
One of simplest way is to use ViewBag like this:
public ActionResult Stations()
{
string jsonString = "{ \"stations\":[{\"name\":\"aname\",\"free\":false},{\"name\":\"anothername\",\"free\":true}]}";
ViewBag.stations = ((dynamic)Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString)).stations;
return View();
}
and inside cshtml for ex.
<p>#ViewBag.stations[0].name</p>
Model
public class Stations
{
public List<Station> Station { get; set; }
}
public class Station
{
public string Name { get; set; }
public bool Free { get; set; }
}
Controller
// Deserialising JSON
var station = JsonConvert.DeserializeObject<Stations>(response);
// Pass result to view
return View(station.Station);
View
At the top of your Stations.cshtml add:
#model IEnumerable<Station>
You can use a foreach to iterate over the model:
#foreach(var station in Model)
{
<p>#station.Name</p>
}

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 Pass Details Model from Controller to View

I am accessing Data in Controller using a WCF Service.
public ActionResult Index()
{
DataRerieveClient _proxy = new DataRerieveClient();
var orderDetails = _proxy.GetProductDetails(null);
return View();
}
Now how to pass the orderdetails from Controller to view and how to access them in View.
Edit:
I have a Model :
public class OrderDetails
{
public int OrderId { get; set; }
public int ProductId { get; set; }
public decimal UnitPrice { get; set; }
public int quanity { get; set; }
public decimal Discount { get; set; }
}
and _proxy.GetProductDetails(null) returns List<ServiceType.OrderDetails>
Do I need a Local Model at all in this scenario?
How do I display the List values in a table in my view?
Edit2:
public class AutoMapperConfig
{
public static void Configure()
{
Mapper.Map(ServiceOrders.OrderDetails, NorthWindMVCWCF.Models.OrderDetails);
}
}
Now getting the Error
'NorthWindMVCWCF.ServiceOrders.OrderDetails' is a 'type', which is not valid in the given context
'NorthWindMVCWCF.Models.OrderDetails' is a 'type', which is not valid in the given context
I prefer to create view models, I would do it as follows:
Create View Models
public class OrderDetailViewModel
{
public int OrderId { get; set; }
public int ProductId { get; set; }
public decimal UnitPrice { get; set; }
public int Quanity { get; set; }
public decimal Discount { get; set; }
}
public class OrderDetailsViewModel
{
public OrderDetailsViewModel()
{
OrderDetails = new List<OrderDetailsViewModel>();
}
public List<OrderDetailsViewModel> OrderDetails { get; set; }
}
Manual projection
You could create an OrderDetails view model and project an instance manually as follows:
var orderDetailsViewModel = new OrderDetailsViewModel();
foreach(var orderdetail in orderDetails)
{
orderDetailsViewModel.Add(new OrderDetailsViewModel { OrderId = orderDetail.OrderId, ProductId = orderDetail.ProductId, UnitPrice = orderDetail.UnitPrice, Quanity = orderDetail.quantity, Discount = orderDetail.Discount });
}
AutoMapper alternative projection
Install AutoMapper, run the following from the package manager console:
Install-Package AutoMapper
Create an AutoMapperConfig.cs in the App_Start folder with the mappings, similar to below:
public static class AutoMapperConfig
{
public static void Configure()
{
Mapper.CreateMap<OrderDetails, OrderDetailViewModel>();
}
}
In your global asax call the configure method:
protected void Application_Start()
{
...
AutoMapperConfig.Configure();
...
}
Then map in your controller:
var orderDetailsViewModel = new OrderDetailsViewModel();
orderDetailsViewModel.OrderDetails = Mapper.Map<List<OrderDetails>, List<OrderDetailsViewModel>>(orderDetails);
I prefer to use the AutoMapper approach as the mapping is defined globally and can be reused within your app.
Returning your view model
Your view model would then be passed back as follows:
return View(orderDetailsViewModel);
Razor output
You access it in your view by adding a model reference at the top:
#model OrderDetailsViewModel
Then output the properties as follows, I've only included OrderId but you can just add the fields the same way:
<table>
<tr>
<th>OrderId</th>
</tr>
#foreach(var orderDetail in Model.OrderDetails)
{
<tr>
<td>#orderDetail.OrderId</td>
</tr>
}
</table>
You have create ViewModel for that.
For example in your model folder create a class:
public class MyViewModel // Whatever name you want to give
{
//My fields which I want to pass to View
publis string Field1{get;set;}
etc
etc
}
public ActionResult Index()
{
DataRerieveClient _proxy = new DataRerieveClient();
var orderDetails = _proxy.GetProductDetails(null);
List<MyViewModel> viewModelList = new List<MyViewModel>();
foreach(var orderDetail in orderDetails)
{
MyViewModel viewModel = new MyViewModel(); //Create an object of your ViewModel
viewModel.Field1 = orderDetails.Field1; //set all feilds like that
viewModelList.Add(viewModel);
}
return View(viewModelList); // Pass View Model to View
}
Note: You have to create View for your ViewModel
Like
#model `List<MyViewModel>`
then use this ViewModel to access properties.
To know more about what is ViewModel, refer to the link below:
http://sampathloku.blogspot.ae/2012/10/how-to-use-viewmodel-with-aspnet-mvc.html
in the Controller class write :
public ActionResult Index()
{
DataRerieveClient _proxy = new DataRerieveClient();
var orderDetails = _proxy.GetProductDetails(null);
return View(orderDetails);
}
i assume your project name is MvcApplication2 and your class name is in Model Folder. so add follow code in top of View (sample.cshtml) :
#model MvcApplication2.Models.OrderDetail
ok , you can use this code to access properties of DataRecieveClient :
<div class="display-label">
#Html.DisplayNameFor(model => model.F1)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.F1)
</div>
Sorry for poor english.!

How to use UIHint attribute for property type of interface?

I have the next view model:
public class PickUpLocationViewModel
{
public DateTime PuDate {get;set}
public IAddressViewModel {get;set;}
}
Depends on implementation of IAddressViewModel I want to use appropriate UIHint("Airport"), UIHint("Seaport") etc.. Is it possible? If yes, how?
You could create an extra property on the IAddressViewModel of TemplateName like so:
public interface IAddressViewModel
{
string TemplateName { get; }
}
So then for each class that implements IAddressViewModel you can define a separate template name like:
public class SeaportAddressViewModel : IAddressViewModel
{
public string TemplateName
{
get
{
return "Seaport";
}
}
}
Then in your view you can use one of the overloads of EditorFor like:
#Html.EditorFor(m => m.Address, Model.Address.TemplateName)
This should cause it to use the editor template called Seaport.cshtml.
Let's suppose that you have the following models:
public class PickUpLocationViewModel
{
public DateTime PuDate { get; set }
public IAddressViewModel Address { get; set; }
}
public class AirportAddressViewModel: IAddressViewModel
{
public string Terminal { get; set; }
}
public class SeaportAddressViewModel: IAddressViewModel
{
public int DockNumber { get; set; }
}
and then a controller action:
public ActionResult Index()
{
var model = new PickUpLocationViewModel
{
Address = new AirportAddressViewModel { Terminal = "North" }
};
return View(model);
}
and a corresponding view:
#model PickUpLocationViewModel
#Html.DisplayFor(x => x.Address)
Now you could define the corresponding display/editor templates:
~/Views/Shared/EditorTemplates/AirportAddressViewModel.cshtml:
#model AirportAddressViewModel
#Html.DisplayFor(x => x.Terminal)
~/Views/Shared/EditorTemplates/SeaportAddressViewModel.cshtml:
#model SeaportAddressViewModel
#Html.DisplayFor(x => x.DockNumber)
Now based on the concrete type, ASP.NET MVC will automatically use the correct template.
And when it comes to binding back you will need a custom model binder. I have illustrated one here: https://stackoverflow.com/a/6485552/29407

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