Override EditorTemplate based on BeginForm - asp.net-mvc-3

I am using EditorTemplates to style all my input fields. Works like a charm, however now I want two themes of EditorTemplates, one for normal forms, and then one for my wizard forms.
I am already using an overloaded Html.BeginWizardForm() around those Html.EditorFor - but how do I make the MVC logic react on being inside Html.BeginWizardForm() ?

EditorTemplates are designed to be somewhat global. You can override them, though, just like any other view, because they are just views. For example, assuming you have something like Views\Shared\EditorTemplates\String.cshtml, you can then create a another view at Views\Foo\EditorTemplates\String.cshtml, and for any action called from FooController, the latter editor template will be used instead of the one from Shared. You might be able to make this work in your scenario if the wizard form is used in a specific controller or area context.
Short of that, though, there's no way to have this occur automatically. Some manual options still exist, though.
You can decorate the properties of the view model used within the context of the wizard with UIHint attributes. For example, assuming the same shared editor template above, you could do something like:
[UIHint("WizardString")]
public string Foo { get; set; }
That would cause it to look for Views\Shared\EditorTemplates\WizardString.cshtml instead.
You can pass the editor template to use in the call to EditorFor:
#Html.EditorFor(m => m.Foo, "WizardString")
All that said, the biggest problem here is that you seem to be violating a pretty core principal of good web design. HTML is about structure, not presentation. CSS is for presentation. As a result, if you want something to look different in a certain context, the correct approach is to apply different CSS. If things are designed well, your HTML shouldn't really have to change.

It seems is as stated by Chris Pratt not possible to have multiple EditorTemplates.
I however found a workaround by extending the MvcForm and created a WizardForm which adds a value to the ViewContext (in my case "wizardContext" => true) and on disposing setting wizardContext => false.
This allows me in the EditorTemplates to add a check for if I am inside or outside the wizardContext, which will propagate through the nested EditorFor, and in this way allow me to have different themes, without having to be specific in EditorFor.

Related

Durandal and multiple views using the same vm

I have an ADD and an EDIT page for a customer entity. The data to support each function is similar, however there are business rules that differ between the 2, and slightly different UI, so my original thinking is that I make 2 separate views, but use a single vm. This is a different approach than the John Papa example I'm using as my guide, as he had a separate vm for each. (sessionadd.js, sessiondetail.js). The data is identical so it seems like a lot of duplication, but maybe that's the way to go.
Two questions: what is the best practice in this scenario where the data for an add/edit is the same, but the rules are different? I can already see myself doing "if (mode == 'add'){ // stuff } else {// its an edit }. That bothers me a little, but I also don't like the idea of having to change 2 vms if I add a new field to the views.
Second question, can I specify the view as part of the route definition? I didn't see anything in the docs but I'm still new to the framework. In the following routes, I would like the first one to be loaded with custedit.html and in the second one custadd.html. Both using the custmaint.js vm (never at the same time tho).
{ route: 'custedit', moduleId: 'viewmodels/custmaint', title: 'Edit' },
{ route: 'custadd', moduleId: 'viewmodels/custmaint', title: 'Add' },
thanks
You can customize the view you want to be used by defining getView() or viewUrl() on your viewmodel as described here:
http://durandaljs.com/documentation/Hooking-Lifecycle-Callbacks.html
As to your initial question, if they are very similar, I would definitely combine edit and add operations within a single viewmodel and single view. Sharing the same viewmodel but splitting the views will likely result in a ton of duplicated view code. You could always decompose the elements of your view into smaller views if you need to simplify.
If the edit and add experience are different enough to warrant a separate view, I would create a separate viewmodel as well (and potentially look into splitting view parts and viewmodel functionality into smaller components)

How can I take better advantage of Entity Model validation?

I currently have:
#Html.EditorFor(model => model.PurchasePrice)
I would like to split this into 2 separate fields separated by a decimal (for price input obviously). But if I do that using basic text boxes I will loose the ability to take advantage of ASP.NET's validation.
Is there a way to do this, in Razor or by using attributes, so that I am able to keep the JS and server-side validation against my Entity model?
I can easily do it somewhere else by creating my own functions within the viewmodel, but I'm new to MVC3 and not entirely sure if that would be the best route or there is a simpler method.
Edit:
This is kind of the direction I am thinking, I do not fully understand how this works.
I set 2 fields, 1 as ppDollar and 1 as ppCents. In the controller I have:
modelname.PurchasePrice = Request["ppDollar"] + Request["ppCent"];
But, I can look at that and tell that's not going to work. So, I guess the question really is how is user input validated against the entity model and how can I better take advantage of the built in functionality?
You can create custom editors for particular types that are rendered by EditorFor. You can find a lot of examples of how to do this online, most of them focusing on a custom DateTime editor but the same idea applies to any type. Just one example from a quick search:
http://buildstarted.com/2010/09/10/overriding-displayfor-and-editorfor-to-create-custom-outputs-for-mvc/
In short, the process is:
Create a partial view template, placed in the Views\Shared\EditorTemplates folder, with the same name as the type (e.g. Decimal.cshtml).
The view should use, as its model, the type you want to display: #inherits System.Web.Mvc.WebViewPage<System.Decimal>
Make the view display whatever you want, using some field naming convention or whatever.
You can also pass HTML attributes via the appropriate EditorFor overload, referenced in your template through the ViewData.ModelMetadata.AdditionalValues property.
One thing to note: once you define an editor template it will be used for every call to EditorFor. You can scope them to a specific controller by moving the EditorTemplates folder into the appropriate view subfolder instead of the shared one.

