ASP.NET MVC ViewModel to view issue [duplicate] - c#

I'm working on a MVC 5 project, very new to MVC. I noticed this line in the code:
#Html.DropDownListFor(model => model.ContractorId, Model.Contractors)
the directive on the top of the page is:
#model Project.Models.ContractViewModel
The ContractViewModel class does have a Contractors object in it.
public IEnumerable<SelectListItem> Contractors
I'm just a little confused on the capital M (Model.Contractors), does Model always refer to the object passed in the #model? Then what is the difference between using Model.Contractors and model.Contractors?

Model actually represents an instance of the class that is your model and model is an alias for lambda expression.
When you write #Model in your view you are using the object of ContractViewModel which is passed from Controller action, if it is not passed from View it can be null and accessing any property of Model can throw Null Reference Exception and writing Model.Contractors you basically mean ContractViewModel.Contractors
and when you write a html helper you need to write an alias for it, its not mandatory to write model you can write anything.
for example:
#Html.DropDownListFor(m=> m.ContractorId, Model.Contractors)
It is just an alias to access the model properties inside Html Helper.
When you write #model Project.Models.ContractViewModel at the top of View that is a different thing, in this case we are defining the model of view that it will take instance of Project.Models.ContractViewModel , actually our view is now strongly typed to instance of class Project.Models.ContractViewModel.

Related

Partial View with intentionally blank model

Okay, so I've been using .net MVC (and nowadays .net core) for years and have never had this issue... to my recollection.
I've got a parent view with its own ViewModel, and a partial with its own view model. Now, the razor code that calls the partial does so by string name, and it has no idea what viewmodel it should use because it's dynamic. Now, when we call a controller method that returns a view that requires a viewmodel and we don't provide an instance of that viewmodel, MVC wires us up a new instance by default. However, with a partial view inside of a parent view, even if we don't specify a viewmodel, or intentionally pass in null, we will still receive the error that the parent viewmodel type was passed in when the partial's viewmodel type was required. I simply want to, by default new up a viewmodel of whatever type the partial needs, without hard-coding it... just like a normal view would do when returned by a controller method...
Any ideas?
For example
public IActionResult DoSomething() => View();
With a view calld "DoSomething" that looks like this.
#model app.viewmodels.DoSomethingViewModel
<h1>#(Model.SomeStringProperty)</h1>
The controller view will use a newly constructed model for reference.
However, if I have another view called "DoSomethingElse"
#model app.viewmodels.DoSomethingElseViewModel
<h1>#(Model.SomeStringProperty)</h1>
and I change the first view to include a partial of that view
#model app.viewmodels.DoSomethingViewModel
<h1>#(Model.SomeStringProperty)</h1>
#await HTML.PartialAsync("DoSomethingElse")
By default the partial will get passed into it the "DoSomethingViewModel" from its calling parent.
How can I make the partial use its default constructor without hardcoding something like this.
#model app.viewmodels.DoSomethingViewModel
<h1>#(Model.SomeStringProperty)</h1>
#await HTML.PartialAsync("DoSomethingElse", new
DoSomethingElseViewModel())
I wanted to avoid using reflection in my particular circumstances, and it just seems that there should be an overload that allows you to uses a newly constructed model by default.

How to handle MVC DisplayTemplates for two classes with the same name (different namespaces)

You can only have one View per class name in the DisplayTemplates folder as the class name is used as the name of the view.cshtml file.
However, you can have two classes in a solution with the same name if they appear in different namespaces:
MyNamespace.Class1
MyOtherNamespace.Class1
Both try to use the DisplayTemplate defined by view:
Class1.cshtml
However in the view file you must declare the model - for example:
#model MyNamespace.Class1
This means that if you have a DisplayFor which takes a MyOtherNamespace.Class1 you get a runtime error due to a type mismatch.
If you knew in advance the places where this was going to happen you could use the UIHint to force the DisplayFor to use an alternative template (or you could use a named template directly in the view). But if you don't know in advance (you have all these objects in an enumeration of some kind and therefore can't write specific code to handle edge cases like this without a lot of unwieldy reflection - is there any way to have DisplayTemplates for these classes?
I haven't tried something like this before, but it should work. You can have the view accept a generic model type like object, and then attempt to cast it to the appropriate type:
#model object
#if (Model is MyNamespace.Class1)
{
var class1 = Model as MyNamespace.Class1;
// view code for this type
}
#if (Model is MyOtherNamespace.Class1)
{
var class1 = Model as MyOtherNamespace.Class1;
// view code for this type
}
UPDATE
Looking again at this, I'm bothered by the branching being done in this template. That's unavoidable, but a slightly better solution might be something like:
#model object
#if (Model is MyNamespace.Class1)
{
Html.RenderPartial("MyNamespaceClass1", Model);
}
#if (Model is MyOtherNamespace.Class1)
{
Html.RenderPartial("MyOtherNamespaceClass1", Model);
}
Then, simply create those additional views. That way, your code is still neatly broken into specific views, which can have the appropriate model declaration. This view basically just becomes a proxy that routes to the right one.

