Pass data between viewmodels - asp.net-mvc

I think I am getting somewhere with mvc.
I have created a view that is bound to my view model that looks like this
public class CreatePurchaseViewModel
{
public Order Order { get; set; }
public IEnumerable<Product> Products { get; set; }
public DateTime OrderDate { get; set; }
public bool OrderSent { get; set; }
}
I have also created another view model
public class ProductsViewModel
{
public int ProductID { get; set; }
public int OrderID { get; set; }
}
I have create a partial view that is bound to this viewmodel.
I am loading it from my view
#Html.Partial("_AddProductItem", new MVC_WireFrame.ViewModels.ProductsViewModel())
Now how do I get the items from my ProductsViewModel into my CreatePurchaseViewModel or is that not the correct way of doing things?
I can access the data from the ProductsViewModel in my controller like
[HttpPost]
public ActionResult InsertProduct(string input)
{}
2 questions really, how do I pass the value into the other viewcontroller? and
how do I populate a list within the AddProduct partial view so I can show what products have been added?
Thanks in advance for any help.

Normally you should not be passing data from one view model to another. You should create your view model classes in such a way that they contain all the required information for the view to display. It is the controller's responsibility to fill this information. Concerning you second question about the list, well you simply add a property which is of type IEnumerable<T> to this view model which will be filled by the controller and the view can show what products have been added. So think of what information your views require and add it to the view models as properties.

Related

mvc4 how to get specific data of html helper while has multiple models in the view

The code is:
Model
Use entity frame work to show 2 tables in database and put these into a model
public class UserDb : DbContext
{
public DbSet<UserItems> Users { get; set; }
public DbSet<ProductItems> Products { get; set; }
}
[Table("db_user")]
public class UserItems
{
[Display(Name="User Name")]
public string name { get; set; }
[Display(Name="E-mail")]
public string email { get; set; }
}
[Table("Products")]
public class ProductItems
{
[Display(Name="Product Name")]
public string name { get; set; }
[Display(Name="Product Number")]
public int number { get; set; }
}
public class DbCombine
{
public IEnumerable< UserItems> UserItems { get; set; }
public IEnumerable< ProductItems> ProductItems { get; set; }
}
Controller
Pass the model with tables' list to the view.
public ActionResult testingView()
{
var model = new DbCombine
{
ProductItems = db.Products.ToList(),
UserItems = db.Users.ToList()
};
return View(model);
}
View
#model MVCselfcode.Models.DbCombine
<div>#Html.EditorFor(m=>m.UserItems*.name*)</div>
The problem is I can't get the the detail data in strong type, like the code in view, it can't have .name afterm=>m.UserItems.
The error message is " This model doesn't include the 'name' defination".
How can I use strong type for this? or should I change the method to combine tables.
UserItems is of type IEnumerable<UserItems>, and IEnumerable<T> doesn't have a property called name. Each instance of the object has that property, but a collection of the objects does not.
Which element in the collection are you trying to edit?
In order to get the HTML helper to identify the property you want, you need to supply it with an instance of that property:
#Html.EditorFor(m=>m.UserItems.First().name)
This may intuitively seem like it would throw an exception if the collection is empty, but it actually doesn't invoke the call to First(). This simply allows the framework to reflect into the definition of the type returned by First() so it can build the resulting HTML.
If you're actually looking to edit the records, you'll probably want to create a custom editor for your UserItems type and iterate over the UserItems property to display an editor for each one. Additionally, to avoid confusion, I suggest not naming the plural property and the singular class with the exact same name. Perhaps the class should be called UserItem instead.
What you have doesn't make sense. UserItems is a collection which means it includes multiple UserItems entities. The question is which item in the Model.UserItems collection do you want to reference.
For example, did you perhaps mean to enumerate over the collection and produce a div for each item:
#foreach(var item in Model.UserItems)
{
<div>#Html.EditorFor(m => item.name)</div>
}

Render <List> data in partial page in ASP.NET MVC 5

