REMESQ
REMESQ

Reputation: 1220

Using model with multiple types and creating different EditorForModel templates

I am a bit confused about how to implement EditorForModel. I get the idea of setting up templates in Views\Shared\EditorTemplates, but I think I have over-researched (if that's possible) which has led to my confusion.

Basically, I am trying to minimize code replication. I have 5 services I provide to clients, and each service has between 4 - 6 different solutions. Making things more complex, there are certain types that can be shared among many of the solutions to varying degrees.

To make this simple, take the type:

public string FirstName { get; set; }

I will use this in every solution (and going up the "tree" in every service). But obviously I have numerous other types that will either be shared among a few solutions or none at all.

Let's say I have 100 types for each service. I could separate them out as different View Models, but then I would have to factor that by the 5 services. I would prefer to just keep them all in one View Model, per service.

My trouble comes in when I try to create the templates. I want to use the templates because I am using a wizard and I don't want to re-create a View for each part of the wizard in a particular solution especially if it's the same "data" (and, again, factoring in the amount of solutions I have).

So, I create a BasicDetails.cshtml View (with types for things like FirstName, LastName and Email), which can actually be used across all the solutions. An editor template seems ideal here, but my confusion arises because if I use ServiceViewModelOne.cs and do an @Html.EditorForModel(), I would either spit out all 100 types or, using a template, only spit out that which I want in BasicDetails.cshtml by creating a template at \Views\Shared\EditorTemplates\ServiceViewModelOne.cshtml.

Now, would I be able to, for example, do the following:

@Html.EditorForModel("BasicDetails")
@Html.EditorForModel("WizardStep2")
@Html.EditorForModel("WizardStep3")

for every custom template I wanted to make (and however many more I wanted to make), all using the same ServiceViewModelOne.cs? If I am correct, I would then have the following folder structure:

Obviously, within each template I would have the corresponding

<div class="editor-label">
    @Html.LabelFor(m => m.FirstName)
</div>
<div class="editor-field">
    @Html.EditorFor(m => m.FirstName)
    @Html.ValidationMessageFor(m => m.FirstName)
</div>
...

for all of the HTML inputs specific to that step in the wizard (which includes the entire HTML layout)

Would this be an appropriate way to do what I want, or am I barking up the wrong tree?

UPDATE: I thought about using UIHint, but I am not sure if it will work completely.

I can use UIHint at the model level:

[UIHint("BasicDetails")]
public class MyModel {}

or at the type level

public class MyModel
    {
        [UIHint("FirstName")]
        public string FirstName { get; set; }
    }

And I could create a MyModel.cs and then auto map some of the types in there into MyViewModelOne.cs, MyViewModelTwo.cs, etc.

However, I think I will wind up boxing myself in, so to speak.

Let's say I have Type1, Type2, Type3, Type4. Type1 can be used in every solution (keep it simple, lets say there are 4 solutions). Type2 and Type3 can be used in one solution, but not the others. And lets say that in another solution I can use Type2 and Type4.

Using UIHint or automapping means I'd have to create 3 different things to account for the above, and what if I need to use Type3 and Type4 in yet another solution.

I could be off base but it just seemed to restrictive forcing me to create multiple permutations, which is what I was hoping to avoid.

I will confess to not having used AutoMapper and am looking into whether or not that will help out.

Upvotes: 0

Views: 336

Answers (2)

REMESQ
REMESQ

Reputation: 1220

UPDATE (ANSWER) I figured out how to handle this and in case this is useful to others am posting an answer. For my purposes this helps out tremendously and opens up lots of possibilities while adhering to DRY (somewhat) because it's better to have one template than to have 6 files with the same fields.

I posted this question because I tried putting a template at \Views\Shared\EditorTemplates\BasicDetails.cshtml and was just getting all my properties (fields such as FirstName) returned, rather than the few that I wanted (FirstName, LastName, EMail). Ordinarily placing the template in the \Shared\ folder would be the right thing to do IF I had a model BasicDetails.cs (for example).

Reading the comments buried in Brad Wilson's Post, I realized that I should instead try putting the template in

\Views{CurrentController}\EditorTemplates\BasicDetails.cshtml.

This works to show the view AND validation errors pop up on "Required" fields AND the wizard goes through its steps after clicking either "Next" or "Submit"

To reiterate, I used

@Html.EditorForModel("BasicDetails")

where "BasicDetails" is the name of the template inside the Current Controller.

Upvotes: 0

RPM1984
RPM1984

Reputation: 73123

Its a bit confusing because of the complexity of your question, but i'll take a stab.

Editor Templates work off convention in two ways - the name of the file needs to match the name of the model, and the type of the template needs to match the type of the model.

So if you have multiple classes with different names, but you want to use a single template, it won't work off the bat.

I can see a couple of options.

  1. Use [UIHint] on your models to specify the name of the template.
  2. Create another layer between your services and presentation, where you map the models into viewmodels, that way the View doesn't need to care about rendering 100+ different classes. You could use something like AutoMapper to do this easily.

I would strongly advise going with option 2 (if possible). Again, not sure if i understand your question.

Upvotes: 1

Related Questions