Does a model need to be explicitly passed to a view if the model is strongly bound to the view?

I have an example from a project I'm working on in which a particular model is passed on to the view from the controller, like this:
result = View(stu) //stu is an object of type Student
//
//
return result;
In that particular view, at the top I have #model Project.Models.Student and I have textboxes which bind the information entered to the model. However, in another controller I have another method that has the following code:
//
//
result = View();
//
and the view for this has #model.Project.Models.Login, but I can still bind things to the model from this view just like in the other view (eg, I have something like:
#Html.TextBoxFor(model => model.login_name, new { maxlength = "30" })
I didn't pass a model to the view like I did in the first method, and yet it seems to have the same functionality. If I am using #model at the top of the view, does that mean that it is not necessary to explicitly pass a model object as a parameter from the controller method?
If you declare #model at the top of your cshtml page, then your page expect to get model of the type you have declared. Of course you can choose not to use a model in your page, and in this situation your declare is useless.
In addition you can declare a model, but don't send any object to the view.
If you send an object, it must be the same type as you declare in #model.

ASP.NET MVC Html.Editor pass model to Editor Template

I have an Editor Template called "Address.cshtml" that has a model defined as:
#model Acme.Models.Address
In a View I want call the Editor Template and pass a local variable of the same type, and define the name it will use for the variables, I've tried a number of things including:
#Html.Editor("address", "Address", new { Model = address })
How do I pass the model?
Note, I cannot use #Html.EditorFor() because the view uses a different model.
The only purpose of EditorFor is to work with your view's model. If you need to work with a completely different class instance that's not your view's model or accessible through you're view's model. Then just use Html.Partial. They're functionally the same. If you're worried about using a specific editor template, you can always pass the full path to the view to Html.Partial.
In a view (in its header or somewhere else, but before the row you are calling your Html.Editor) you can add the model in the ViewData with the key equals to your Html.Editor's expression and it will be used as a model in your called editor. For example:
#{
var address = new Acme.Models.Address();
ViewData["address] = address;
}
#Html.Editor("address", "Address")

Rendering strongly-typed partial view with a different model

I have two views:
1) Register – primary view for creating user account
2) Category – partial view for adding category dynamically if it's not there in a register view combo field.
The Category view is shown as jQuery dialog when user click on Add Category while registering. This view shows fields required to make up a new category like name and description. For this reason, it has a separate model.
On get page everything works fine, however on post, if there's some validation error, the page needs to reload with user provider values for making correction, instead it throws following error:
Exception Details: System.InvalidOperationException: The model item passed into the dictionary is of type 'Delight.Models.User', but this dictionary requires a model item of type 'Delight.Models.Category'.
I thought that using the following statement might be causing this problem (since it doesn't specify the model object to use for partial view):
#Html.Partial("CreateCat")
However, resorting to the following overload didn't solve the problem either:
#Html.Partial("CreateCat", null, null)
Above the second parameter (with null value) represents the model object.
However, unexpectedly following solved my problem:
#Html.Partial("CreateCat", new Category(), null)
Why is empty object working in this case but null isn't?
Is there any other better way to render strongly-typed partial view with different model type.
Unless you want to use the parent's model or no model, you should always pass in the appropriate model for a partial view. Passing in null is silly, if you don't want an instantiated model in your partial view then why would your partial view use a model at all? In this instance, I think new Category() is the correct choice. However, I've always seen sub models passed into partials
#Html.Partial("CreateCat", Model.Category)
something about needing to do what you're doing seems strange, but I'm not certain how you're using the partial view.

Categories

Resources