I have a few different styles/templates on my site. These templates are all used for compositions all over my site. Here's an example of my Document Types:
Layouts (folder)
Style 1
Style 2
Style 3
Products (folder)
ProductsPage
Product
News (folder)
NewsOverview
NewsPage
That's basically what it looks like. All of these have templates except for Product and NewsPage, but they have Style X as compositions. Here is what my content nodes looks like:
Home
Products
Product 1 (Style 2)
Product 2 (Style 3)
Product 3 (Style 2)
Product 4 (Style 1)
News
Article 1 (Style 1)
Article 2 (Style 3)
and so on. You get the point? The Style X document types are all compositions, so I don't have to style the same page over and over again, but I can still create any style of page I want.
Now, on my parent (for example NewsOverview), I would like to access the properties of the children. Inside the NewsOverview template file, I would then have to do this:
#foreach(var article in Model.Content.Children) {
dynamic image = article;
<img src="#image.OverviewImage[0].Url" />
<p>#article.GetPropertyValue("overviewTitle")</p>
}
I cannot access the properties without using strings or casting to dynamic (basically), although my models are set to Dll and I usually can do Model.Content.PROPERTY with intellisense and so on.
How can I achieve this? How can I access the properties without using dynamic? I understand that the children aren't necessarily all the same, but all my styled pages contains the same properties, they're just arranged differently in the template.
There's a method called Children<T>() that gets all the child documents of a certain type and can thus safely be cast in a foreach:
#foreach(Article article in Model.Content.Children<Article>()) {
<img src="#article.OverviewImage.First().Url" />
<p>#article.OverviewTitle</p>
}
You'll probably want to add some logic around article.OverviewImage.First() as if there is no value for OverviewImage it will throw a null reference exception.
Have you added your parent model to the template?:
#inherits UmbracoViewPage<ContentModels.Product>
#using ContentModels = Umbraco.Web.PublishedContentModels;
You probably need to cast the children to the specific type:
#using ContentModels = Umbraco.Web.PublishedContentModels;
#foreach (var article in Model.Content.Children.Select(child => new ContentModels.NewsPage(child)) {
<img src="#article .OverviewImage.First().Url" />
<p>#article.OverviewTitle</p>
}
.Children() just gets children of type IPublishedContent, because the ModelsBuilder has no idea which types of documents can exist under the current page.
Related
I have a select field to choose the department. I want to implement a view that displays the list of employees working in that department. I want to display both the select field and list of employees in the same page(view). How is it possible to send the selected field parameter to the same controller and update the list of employees object and display the list in the same page.
There are three main parts to a partial page update. I will give you a general overview of how each part is composed with some examples. This should get you started on the right path. I'm having to make lots of assumptions since your question is light on details. However you should be able to take this information and write your won implementation.
Part 1 (Making the request)
This involves monitoring the select list for a change and sending the value of the selected option to the controller. JQuery is well suited for this. I am going to pretend that the select list has an id of "departmentId" and we want to put the contents of the employee list into an element with the id of "displayList".
<script type='text/javascript'>
<!--
(function() {
$("#departmentId").on("change", function() {
$.get("${g.createLink(controller: 'employeee', action: 'listForDepartment')}/"+$(this).val(), function(data) {
$("#displayList").html(data);
});
});
})();
// -->
</script>
Part 2 (Fulfilling the request)
The second part is our controller code for getting the list of employees. This is just an example of what it might look like. Notice that we are going to render a template instead of a view. This is very important because we don't want Grails (Sitemesh) to apply any layout to the results.
class EmployeeController {
...
def listByDepartment() {
def model = [:]
model['department'] = Department.get(params.id)
model['employees'] = Employee.findAllByDepartment(model['department'])
render template: 'employeeListForDepartment', model: model
}
...
}
Part 3 (Displaying the results in a template)
Finally, our template grails-app/views/employee/_employeeListForDepartment.gsp is going to display our employees for the department. Since we used the employee controller the template is inside the employee views and all templates begin with an underscore.
<h1>Employees for ${department.name}</h1>
<ul>
<g:each in="${employees}" var="employee">
<li>${employee.name}</li>
</g:each>
</ul>
Of course, the details of your implementation my be very different but the overall concept should be the same. This just touches on the main part of this and leaves a lot of details out, such as spinners, canceling requests, and such.
This is rather baffling. Imagine a Company entity with an .Employees enumerable property, for the sake of simplicity. I've seen elsewhere on SO that the trick to getting EditorTemplates to render enumerables sensibly is to use syntax like this:
In Index.cshtml:
#Html.EditorFor(company => company.Employees, "EmployeeEditorTemplate")
EmployeeEditorTemplate.cshtml expects a single employee:
#model MyNamespace.Models.Employee
//...
#Html.EditorFor(x => x.FullName)
// ...etc.
Posts like this one: Viewmodels List Is Null in Action ...indicate that the modelbinder is smart enough to figure out the binding and index the enumerable on the fly. I'm getting different results (exactly what I'd expect if the modelbinder wasn't supposed to be so mageriffic):
The model item passed into the dictionary is of type
System.Collections.Generic.List`1[MyNamespace.Models.Employee]',
but this dictionary requires a model item of type
'MyNamespace.Models.Employee'.
Enumerating it myself renders the collection just fine, but emits the same id for every row's controls (which is less than optimal, of course, but it tells me the EditorTemplate is functionally correct):
#foreach (var item in Model.Employees)
{
#Html.EditorFor(x => item, "EmployeeEditorTemplate")
}
This construct also fails to post the company.Employees collection back to my other controller action.
Any ideas on what's required to achieve the following?
Render the child collection with unique Ids per instance in the list
Post the child collection back with the model
I don't care if I have to enumerate it myself, nor whether it's inside or outside the EditorTemplate; I've just seen it said that this is unnecessary and that MVC works better if you let it handle things. Thanks.
Per #David-Tansey (from this answer - see for a much more detailed explanation):
(changed to suit this question):
When you use #Html.EditorFor(c => c.Employees) MVC convention chooses the default template for IEnumerable. This template is part of the MVC framework, and what it does is generate Html.EditorFor() for each item in the enumeration. That template then generates the appropriate editor template for each item in the list individually - in your case they're all instances of Employee, so, the Employee template is used for each item.
To sum up his explanation on when you use the named template, you are, in effect, passing the entire IEnumerable<Employee> to a template expecting a single Employee by using #Html.EditorFor(company => company.Employees, "EmployeeEditorTemplate").
note: I really only answered this because it had no answer and I stumbled here first. At least now someone doesn't close it and potentially miss an answer without having to go through the rigmarole of getting duplicate question votes, blah blah.
You can read about it here: Hanselman's article
In short, you should write in your view (index.cshtml):
int i=0;
#foreach (var item in Model.Employees)
{
#Html.TextBox(string.Format("Model[{0}].FullName", i), item.FullName)
i++;
}
foreach can be used with #HTML.EditorFor, for an example see below syntax:
#foreach(var emp in #Model)
{
#Html.EditorFor(d => emp.EmployeeName)
#Html.EditorFor(d => emp.Designation)
<br />
}
I have been struggling with my customization of EditorForModel and the naming of HTML elements emitted by my code and the built-in MVC3 helpers. My code is very simple, and is clearly missing some subtleties, like naming the the rendered elements properly.
I am looking for advanced resources that can help me hone this area of my current development, especially with a view to subdividing a main view model across smaller sub-models, so that I can apply say three EditorForModel calls in one view, to split generated model editors across form columns or tab pages.
My current 'override' of the default EditorForModel template is as follows:
#{
// TODO Filtering for subsets of model without having to bind separate models.
var properties = ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForEdit && !pm.IsComplexType && !ViewData.TemplateInfo.Visited(pm));
}
<fieldset>
<legend>#ViewData.ModelMetadata.DisplayName</legend>
<ul class="form-column">
#foreach (var prop in properties)
{
<li>
#{
if (prop.HideSurroundingHtml)
{
#Html.Editor(prop.DisplayName ?? prop.PropertyName)
}
else
{
#Html.Label(prop.PropertyName, (prop.IsRequired ? "* " : "") + (prop.DisplayName ?? prop.PropertyName))
#Html.Editor(prop.PropertyName)
}
}
</li>
}
</ul>
</fieldset>
I have copied and modified this code from the Object.ascx example template on this article on Brad Wilson's blog. What resources can I consult to enrich this to cater for as many scenarios as possible, in as rich a manner as possible?
Your template seems pretty good for a very generic editor. If I understand your question properly, you're looking for more ways to break up and filter your model properties.
One way to filter the model into subsets without having to create submodels would be to use attributes. You could create as many attributes as you want, and have them implement IMetadataAware. There you could add arbitrary properties to the ModelMetadata.AdditionalValues property bag, and have your editor templates inspect those values.
Alternatively you could implement your own custom ModelMetadataProvider that returns a custom ModelMetadata object that had whatever properties you wanted.
Either would allow you to simply annotate your model to define filter behavior.
Both these methods are described by who else, Brad Wilson, in this blog post.
So, the title should speak for itself.
To create re-usable components in ASP.NET MVC, we have 3 options (could be others i haven't mentioned):
Partial View:
#Html.Partial(Model.Foo, "SomePartial")
Custom Editor Template:
#Html.EditorFor(model => model.Foo)
Custom Display Template:
#Html.DisplayFor(model => model.Foo)
In terms of the actual View/HTML, all three implementations are identical:
#model WebApplications.Models.FooObject
<!-- Bunch of HTML -->
So, my question is - when/how do you decide which one of the three to use?
What i'm really looking for is a list of questions to ask yourself before creating one, for which the answers can be used to decide on which template to use.
Here's the 2 things i have found better with EditorFor/DisplayFor:
They respect model hierarchies when rendering HTML helpers (e.g if you have a "Bar" object on your "Foo" model, the HTML elements for "Bar" will be rendered with "Foo.Bar.ElementName", whilst a partial will have "ElementName").
More robust, e.g if you had a List<T> of something in your ViewModel, you could use #Html.DisplayFor(model => model.CollectionOfFoo), and MVC is smart enough to see it's a collection and render out the single display for each item (as opposed to a Partial, which would require an explicit for loop).
I've also heard DisplayFor renders a "read-only" template, but i don't understand that - couldn't i throw a form on there?
Can someone tell me some other reasons? Is there a list/article somewhere comparing the three?
EditorFor vs DisplayFor is simple. The semantics of the methods is to generate edit/insert and display/read only views (respectively). Use DisplayFor when displaying data (i.e. when you generate divs and spans that contain the model values). Use EditorFor when editing/inserting data (i.e. when you generate input tags inside a form).
The above methods are model-centric. This means that they will take the model metadata into account (for example you could annotate your model class with [UIHintAttribute] or [DisplayAttribute] and this would influence which template gets chosen to generate the UI for the model. They are also usually used for data models (i.e. models that represent rows in a database, etc)
On the other hand Partial is view-centric in that you are mostly concerned with choosing the correct partial view. The view doesn't necessarily need a model to function correctly. It can just have a common set of markup that gets reused throughout the site. Of course often times you want to affect the behavior of this partial in which case you might want to pass in an appropriate view model.
You did not ask about #Html.Action which also deserves a mention here. You could think of it as a more powerful version of Partial in that it executes a controller child action and then renders a view (which is usually a partial view). This is important because the child action can execute additional business logic that does not belong in a partial view. For example it could represent a shopping cart component. The reason to use it is to avoid performing the shopping cart-related work in every controller in your application.
Ultimately the choice depends on what is it that you are modelling in your application. Also remember that you can mix and match. For example you could have a partial view that calls the EditorFor helper. It really depends on what your application is and how to factor it to encourage maximum code reuse while avoiding repetition.
You certainly could customize DisplayFor to display an editable form. But the convention is for DisplayFor to be readonly and EditorFor to be for editing. Sticking with the convention will ensure that no matter what you pass into DisplayFor, it will do the same type of thing.
Just to give my 2c worth, our project is using a partial view with several jQuery tabs, and each tab rendering its fields with its own partial view. This worked fine until we added a feature whereby some of the tabs shared some common fields. Our first approach to this was to create another partial view with these common fields, but this got very clunky when using EditorFor and DropDownListFor to render fields and drop downs. In order to get the ids and names unique we had to render the fields with a prefix depending on the parent partial view that was rendering it:
<div id="div-#(idPrefix)2" class="toHide-#(idPrefix)" style="display:none">
<fieldset>
<label for="#(idPrefix).Frequency">Frequency<span style="color: #660000;"> *</span></label>
<input name="#(idPrefix).Frequency"
id="#(idPrefix)_Frequency"
style="width: 50%;"
type="text"
value="#(defaultTimePoint.Frequency)"
data-bind="value: viewState.#(viewStatePrefix).RecurringTimepoints.Frequency"
data-val="true"
data-val-required="The Frequency field is required."
data-val-number="The field Frequency must be a number."
data-val-range-min="1"
data-val-range-max="24"
data-val-range="The field Frequency must be between 1 and 24."
data-val-ignore="true"/>
#Html.ValidationMessage(idPrefix + ".Frequency")
... etc
</fieldset>
</div>
This got pretty ugly so we decided to use Editor Templates instead, which worked out much cleaner. We added a new View Model with the common fields, added a matching Editor Template, and rendered the fields using the Editor Template from different parent views. The Editor Template correctly renders the ids and names.
So in short, a compelling reason for us to use Editor Templates was the need to render some common fields in multiple tabs. Partial views aren't designed for this but Editor Templates handle the scenario perfectly.
Use _partial view approach if:
View Centric Logic
What to keep all _partial view related HTML in this view only. In the template method, you will have to keep some HTML outside the Template View like "Main Header or any outer border/settings.
Want to render partial view with logic (From controller) using URL.Action("action","controller").
Reasons to use Template:
Want to remove ForEach(Iterator). Template is well enough to identify Model as a list type. It will do it automatically.
Model Centric Logic. If multiple views are found in the same displayfor Template folder, then rendering will depend on Passed Model.
Another difference that hasn't been mentioned so far is that a partialview doesn't add model prefixes while a template does
Here is the issue
I have a product treeview that is referenced in multiple views and controller. The treeview items of the product treeview are loaded dynamically using AJAX and a public Action method.
Should i move the product treeview's logic and public action method to a shared controller such as SharedController? What do you recommend?
burnt1ce,
as ever, it depends... If you always use it via ajax (jquery or msajax?? [not that it matters much, but would allow you to add the appropriate tag to the question]), then I would be tempted to refactor it out to an html.helper with a few overloads to allow different product models to be loaded. (I would recommend using product interfaces, rather than concrete classes to allow for a variety of product sub-classes if required)...
If you ever need to load it in the context of a view, then you could keep it where it is and load it via an html.RenderAction() method.
this would certainly be my initial thoughts.
A ProductController with the action to retrieve your product data (returns JSON?)
Use a Partial View to spell out the Telerik View. I assume from that view you'll be making the ajax call to get the products then updating the treeview w/ that data?
<%= Html.Telerik().TreeView()
.Name("TreeView")
.Items(item =>
{
item.Add()
.Text("Mail")
.ImageUrl("~/Content/PanelBar/FirstLook/mail.gif")
.ImageHtmlAttributes(new { alt = "Mail Icon" })
.Items(subItem =>
{
...