i need to render list data in partial page... I have store procedure that is responsible to get list of menus and have master Layoutpage in view--> shared folder--> now i am rendering partial page in masterLayout page but i am not getting any result. I am aware that partial page doesn't go through controller so how i would pass the data in that?
Controller Action
public ActionResult DisplayFunctionsList()
{
var myList = F_UOF.GetAllFunctions();
return View(myList);
}
Store Procedure Mapping (Model) class
public class GetAllFunction_SP_Map
{
public GetAllFunction_SP_Map() { }
[Key]
public int Hierarchy_ID { get; set; }
[Required]
public int ParentID { get; set; }
[StringLength(250)]
[Required]
public string ParentName { get; set; }
[Required]
public int ChildID { get; set; }
[StringLength(250)]
[Required]
public string ChildName { get; set; }
[StringLength(250)]
[Required]
public string Controller { get; set; }
[StringLength(250)]
[Required]
public string Action { get; set; }
}
MasterLayout Page
#Html.Partial("_DisplayFunctionList_Partial")
Partial Page (_DisplayFunctionList_Partial)
#model IEnumerable<DatabaseLayer.StoreProcedures.StoreProceduresMapping.GetAllFunction_SP_Map>
#foreach(var item in Model)
{
#item.ParentName
}
In this example, since you are calling from the master page, you want to use the Html.RenderAction() method.
#{Html.RenderAction("DisplayFunctionsList", "Controller");}
Edit - the Html.RenderAction must be surrounded by curly braces with the semicolon (';') at the end of the function call. To avoid this, you can use the #Html.Action call, which returns an MvcHtmlString
#Html.Action("DisplayFunctionsList", "Controller")
Also, in using this method, you would need to change your view result slightly because the view you are trying to render is not the name of the action you are calling it from and you appear to be wanting to return a PartialViewResult
public ActionResult DisplayFunctionsList()
{
var myList = F_UOF.GetAllFunctions();
return PartialView("_DisplayFunctionList_Partial", myList);
}
If you are within a view (not a master page), then you would need to pass the model, assuming the model is of the correct type. If the model for the partial view is a property on your overall view model, then just send the model property instead of the entire model.
*Send Entire Model*
#Html.Partial("_DisplayFunctionList_Partial", Model)
*Send Model Property*
#{Html.Partial("_DisplayFunctionList_Partial", Model.MyList)}
The call to #Html.Partial takes a second parameter, which is the model to pass to the partial view. All you need to do is include the list in your View's Model and then pass it along appropriately.

combine 2 related model in mvc

I have 2 models like this.
public partial class Question
{
public int QuestionId { get; set; }
public string QuestionText { get; set; }
public string Ans1 { get; set; }
public string Ans2 { get; set; }
public string Ans3 { get; set; }
public string Ans4 { get; set; }
}
public partial class UserAnswer
{
public int UserAnsId { get; set; }
public Nullable<int> QuestionId { get; set; }
public Nullable<int> UserId { get; set; }
public Nullable<int> AnsVal { get; set; }
}
As you can see QuestionId is in both the models. How can I render it in view. There are multiple questions. Question Moldel has data in initial run but UserAnswer doesn't.
How can I combine these 2 models so that I can use it as IEnumerable in view. Ans1,Ans2,Ans3,Ans4 has text and AnsVal in UserAnswer will get its value from Raiobutton.
make a combine class like below..i am not sure this is perfect or not..any suggestions are acceptable.
public class QuestionAnswerViewModel
{
public Question Question {get;set;}
public ICollection<UserAnswer> Answers {get;set;}
}
You want to create a ViewModel that represents the combined model objects. This keeps things clean, your model is just that, the model, what gets passed to the view can be the model but in many cases the concept of a ViewModel will make things easier to design while keeping your code loosely coupled and clean. This also keeps things that are not important to the View out of the equation aka particular properties in your model such as maybe a CreatedDate should not be passed to the View, especially since View requests will pass back the value as null since it is not being used in the view and thus not populated on postback. This could lead to you updating the database with a null value for CreatedDate simply because it was not used in the View.
Maybe you have a Model class library in your solution? If you do, create another class library called MyNamespace.Web.ViewModels or something like that. Also you should look into using a tool like AutoMapper that will populate the ViewModel on View request to the Controller and populate the model on View postback to the controller.

MVC - Multiple models in a view

