I have a Taxonomy called Categories. In this taxonomy I have multiple levels of terms. Each term is a CategoriesTerm contenttype.
I have defined a custom razor template: Content-CategoriesTerm.cshtml, which is used when I click a CategoriesTerm on the frontend.
Now I want to display on that page all direct children (if any), but there is no property like Term.Children or something. How can I get the children of a term in the Razor view?
Check Taxonomy.cshtml and Orchard.Mvc.DisplayChildren. It goes like this:
var tag = Tag(Model, "ul");
IList<dynamic> items = Model.Items;
if (items.Any()) {
items[0].Classes.Add("first");
items[items.Count - 1].Classes.Add("last");
<div>
#tag.StartElement
#* see MenuItem shape template *#
#DisplayChildren(Model)
#tag.EndElement
</div>
#DisplayChildren could be done in Razor if you like:
public IHtmlString DisplayChildren(dynamic shape) {
var writer = new HtmlStringWriter();
foreach (var item in shape) {
writer.Write(Display(item));
}
return writer;
}
Related
2SXC 10.25.2 / DNN 9.3.2
I have a 2sxc module that uses a C# template with "list" enabled. I have a content type called "pathway" and inside that I have 2 entity picker fields for "first step sessions" and then "next step sessions". These entity pickers use a "session" content type. Inside each of those "session" content types I also have an entity picker for "speaker(s)". All in all, it's a setup that I have lists within lists within lists.
When I create the loops for each of the sublists, I can easily do that within the 1 C# template but it becomes repetitive, long, and unruly because there's so much c# code where I'm looping the same session template for different entity picker sections. So, I tried using the "Render sub-template" code to simplify the template - I created new sub templates and inserted them in - it seemed to work at first, however, the template started outputting all "session" items into each item in the list.
I suspect that the subtemplate somehow loses the context of the item that it's in so it's outputting everything. Is there something special I need to know about using subtemplates with for each loops? Do I have to include params and, if so, how do I do that?
EDIT to include code sample:
Here is a small, simplified version of the code I'm working with:
#foreach(var Content in AsList(Data)) {
<h2>#Content.Title</h2>
<h3>Lead Sessions</h3>
<div class="lead-sessions text-green">
#foreach(var item in AsList(Content.LeadSessions as object)){
<h4>#item.LeadSessionTitle</h4>
<p>#item.LeadSessionText</p>
}
</div>
<h3>Next Sessions</h3>
<div class="next-sessions text-green">
#foreach(var nextitem in AsList(Content.NextSessions as object)){
<h4>#nextitem.LeadSessionTitle</h4>
<p>#nextitem.LeadSessionText</p>
}
</div>
}
I want to make a subtemplate so I don't have to repeat the same code for the sessions loop. How could I simplify this template to use a subtemplate for looping the sessions within the lead-sessions and next-sessions?
So based on the modified question, it's a bit like this
#foreach(var Content in AsList(Data)) {
<h2>#Content.Title</h2>
<h3>Lead Sessions</h3>
#RenderPage("_inner.cshtml", new { Items = Content.LeadSessions })
<h3>Next Sessions</h3>
#RenderPage("_inner.cshtml", new { Items = Content.NextSessions })
}
Second file _inner.cshtml
#{
var items = AsList(PageData["Items"]);
}
<div class="next-sessions text-green">
#foreach(var nextitem in items){
<h4>#nextitem.LeadSessionTitle</h4>
<p>#nextitem.LeadSessionText</p>
}
</div>
Yep, you can just use RenderPage without params, or pass in params like in the blog app:
#RenderPage("shared/_Category Filter.cshtml", new { MobileView = true, FilteredCategory = filteredCategory })
See https://github.com/2sic/app-blog/blob/master/_List.cshtml#L25
Then the template can retrieve the values like
#{
var filteredCategory = PageData["FilteredCategory"];
}
See https://github.com/2sic/app-blog/blob/master/shared/_Category%20Filter.cshtml#L6
You can pass around any amount of values/objects like this.
You can also create helpers - and then call those helpers. Like this
https://github.com/2sic/app-news/blob/master/shared/_Helpers.cshtml#L24-L33
I have a Razor partial which displays my site navigation:
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
var home = CurrentPage.Site();
umbraco.NodeFactory.Node navigationSettingsNode = MySite.Umbraco.NavigationSettings;
dynamic navigationSettings = new umbraco.MacroEngines.DynamicNode(navigationSettingsNode.Id);
var settings = home.Children.Where("DocumentTypeAlias == \"Settings\"").First();
}
#if (navigationSettings.HasValue("topNavigation"))
{
<ul>
dynamic topNavigation = navigationSettings.topNavigation;
var topNavigation2 = settings.topNavigation;
<span>#topNavigation</span>
<span>#topNavigation2</span>
foreach(dynamic item in topNavigation)
{
<li>
#item.caption
</li>
}
</ul>
}
Initially I was looping through topNavigation2 items which worked fine and with no problem.
Now I'm looping through topNavigation items and it throws an error:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'char' does not contain a definition for 'link'
I don't want to use var settings anymore, I want to use only dynamic navigationSettings variable. In order to get the right node of navigationSettings I need to some operation and I don't fancy to paste the same code in every view I want to use it so I want it to be accessible from dll and available to use anywhere.
Also the navigationSettings node in my Umbraco is outside of main content tree so is not a child of Home.
Why isn't it working? Both
dynamic topNavigation = navigationSettings.topNavigation;
var topNavigation2 = settings.topNavigation;
produce the same json result and both are dynamic objects.
How to make it work correctly?
I'm using MVC 5.2.3
It looks like your topNavigation property is a string, and so when you call for each on it, it's iterating through the characters in the string.
Also, don't use NodeFactory, it's deprecated. You should be using IPublishedContent instead.
I'd use the strongly typed content objects instead of dynamic, as a) they're faster, and b) they're easier to work with.
Here's a great article explaining the different ways of getting content: https://24days.in/umbraco-cms/2015/strongly-typed-vs-dynamic-content-access/
Scenario: HTML snippets created in admin. These are accessed (by name) in a template dynamically, based on state of the template's model's fields.
I have a custom content type and content created. How can I access this content by name from cshtml when it is not part of the model?
Here is psuedo-code of what I want to do.
#{
string title = Model.Title;
string html = "";
if(title.Contains("widget-a")) {
html = GET_CONENT [widget-a].Body;
}
else if(title.Contains("widget-b")) {
html = GET_CONENT [widget-b].Body;
}
body = Model.Html + html;
}
#body
I don't want to attach new fields to the content item whose HTML I'm altering.
My final objective is don't have to write HTML like this:
<div id='counter'>
{{counter}}
</div>
<div>
<button
id="startButton"
on-click="{{start}}">
Start
</button>
<button
id="stopButton"
on-click="{{stop}}">
Stop
</button>
<button
id="resetButton"
on-click="{{reset}}">
Reset
</button>
</div>
I would like to know if it is possible to create a Polymer-element without using HTML. For example I tried this:
#CustomTag('tute-stopwatch')
class TuteStopWatch extends PolymerElement {
ButtonElement startButton,
stopButton,
resetButton;
#observable String counter = '00:00';
TuteStopWatch.created() : super.created() {
createShadowRoot()..children = [
new DivElement()..text = '{{counter}}',
new DivElement()..children = [
startButton = new ButtonElement()..text = 'Start'
..onClick.listen(start),
stopButton = new ButtonElement()..text = 'Stop'
..onClick.listen(stop),
resetButton = new ButtonElement()..text = 'Reset'
..onClick.listen(reset)
]
];
}
}
Previous code creates HTML and shadow root correctly, but it doesn't create the binding between the #observable counter and the text of the DivElement.
I know that this is caused because I am trying to create the shadow root after the element has been instantiated/created. So that I should create the template of the element in other place before the template has been bound with its observable.
You can write a manual data binding like this:
changes.listen((changes) {
for (var change in changes) {
if (change.name == #counter) {
myDivElement.text = change.newValue;
}
}
});
changes is a property of the Observable class, which PolymerElement mixes in. (This is difficult to see in the API reference, as it currently doesn't show a class' mixins or the mixed in properties and methods.)
Polymer seems to be mostly about enabling declarative html based bindings. It may be worth exploring using custom elements and shadow dom directly, as you're not really using polymer for anything in this example. To do this you need to change the class definition to:
class TuteStopWatch extends HtmlElement with Observable {
...
}
And register your element with document.register(). You also need to include the polymer.js polyfill for custom elements.
Basically what I'm trying to do is create a list of breadcrumbs. That list of dynamic (as you drill down to deeper pages the list of breadcrumbs grows) and most links have parameters. I've seen examples with MVCSiteInfo but a little confused as most of the examples I've seen focus on a static set of links with no parameters. I can't imagine this isn't a common problem so I was wondering what's the best way to accomplish this functionality.
Thanks in advance!
Sieg
I'd suggest you use the MVC Sitemap provider and the bread crumb trails from it. You will need to build a Dynamic Node Provider, but that's fairly straightforward - just follow the steps to use Dynamic Nodes
One of the tricks when building dynamic nodes is to make sure that you foreach across each node at each level, but add it to the nodes collection at the top.
var nodes = new List<DynamicNode>();
foreach (var eventCategory in eventCategories)
{
var node = new DynamicNode
{
Key = string.Format("{0}_{1}", "home_events", eventCategory.Name),
ParentKey = "home_events",
Title = pluralize.Pluralize(eventCategory.Name),
Description = eventCategory.Description,
Controller = "event",
Action = "category"
};
node.RouteValues.Add("slug", eventCategory.Slug);
nodes.Add(node);
foreach (var e in eventCategory.Events)
{
var eventNode = new DynamicNode
{
Key = string.Format("{0}_{1}", eventCategory.Name, e.Name),
ParentKey = node.Key,
Title = e.Name,
Controller = "event",
Action = "event"
};
eventNode.RouteValues.Add("categorySlug", eventCategory.Slug);
eventNode.RouteValues.Add("slug", e.Slug);
nodes.Add(eventNode);
}
}
and then it's just a case of putting the breadcrumbs in like this
Html.MvcSiteMap().SiteMapPath()
home > events > marathons > melbourne marathon