I have a Settings Action on my Account controller that renders the Settings View.
On the Settings View, I recieve a ViewModel that includes ChangePasswordModel.
Here is the SettingsViewModel:
public class SettingsViewModel
{
public ChangePasswordModel ChangePasswordModel { get; set; }
}
The Settings View recieves
#model XBLTools.Models.SettingsViewModel
The ChangePassword View recieves
#model XBLTools.Models.ChangePasswordModel
The ChangePassword view works OK alone.
How to render the ChangePassword View passing the Model.ChangePasswordModel?
I've tried some combinations without success getting different errors:
#Html.RenderPartial("ChangePassword", (XBLTools.Models.ChangePasswordModel)(Model.ChangePasswordModel))
#Html.RenderPartial("ChangePassword", Model.ChangePasswordModel)
#Html.Partial("ChangePassword", (XBLTools.Models.ChangePasswordModel)(Model.ChangePasswordModel))
#Html.Partial("ChangePassword", Model.ChangePasswordModel)
Any ideas?
If it's null pass in a new instance of ChangePasswordModel:
#Html.RenderPartial("ChangePassword", new ChangePasswordModel())
Or instantiate it in the constructor of SettingsViewModel:
public class SettingsViewModel
{
public SetttingsViewModel()
{
ChangePasswordModel = new ChangePasswordModel();
}
public ChangePasswordModel ChangePasswordModel { get; set; }
}
You should initialise the ChangePasswordModel on the settings view model in the controller.
public ActionResult MyAction()
{
var model = new SettingsViewModel{
ChangePasswordModel = new ChangePasswordModel()
}
return View(model);
}
then use:
#Html.Partial("ChangePassword", Model.ChangePasswordModel)
You can just pass your model property:
#Html.Partial("ChangePassword", Model.ChangePasswordModel)
If the ChangePasswordModel proeprty is null, you'll get an error, since the partial view needs a model.
Make sure that you've set the ChangePasswordModel property to an instance.
Alternatively, you can just pass a new ChangePasswordModel instance:
#Html.Partial("ChangePassword", new ChangePasswordModel())
Related
I'm getting the apparently classic exception:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'PieShop.ViewModels.HomeViewModel', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable`1[PieShop.Models.Pie]'
when trying to render a page in ASP.NET Core MVC.
I've seen a lot of answers for this question, but all seem to be the result of an obvious datatype mismatch between what's passed into the view from the controller and what's declared in the view itself. In my case, they match perfectly. Here's my controller:
public class HomeController : Controller
{
private readonly IPieRepository pieRepository;
public HomeController(IPieRepository pieRepository)
{
this.pieRepository = pieRepository;
}
public IActionResult Index()
{
var pies = pieRepository.GetAllPies();
var vm = new HomeViewModel()
{
SomeData = "haiod",
Title = "Welcome to the Pie Shop"
};
return View(vm);
}
}
Here's the view model:
public class HomeViewModel
{
public string Title { get; set; }
public string SomeData { get; set; }
}
And here's the view (which is called Views/Home/Index.cshtml:
#model PieShop.ViewModels.HomeViewModel
<h1>#Model.SomeData</h1>
The model passed into the view from the controller and what the view is declaring as its model are clearly the exact same type. What gives?
Turns out I had declared a type for the model in the shared _Layout.cshtml because I copy/pasted it during some refactoring:
#model IEnumerable<PieShop.Models.Pie>
So... just a copypasta error :facepalm:
I have a ViewModel that has a complex object as one of its members. The complex object has 4 properties (all strings). I'm trying to create a re-usable partial view where I can pass in the complex object and have it generate the html with html helpers for its properties. That's all working great. However, when I submit the form, the model binder isn't mapping the values back to the ViewModel's member so I don't get anything back on the server side. How can I read the values a user types into the html helpers for the complex object.
ViewModel
public class MyViewModel
{
public string SomeProperty { get; set; }
public MyComplexModel ComplexModel { get; set; }
}
MyComplexModel
public class MyComplexModel
{
public int id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
....
}
Controller
public class MyController : Controller
{
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
model.ComplexModel = new MyComplexModel();
model.ComplexModel.id = 15;
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// model here never has my nested model populated in the partial view
return View(model);
}
}
View
#using(Html.BeginForm("Index", "MyController", FormMethod.Post))
{
....
#Html.Partial("MyPartialView", Model.ComplexModel)
}
Partial View
#model my.path.to.namespace.MyComplexModel
#Html.TextBoxFor(m => m.Name)
...
how can I bind this data on form submission so that the parent model contains the data entered on the web form from the partial view?
thanks
EDIT: I've figured out that I need to prepend "ComplexModel." to all of my control's names in the partial view (textboxes) so that it maps to the nested object, but I can't pass the ViewModel type to the partial view to get that extra layer because it needs to be generic to accept several ViewModel types. I could just rewrite the name attribute with javascript, but that seems overly ghetto to me. How else can I do this?
EDIT 2: I can statically set the name attribute with new { Name="ComplexModel.Name" } so I think I'm in business unless someone has a better method?
You can pass the prefix to the partial using
#Html.Partial("MyPartialView", Model.ComplexModel,
new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ComplexModel" }})
which will perpend the prefix to you controls name attribute so that <input name="Name" ../> will become <input name="ComplexModel.Name" ../> and correctly bind to typeof MyViewModel on post back
Edit
To make it a little easier, you can encapsulate this in a html helper
public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
string name = ExpressionHelper.GetExpressionText(expression);
object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
var viewData = new ViewDataDictionary(helper.ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo
{
HtmlFieldPrefix = string.IsNullOrEmpty(helper.ViewData.TemplateInfo.HtmlFieldPrefix) ?
name : $"{helper.ViewData.TemplateInfo.HtmlFieldPrefix}.{name}"
}
};
return helper.Partial(partialViewName, model, viewData);
}
and use it as
#Html.PartialFor(m => m.ComplexModel, "MyPartialView")
If you use tag helpers, the partial tag helper accepts a for attribute, which does what you expect.
<partial name="MyPartialView" for="ComplexModel" />
Using the for attribute, rather than the typical model attribute, will cause all of the form fields within the partial to be named with the ComplexModel. prefix.
You can try passing the ViewModel to the partial.
#model my.path.to.namespace.MyViewModel
#Html.TextBoxFor(m => m.ComplexModel.Name)
Edit
You can create a base model and push the complex model in there and pass the based model to the partial.
public class MyViewModel :BaseModel
{
public string SomeProperty { get; set; }
}
public class MyViewModel2 :BaseModel
{
public string SomeProperty2 { get; set; }
}
public class BaseModel
{
public MyComplexModel ComplexModel { get; set; }
}
public class MyComplexModel
{
public int id { get; set; }
public string Name { get; set; }
...
}
Then your partial will be like below :
#model my.path.to.namespace.BaseModel
#Html.TextBoxFor(m => m.ComplexModel.Name)
If this is not an acceptable solution, you may have to think in terms of overriding the model binder. You can read about that here.
I came across the same situation and with the help of such informative posts changed my partial code to have prefix on generated in input elements generated by partial view
I have used Html.partial helper giving partialview name and object of ModelType and an instance of ViewDataDictionary object with Html Field Prefix to constructor of Html.partial.
This results in GET request of "xyz url" of "Main view" and rendering partial view inside it with input elements generated with prefix e.g. earlier Name="Title" now becomes Name="MySubType.Title" in respective HTML element and same for rest of the form input elements.
The problem occurred when POST request is made to "xyz url", expecting the Form which is filled in gets saved in to my database. But the MVC Modelbinder didn't bind my POSTed model data with form values filled in and also ModelState is also lost. The model in viewdata was also coming to null.
Finally I tried to update model data in Posted form using TryUppdateModel method which takes model instance and html prefix which was passed earlier to partial view,and can see now model is bound with values and model state is also present.
Please let me know if this approach is fine or bit diversified!
I am using Html.RenderAction in my View to call a method that is in my controller. The controller method returns a custom object, I want to know how would I be able to use this returned object in the view.
View
//at the top
#model ServiceCheckerUI.Models.DeleteDeliverableModel
#{ Html.RenderAction("retrieveDeliverableInfo","DeliverableManagement", new {uniqueId = element});}
//Trying to use the model property
Model.deliverableResponse.{properties}
Controller
public ActionResult retrieveDeliverableInfo(string uniqueId){
var response = _target.DoSomething();
return PartialView("DeleteDeliverable", new DeleteDeliverableModel {deliverableResponse = response});
}
Model
namespace ServiceCheckerUI.Models
{
public DeleteDeliverableModel
{
//omit
public GetDeliverableResponse deliverableResponse {get;set}
}
}
The GetDeliverableResponse object has fields like id, name etc which are strings and ints.
RenderAction is used to directly write response to the page and helps in caching the partial view. Your method should return partial view instead of GetDeliverableResponse. You can define the partial view and use GetDeliverableResponse as it's model.
public ActionResult RetrieveDeliverableInfo(string uniqueId)
{
var response = _target.DoSomething();
return PartialView("_Deliverable", response );
}
Here _Derliverable would be your partial view which will have GetDeliverableResponse as model.
To keep it more neat you can also Wrap the response object in a dedicated model class of _Derliverable like this:
class DerliverableModel
{
public GetDeliverableResponse Derliverables { get; set; }
}
now in your action method you need to pass the object of this model:
return PartialView("_Deliverable", new DerliverableModel { Derliveries = response });
I'm getting the error, "Object reference not set to an instance of an object." when attempting to assign a value to a model's fields in my MVC project. My model (not strongly typed) is referenced in my view thus:
...Inherits="System.Web.Mvc.ViewPage<Project.Models.MyModel>" %>
Intellisense picks up MyModel's fields when I access it in the view. My model is posted below:
namespace Project.Models
{
public class MyModel
{
public int AddressId { get; set; }
public int AddressTypeId { get; set; }
....
}
}
As you can see, I do a get set on each field and everything is public. But when I debug it, as soon as I hit anything to do with the Model, the compiler complains that "Object reference not set to an instance of an object."
What's missing here?
Make sure you have passed a model to this view from the controller action that rendered it:
public ActionResult SomeAction()
{
MyModel model = ... fetch your model from somewhere
return View(model); // <!-- Notice how the model must be passed to the view
}
Obviously the function that is retrieving your model from wherever you are retrieving it must ensure that the model is not null. Alternatively you could test in the view if the model is not null before accessing it's properties and if it is null render some alternative content.
You will have to initialize your model first
for eg:
public ActionResult YourAction()
{
MyModel model = new MyModel();
return View(model);
}
I have a view that contains many partial views and I need to pass to each one the matching model.
I've found 2 ways to do this, but I don't know whats the real way it should be done.
I thought of creating big class that contain all the models as properties and than i can send the models to each partial view. the problem is that its hard typed, and if i need to pass a diffrent combination of models it wont fit.
The other way I though of is having a methods in each model that bring me the model for each partial view (GetMenuBar() and so on).
Whats the right way doing that?
My advice, go with Option 1. I use that with all of my Main View/Multiple Partial View scenarios. It's easy to maintain as each partial has it's own ViewModel. It keeps the whole thing nice and clean
I use the exact same setup like so:
public class MainViewModel {
public Partial1ViewModel Partial1 [ get; set; }
public Partial2ViewModel Partial2 [ get; set; }
public Partial3ViewModel Partial3 { get; set; }
public Partial4ViewModel Partial4 { get; set; }
public MainViewModel() {}
public MainViewModel() {
Partial1 = new Partial1ViewModel();
Partial2 = new Partial2ViewModel();
Partial3 = new Partial3ViewModel();
Partial4 = new Partial4ViewModel();
}
}
Each PartialViewXViewModel is it's own ViewModel and if need be can be reused in another view.
Your Action that renders can look like so:
public ActionResult Index {
var model = new MainViewModel();
return View(model);
}
Your View
#model MainViewModel
<div>
{#Html.RenderPartial("PartialOne", Model.Partial1)}
</div>
<div>
{#Html.RenderPartial("PartialTwo", Model.Partial2)}
</div>
<div>
{#Html.RenderPartial("PartialThree", Model.Partial3)}
</div>
<div>
{#Html.RenderPartial("PartialFour", Model.Partial4)}
</div>
Define the UI for each PartialX like:
#model Partial1ViewModel
//view html here
Now, each Partial view html and each model that they use can be used anywhere.
The great part is now if you have a page that needs only 2 of these you just create a new ViewModel to represent that specific view like so:
public class OtherMainViewModel {
public Partial2ViewModel Partial2 [ get; set; }
public Partial4ViewModel Partial4 { get; set; }
public OtherMainViewModel() {}
public OtherMainViewModel() {
Partial2 = new Partial2ViewModel();
Partial4 = new Partial4ViewModel();
}
}
And use it in another view like so:
public ActionResult SomeOtherAction {
var model = new OtherMainViewModel();
return View(model);
}
And that's perfectly acceptable and also the preferred design strategy in MVC, to have ViewModels that specifically represent what a view needs and only what it needs.
You may want to use a different method for populating your models tho. Most here would recommend using Automapper. Either way, the above just initializes the PartialViewXModels in the constructor of the MainViewModel. That won't necessarily be your case if you are populating those models with data from your DB. You would want your own strategy for that. This would work here:
public ActionResult Index {
var model = new MainViewModel();
model.Partial1 = GetPartial1Data(); // this method would return Partial1ViewModel instance
model.Partial2 = GetPartial2Data(); // same as above for Partial2ViewModel
...
return View(model);
}
This all would just get you started with the design, you can tweak it to your hearts content :-)