I have a Web app where my controller passes a model to the parent view like so:
public ActionResult Results()
{
//Processing
return View ("ParentView",model);
}
Within my "ParentView" I will do render a partial view like so:
#Html.Partial("_PartialView", anotherModel)
Now I would like to not touch the anotherModel at all.
But what I am trying to do is pass a value to _PartialView from the ParentView.
I know I can pass something like ViewBag.Value="Text" from the Controller to the "ParentView", however is something like that doable from "ParentView" to "_PartialView"?
Basically I want to add a value in the model that is being used by "ParentView", and somehow pass it down to "_PartialView"
You will have to create a View model. you can create it by 3 ways
first way
public class ViewModel
{
public class ParentViewModel {get; set;}
public class ChildViewModel {get; set;}
}
in this case your view
#model ViewModel
...... //html is using #Model.ParentViewModel)
#Html.Partial("_PartialView", #Model.ChildViewModel)
second way
public class ParentViewModel:ChildViewModel
in this case the same model can be used for both
#model ParentViewModel
...... //html is using #Model)
#Html.Partial("_PartialView")
The third way can be used if it is possible to use interface to another model
partial view
#model IAnotherModel
viewmodel
public class ViewModel:IAnotherModel
view is the same as the second way
You can pass properties from your PageView Model to your PartialView like this:
#Html.Partial("_PartialView", #Model.AnotherModel)
You then set the Model of your _PartialView to be of the type of AnotherModel.
Related
I have a tree structure of objects (as in picture below). Classes Descendant1 and Descendant2 are to be viewed in the same way as Form class(the root class). I wanted to create a partial view for that, however, I need to have a model in the view as I am using properties from the model(such as Name from the root class)
This is my code of FormView that is to be in the partial view:
<div>
#foreach (var subForm in Model.SubForms)
{
Html.RenderPartial(partialView, subForm);
}
<div>#Model.Name</div>
</div>
I was wondering if it was possible to create a partial view that can have multiple models? Do I create one controller for all the descendant classes together? Otherwise, do you have any ideas how to proceed?
I was wondering if it was possible to create a partial view that can have multiple models?
Yes, make a view model for those 3 classes. Example below is named FormViewModel.
public class FormViewModel{
public class Descendant1 {get;set;}
public class Descendant2 {get;set;}
public class Descendant3 {get;set;}
}
Then in your view you could do;
#foreach (var subForm in Model.SubForms)
{
FormViewModel fmv = new FormViewModel();
// access its class properties
fmv.Descendant1.SubForms.Add(new Form(){ // assign properties });
// pass the view model to the partial view
Html.RenderPartial(partialView, fmv);
}
As I found on 10 Good practices for asp.net mvc webapplications it is a good practice to split mvc models in ViewModel (Models representing the view) and InputModels (Representing data entered by user).
The ViewModel gets a property of Type InputModel. The InputModel carries the data that can be edited by the user.
public class EmployeeInputModel{
public string Name {get;set;}
public Id? DepartmentId{get;set;}
}
public class EmployeeCreateViewModel{
public IList<Department> Departments{get;set;}
public EmployeeInputModel EmployeeModel{ get;set;}
}
The Controller-methods look like:
public class EmployeeController : Controller{
public ActionResult Create(){
var viewModel = new EmployeeCreateViewModel(DepartmentService.GetAll(), new EmployeeInputModel());
return View(viewModel);
}
public ActionResult Create(EmployeeInputModel createModel){
try{
EmployeeService.Create(...);
return RedirectToAction("Index");
} catch (Exception ex){
var viewModel = new EmployeeCreateViewModel(DepartmentService.GetAll(), createModel);
return View(viewModel)
}
}
}
The View looks like:
#model EmployeeCreateViewModel
#Html.EditorFor(m => m.EmployeeModel)
The Editor Partial is just like:
#model EmployeeInputModel
#Html.TextBoxFor(m => m.Name)
#Html.DropDownFor(m => m.Department, ???)
This worked great for me, unless I came to the point of DropDownLists (in the sample see departments). Because the EditorTemplate doesnt know the ViewModel but just the InputModel.
I dont want to put the department list into the input model, because it is not the supposed place to be for this list (I would have to bind them). It has to be in the viewmodel. The properties of the input model should also not be in the ViewModel.
Does someone have any idea how to achieve a separation of viewmodel and input model in one view?
You would have to create a model abstraction of your departments. Something like this:
public class EmployeeInputModel{
public string Name {get;set;}
public List<DepartmentInputModel> Departments{get;set;}
}
public class DepartmentInputModel{
public int Id;
public string Name;
}
Then you can display just the name of the department in the drop down list. The value will then be the id of the department.
You can have a look at this SO question for a example.
You can use the ViewBag yo pass the list of departments to your partial.
Or use a partial view that accepts the view model as its model
I`m writing an ASP.Net MVC application with Razor.
Assume that I have HomeController and some views for it.
1. View1
2. View2
3. View3
All this views use common _MyLayout file, which should look like this:
When the links are clicked, the views are rendered by RenderBody() method.
Each view is strongly typed: it requires its own Model.
Everything was fine untill I decided to add special Model to _MyLayout view.
But now I get error
The model item passed into the dictionary is of type 'TestUp.Models.UserModels.PendingTestsModel', but this dictionary requires a model item of type 'TestUp.Models.UserModels.UserNavigationModel'.
Here is controllers code
public ActionResult View1()
{
ModelForView1 model = new ModelForView1();
return View(model);
}
public ActionResult View2()
{
ModelForView2 model = new ModelForView2();
return View(model);
}
public ActionResult View3()
{
ModelForView3 model = new ModelForView3();
return View(model);
}
Shortly speaking if layout view doesn`t require model, specific method for View is invoked,
model is created, passed to view and everything is ok. But now layout requires model as well so it crashes.
The question is: how do I elegantly resolve this problem?
Desired workflow is:
View1 is requested
Method in controller for this view is called, model instance created, passed to view
Some method for layout is called, model for layout created, passed to layout.
Is it possible to make things work somehow like this?
Thanks.
Create a base model type and have your specific view models extend it. This base model can have a property of type UserNavigationModel. The layout can accept the base model and use the new property as the model for the navigation menu.
public abstract class ModelBase
{
public UserNavigationModel NavigationModel { get; set; }
}
public class ModelForView1 : ModelBase { ... }
public class ModelForView2 : ModelBase { ... }
public class ModelForView3 : ModelBase { ... }
View1:
#model ModelForView1
Layout:
#model ModelBase
#* use Model.NavigationModel for nav bar *#
This is the view:
#model tgpwebged.Models.sistema_DocType
...
this model is an entity used with textBoxFor and others html helpers
This is the controller.
public ActionResult AdminSettingAddTipo()
{
IEnumerable<string> indices;
using (tgpwebgedEntities context = new tgpwebgedEntities())
{
var obj = from u in context.sistema_Indexes select u.idName;
indices = obj.ToList();
}
return PartialView(indices);
}
I have all I need here, I am using a model to create with the view so I am not allowed to send ´indices´ as a model because it´s not allowed to have 2 models in one view.
I don´t want to use ´Tupe´ now a parent view. I just want to know how is the best way to send my IEnumerable to the view.
I was thinking of ViewBag for the last option but I am avoiding ViewBag.
thanks
ViewBag is not a good choice. Create ViewModel using your list and your current Model:
public class YourViewModel
{
public sistema_DocType Type { get; set; }
public IEnumerable<string> Indices {get;set;}
}
Hope,it will help.
If you don't want to use ViewBag for whatever reason, you could create a Model specifically for the view that contains the info from the old model and the new indices you want. This is a common pattern in MVC development. You can even have the ViewModel be a Decorator for your current Model.
http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
Use strongly defined where you can, apply this to a model and send that model:
Model
public class MyModel{
public List<sistema_Indexes> indecies {get;set;}
}
Controller
MyModel model = new MyModel();
model.indecies = context.sistema_Indexes.Select(u=> u.idName).ToList();
I have a view model as such:
public class MyViewModel
{
public MyObject myObject{ get; set; }
public List<MyList> myList{ get; set; }
}
I have a view with a form strongly typed to MyViewModel
This view allows you to enter values for the properties of MyObject, as well as create a list of MyList objects. The List part works fine although I thought that would be the more difficult of the two.
Assuming MyObject has a property Description I create a textbox to enter the value as such:
#Html.EditorFor(x => x.myObject.Description);
The text box renders with an id of MyObject_Description...The problem is when I post this to my controller action, MyObject does not get bound at all(althought the list items do as they recieve the appropriate IDs of "MyViewModel_MyList[guid].myListValue")
What am I doing wrong here??
EDIT: more info
The first line of the view is:
#model MyApp.ViewModels.MyViewModel
And the Action method:
[HttpPost]
public ActionResult Create(MyViewModel myViewModel)
{
}
I am passing a new MyViewModel into the partial view to begin...
public ActionResult Create()
{
MyViewModel model = new MyViewModel();
return PartialView(model);
}
EDIT 2
Ok When I render my partial view that contains the forms I call :
#{Html.RenderAction("Create", "MyController");}
this is called from within a View of type #model IEnumerable<MyApp.Models.MyObject>
(this view displays a list of currently existing MyOjects, and at the bottom the partial is rendered to allow the user to add another MyObject to the DB)
If you are not already doing so, try creating a editor template (e.g., Views->Shared->EditorTemplates) called MyObject.cshtml. Move your partial view content to this view and then call
#Html.Editor("myObject").
from your parent partial view.
Change your ViewModel to have the Description directly
public class MyViewModel
{
public string Description { get; set; }
public List<MyList> myList{ get; set; }
}
then bind accordingly
#Html.EditorFor(x => x.Description);
I would expect the top line of your view to look something like this:
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<MyViewModel>" %>
This tells the view that the model it is supplied is of type MyViewModel (a la <T> style).
I don't think the out of the box model binding knows how to bind to complex objects. You're probably going to have to write up some sort of custom model binder.
I'm afraid it's not something I've done since MVC1 so I'm a bit hesitant to give you any sample code because the mechanism may well have changed completely since then. A quick google did turn up this article http://www.learnxpress.com/asp-net-mvc-hosting-6-tips-for-asp-net-mvc-model-binding-2.html and this article http://bradwilson.typepad.com/blog/2010/10/service-location-pt9-model-binders.html.
Edit: I've just seen this answer which might help Retrieving data from view, should I use model binder?