Orchard CMS pass data from View to Theme layout

I'm writing a custom Orchard module with a custom Theme. I would like to pass data from the View back to the Layout to change the layout based on data determined in the View.
In my example, I have a left-nav in my theme - certain views should be able to instruct the layout not to render this left-nav.
In standard mvc 3 I would just pass the value up through the ViewBag, but this doesn't seem to be working within Orchard - I'm guessing that the layout code is executed before the View is rendered?
I've looked into using a Shape to move this data around but looks like it might be a little heavyweight for what i'm trying to achieve.
What's the best practice for passing data around like this as an alternative to ViewBag?
Update: After playing around with it a bit more i've just noticed that TempData is being picked up in the Layout - can anyone explain why TempData is transmitted, but ViewData isn't? And is it safe to use from an Orchard POV?
It's easier than that... All templates have access to the Layout shape, which is a dynamic object. This means that you can modify it on the fly, add it properties, etc.
In your specific case, suppressing a zone, you may even be able to just set that to null: zones are just shapes, and in the case of top-level zones they are expandos on Layout. So if you have a zone named Foo, setting Layout.Foo to null should do the trick. As a matter of facts, I'm doing exactly that in one of my themes, to suppress the side bars from my error pages without having to create a specific widget layer:
Layout.AsideFirst = null;
Layout.AsideSecond = null;

Partial View or HtmlHelper for displaying list of items

I have a model that contains an IEnumerable of a list of custom objects. Each item needs to be displayed with about 6 fields and an image. So, I won't be using a grid to display the items, rather a div and styling to achieve the look I want. With that said, I'm looking for the appropriate approach. In the book I have, Pro ASP.NET MVC 3 Framework by Adam Freeman and Steven Sanderson, they give an example of doing something similar in their Sports Store application, where for each item, they use this code,
#foreach(var p in Model.Products) {
Html.RenderPartial("ProductSummary", p);
}
Most other reading that I've done, and what seems to be a preferred approach to this, would be to use an HtmlHelper that does basically the same thing.
Which is preferred and why would I use one approach over the other?
Thanks
EDIT
I should have mentions that each of my items will be enclosed in it's own form and have a submit button. This may be the reason the authors of the book I mentioned used the partial view.
In my opinion, I would go the helper route if there is a chance that the code would be reused somewhere else. Could it be used on another page? Or in another project?
Something else to think about...
Helpers also help you to encapsulate view code so that you can keep your view clean and simple. How complex is that view? Would encapsulating some of the code assist in making the code easier to read and maintain?

With regards to Html helpers, does data access code go into the helper class too?

I am writing a helper class to query my Zenfolio feed, return and display the images. Right now this code is split between a viewmodel and code in my controller. I want to pack it up into a helper class. Would all the code go into the helper or do i still split the code among different class with the helper only responible for generating the html? I have googled but not found an answer to my question.
Within the MVC pattern there is a clear separation between Model (data), View (html) and Controller (what gives the Model to the View).
To answer your question, No. Load your models in your Controller. Display them in your View. Html Helpers should only generate html for your view.
You may want to consider using a DisplayTemplate, which allows you use the same View template for every model of a particular type.
I wouldn't do any data access from the view. This sounds like a good use case for an action, and reusing code via the RenderAction method. You can mark the action as a child action using the [ChildActionOnly] attribute, which ensures it can't be invoked directly from the HTTP request, and return a PartialView result.
HTML helpers should really be used to generate HTML tags from data taken from the ViewData or Model (i.e. your view model in this case).
Data access in an HtmlHelper is only pain.
I've had the misfortune to inherit a project that had ad-hoc SQL placed into the HtmlHelpers by the 2nd developer on a project. The HtmlHelpers were beautifully written by the first developer, and the ad-hoc SQL pretty much nullified all of the time and effort put into having an service oriented architecture, having an ORM (the 2nd level cache became worthless), the unit of work pattern(transactions, worthless), and every aspect of design. Eventually, this 2nd developer had to make larger and larger HtmlHelpers so that different elements could share access to the data.
This was originally done for a display mode, and editing was accomplished through a pile of ugly custom javascript. All told, when the page rendered, it made 600 synchronous calls to the database.

Resources