I'm using MVC (for the first time) with Entity framework, Database first
What I want to do is display data from a database in a single view. I created the database first, then I made a ADO.NET Entity Data Model based from the database that contains all the tables. I then created a Index view that was strongly typed with my Entity Data Model as model.
In my Index I have at the top
#model IEnumerable<Forum6.Models.Forum>
This allows me to get the rows from the table "Forum" from my database. If I try to add an extra model I get I get this error message when I run:
Line 1: #model IEnumerable<Forum6.Models.Forum>
Line 2: #model2 IEnumerable<Forum6.Models.Post>
Parser Error Message: Only one 'model' statement is allowed in a file.
After searching for an answer I found this: Two models in one view in ASP MVC 3
The answer was to create a ViewModel (ParentModel) that contained all the Models (Tables).
This is the ViewModel I created:
public class ViewModel
{
public IEnumerable<Forum6.Models.Forum> Forum { get; set; }
public IEnumerable<Forum6.Models.Post> Post { get; set; }
public IEnumerable<Forum6.Models.Topics> Topics { get; set; }
public IEnumerable<Forum6.Models.Users> Users { get; set; }
public IEnumerable<Forum6.Models.PrivMsg> PrivMsg { get; set; }
public IEnumerable<Forum6.Models.Permission> Permission { get; set; }
}
I edited my controller to look like this:
public class HomeController : Controller
{
// ForumDBEntities old_db = new ForumDBEntities();
ViewModel db = new ViewModel();
public ActionResult Index()
{
return View(db);
}
}
Then replaced the old Index view with a new strongly typed view that used the ViewModel as model. Which contains:
#model IEnumerable<Forum6.Models.ViewModel>
Trying to run this gives me this error:
The model item passed into the dictionary is of type 'Forum6.Models.ViewModel', but this dictionary requires a model item
of type
'System.Collections.Generic.IEnumerable`1[Forum6.Models.ViewModel]
How do I make the "ViewModel" enumarable? Or is my error elsewhere?
You'll need to change #model IEnumerable<Forum6.Models.ViewModel> to #model Forum6.Models.ViewModel as you're wrapping your IEnumerables inside a single ViewModel.
A good rule of thumb is to have a 1:1 relationship between your ViewModel and View.
This might be a good read for you: http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ (just ignore the automapper part if you don't want to go that route)
You'll also need to put in actual data in your ViewModel since
ViewModel db = new ViewModel();
public ActionResult Index()
{
return View(db);
}
will just give your view an empty ViewModel.
One way to do it would be.
public ActionResult Index()
{
var model = new ViewModel
{
Forum = db.GetForum(),
Post = db.GetPost(),
Topic = you get the idea
};
return View(model);
}
One last thing when naming properties or variables in general you should use the plural verb when it contains a list. So your ViewModel would be.
public class ViewModel
{
public IEnumerable<Forum6.Models.Forum> Forums { get; set; }
public IEnumerable<Forum6.Models.Post> Posts { get; set; }
public IEnumerable<Forum6.Models.Topics> Topics { get; set; }
public IEnumerable<Forum6.Models.Users> Users { get; set; }
public IEnumerable<Forum6.Models.PrivMsg> PrivMsgs { get; set; }
public IEnumerable<Forum6.Models.Permission> Permissions { get; set; }
}
Change #model IEnumerable<Forum6.Models.ViewModel> to #model Forum6.Models.ViewModel as you are passing a single instance of a ViewModel class and not a collection of them.
All your collections are passed in a single instance of a view model.

Passing complex object from view to controller/view in ASP.NET MVC

In my MVC application I have a problem with passing data from view to controller. I have fairly complex domain classes:
public class TaskBase : PersistableObject
{
public virtual TaskCategory Category { get; set; }
public virtual IList<TaskNote> Notes { get; set; }
public virtual string TaskTitle { get; set; }
public virtual string TaskBody { get; set; }
public virtual DateTime? CreationTime { get; set; }
public virtual User CreatedBy { get; set; }
public virtual int CompletionRatio { get; set; }
}
public class MainTask : TaskBase
{
public virtual IList<TaskBase> ChildTasks { get; set; }
public virtual User AssignedTo { get; set; }
public virtual IList<TaskHistory> History { get; set; }
}
public class TaskFormModel : ViewDomainBase
{
public MainTask Task { get; set; }
public LoginForm LoginInfo { get; set; }
}
And in my view I want to pass an instance of TaskFormModel to the controller.
<%= Html.ActionLink<TaskController>("Edit Task", (x) => x.Edit(new TaskFormModel() { Task = item, LoginInfo = Model.LoginInfo }))%>
And here is the controller action:
public ActionResult Edit (TaskFormModel taskInfo)
{
return View(ViewPageName.TaskDetailsForm, task.Task);
}
In this action method taskInfo comes null even if I pass non-null instance from view. I think I have a binding problem here. I think, writing custom model binder requires every property to be converted and also when new fields added then binder class should also be changed, so I don't want custom model binder to do this. Is there any other way to pass data to controller in this scenario? Or could custom model binder can be coded so that less code written and also when new properies are added binder class will not need to be changed?
Edit After Comments: What I am trying to achieve is basically to pass an instance from one view to another view, without querying repository/db in my controller's action.
First version of answer:
Your GET edit method should be like:
public ActionResult Edit (int id)
{
var model = taskRepository.GetTaskEditModel(id);
return View(ViewPageName.TaskDetailsForm, model);
}
and ActionLink:
<%= Html.ActionLink("Edit Task", "Edit", "Task", new { model.Task.id })%>
If you want to pass complex objects to controller, you should wrap them up in html form and pass to POST action.
In my opinion you are doing something wrong.
As I understand: you are trying to instantiate a new object, pass it to browser and get it back.
well you cant.
If object you want to edit exists already in your storage, then you should alter your ActionLink to reference it by id, and instantiate it inside your Edit action.
Take a look at default strongly typed index views created by tooling.

Resources