Issue with iterating using DescendantsOrSelf - razor

I just recently upgraded Umbraco from 4.7.2 to 7.1.9 and now in the process of slowly converting all legacy macroscripts to partial view macros. I have come across a few issues when using DescendantsOrSelf to iterate through nodes.
I have a macro that generates the side menu for my site (intranet). With version 4 the macro worked as expected on the whole site displaying the appropriate menu on the homepage and different side menu's on the child pages.
After the upgrade the below condition:
var model = GetParentSideMenu(CurrentPage);
#if (CurrentPage.AncestorsOrSelf("umbSomePageType").Where("Visible").First().HasValue("PageName") && CurrentPage.AncestorsOrSelf("umbSomePageType").Where("Visible").First().Id != model.Id)
{ ... }
#functions
{
public dynamic GetParentSideMenu(dynamic model)
{
if (model.Level > 1)
{
do
{
if (model.umbSideMenuLinks.Count() > 0)
{
return model;
}
if (model.Level > 1) {
model = model.Up();
} else { break; }
} while (model.Up() != null);
return model;
}
else return model;
}
}
Generates the following error when rendered on the homepage:
System.InvalidOperationException {"Sequence contains no elements"}
Inner Exception is null
The understanding here is that the page being rendered is not "umbSomePageType" so this condition should be false and move on but instead it throws the above exception.
The macro works fine when rendered on a "umbSomePageType" page but as the user is allowed to have further sub pages of a another type under "umbSomePageType" I have to manually check the "DocumentTypeAlias" and make sure the other if statements checking for that type of sub page are not executed because I get the same error as above.
Another issue I am facing is this doesn't return an iterable collection when it used to before in v4:
#if (model.DescendantsOrSelf("umbSideMenuLinks").Where("Visible").Count() > 0)
{
foreach (var item in model.DescendantsOrSelf("umbSideMenuLinks").Where("Visible").First().Children)
{ ... }
.... }
The if condition returns true but the foreach is unable to get any elements to iterate through.
Any help here will be greatly appreciated.
Thank You.

I was able to find a solution to the first problem I specified above. The error was occurring in the "if" condition due to the "CurrentPage" being a dynamic object, "FirstOrDefault()" needs to be used instead of "First()".
The second issue still stands and to further detail that issue if you have the following directory structure:
Root Folder/Homepage
- Second Level Folder
-- SideMenuLinks (umbSideMenuLinks)
-- SomePage...
- SideMenuLinks (umbSideMenuLinks)
In the above case if I am on the "HomePage" and I want to render the "SideMenuLinks" pertaining to the homepage and I use "DecedantOrSelf" it will go from the root folder to the second level folder and to the "SideMenuLinks" instead of first checking it "Self" which is the behaviour I desire. This is something that worked in Umbraco v4 but in v7 it drills into the sub directories first.
Maybe if I reorder/sort the SideMenuLinks so they appear before the "Second Level Folder" ?
Haven't tried that yet.
UPDATE: So I just tried the sorting and if I sort the tree this way:
Root Folder/Homepage
- SideMenuLinks (umbSideMenuLinks)
- Second Level Folder
-- SideMenuLinks (umbSideMenuLinks)
-- SomePage...
It starts to work. In the future we will have to create the page structure this to make sure that the correct SideMenuLinks are hit.

Related

Can't return data from Content Picker in Umbraco 7.6.4

I am currently trying to output data from the new Multinode Treepicker in Umbraco 7.6.4 here is my current setup and code:
Doctype
Content Node with 'Page' Doctype
Code to output the names of the selected nodes:
#{
IPublishedContent typedContentPicker = Model.Content.GetPropertyValue<IPublishedContent>("sections");
if (typedContentPicker != null)
{
<p>#typedContentPicker.Name</p>
}
}
This I took from the official Umbraco Documentation and adapted it to my project. This code is in a template with the 'page' doctype.
Currently the above code does not output anything to my page, I am expecting to see a list of nodes displayed on the page, can anyone see what the issue is or where I am going wrong?
Dumb moment, I was looking at the documentation for a content picker and not a multi-node tree picker!
Correct code is:
#{
var typedMultiNodeTreePicker = Model.Content.GetPropertyValue<IEnumerable<IPublishedContent>>("sections");
foreach (var item in typedMultiNodeTreePicker)
{
<p>#item.Name</p>
}
}

Show different default page depending on stored value

I am trying to make an windows store app where the default page (first page that comes up when app loads) changes depending on stored value.
I have following files
- js
|- default.js
- default.html
- page_A.html
- page_B.html
default.js has the following code:
if (localStorage["value"] == undefined || localStorage["value"] == "pageA") {
localStorage["value"] = "pageA";
//WinJS.Navigation.navigate("page_A.html");
window.location.assign = "page_A.html";
} else {
localStorage["value"] = "pageB";
//WinJS.Navigation.navigate("page_B.html");
window.location.assign = "page_B.html";
}
WinJS.Navigation code does not work at all. So I tried using window.location and what's happening is instead of loading the actual page, it loads an empty page as shown below.
I tried using both href and assign for windows.location object. What's interesting is that it seems like href and assign loads the page because if I have page_A/B.js associated with pageA/B.html and have a simple console.log statement, then the log statement does get logged, but it does not render the page.
Any ideas? I've been stuck for a while.
Try putting your default.js at the root of your project, next to page_A.html and page_B.html, or, and I don't know if this works, you can try calling those pages with ..\page_X.html.
Also, you can add an error handler function to your navigate in case there's something else going on that you're not seeing.
WinJS.Navigation.navigate('page_A.html', {}).then(function () {
// it worked!
}, function (err){
// something went wrong
});

generating page title with razor script - umbraco

So I am trying to create a script whereby depending on the document type of the page a certain pre-defined title tag format will appear, if there is nothing already written in an overwriting custom title input. I have inserted the macro within the title tag on my master template but keep on getting an Error loading Razor Script message .
Html
<title>
<umbraco:Macro Alias="NewPageTitle" runat="server"></umbraco:Macro>
</title>
Script -
#inherits umbraco.MacroEngines.DynamicNodeContext
#using umbraco.MacroEngines
#{
if(String.IsNullOrEmpty(#Model.tabName.ToString()) == false )
{
#Model.tabName
}
else if(#Model.DescendantsOrSelf("Country"))
{
<text>
Holidays in #Model.Name
</text>
}
else
{
#Model.Name;
}
}
Any help would be greatly appreciated.
Try this code out. The problem with your original code is that you were using "#Model.DescendantsOrSelf("Country")" as a boolean, and it is a list. I also removed your comparison for if(String.IsNullOrEmpty(#Model.tabName.ToString())).
Also, if you add ?umbDebugShowTrace=true to the end of your URL, you can get some valuable debugging information. There is a Chrome Extension called "Umbraco Debug" that I use to quickly access that query string and information. You may find it useful.
#inherits umbraco.MacroEngines.DynamicNodeContext
#using umbraco.MacroEngines
#{
if(String.IsNullOrEmpty(#Model.tabName.ToString()))
{
#Model.tabName
}
else if(#Model.DescendantsOrSelf("Country").Count() > 0)
{
<text>
Holidays in #Model.Name
</text>
}
else
{
#Model.Name;
}
}
its very simple just add following code into your title tag
#Umbraco.Field("pageName")
will display pageName,you may also add custom properties from document type.
e.g. you have added new property like "metaKeywords" with value "html,javascript,xml",fetch that values as following way...
#Umbraco.Field("metaKeywords")
even you don't need to add custom properties in your model

Umbraco Querying from Macro Script?

Umbraco Version = 6.0.3
I'm trying to do some seemingly simple stuff in a macro scriptlet. Basically, I want to loop through all of the visible child content that is not a category:
#inherits umbraco.MacroEngines.DynamicNodeContext
#{
var subs = Model.Children.Where("Visible && DocumentTypeAlias != \"Category\"");
}
<span>Count: #subs.Count()</span>
#if (subs.Any())
{
<ul>
#foreach (var sub in subs)
{
<li>
#sub.Name
</li>
}
</ul>
}
If I take out the "Visible" portion of the where clause, it works correctly (with the exception of displaying content marked as hidden). I can also use "Visible" on it's own by removing the "DocumentTypeAlias", but then all visible content including categories are displayed.
I also tried using strongly typed queries #Model.Content.Children.Where(x => x.IsVisible() && x.DocumentTypeAlias != "Category") but I get an error about not being able to use lambda functions with dynamically typed content.
Ideas?
Two things:
The DynamicNode Where clause uses a parameter syntax.
Use NodeTypeAlias to check the document type.
Example:
var subs = Model.Children.Where("Visible && NodeTypeAlias != #0", "Category");
Here are a few Umbraco razor resources:
Umbraco 4.7 Razor Feature Walkthrough. It's a 8-part series and it's pretty informative. Don't be put off by the version reference, it's still valid for Umbraco 6.
Razor DynamicNode Cheat Sheet.

Grails 2.0.4 webflow "type mismatch" exception

I'm still pretty new to Grails and I'm developing an online survey. I decided to use web flow and I have been running into many issues. I'm trying to pass the survey id from the gsp page to the flow controller. This works perfectly fine on any other controller action but whenever I do it to the action for the start state of the flow I always get the same error. I've followed a tutorial in a text book that does this the EXACT same way and I'm running out of ideas.
here is the link from the gsp page:
<g:link controller="surveyPage" action="beginTest" id="${survey.id}">
${survey.surveyName}
</g:link>
and here is the flow with the start state
def beginTestFlow = {
showSurvey{
def survey = Survey.get(params.id)
on("cancel").to "cancelSurvey"
on("continueSurvey").to "nextQuestion"
}
cancelSurvey { redirect(controller:"surveyPage") }
}
it always throws the exception:
argument type mismatch on the line with
def survey = Survey.get(params.id)
I've also tried:
flow.survey = Survey.get(params.id)
or even:
flow.survey = Survey.get(session.survey.id)
always the same error. Also, I made sure class Survey implements Serializable. I've copied and pasted the same code into a different action with the same controller and it works flawlessly. Any ideas to what is different with the web flow?
You can't put code like that directly inside a state definition, you need to use an action state or an onEntry block
def beginTestFlow = {
showSurvey{
onEntry {
flow.survey = Survey.get(params.id)
}
on("cancel").to "cancelSurvey"
on("continueSurvey").to "nextQuestion"
}
cancelSurvey { redirect(controller:"surveyPage") }
}
The onEntry block will fire every time the showSurvey state is entered. If instead you want some logic to be run just once at the start of the whole flow (for example if some later transition might re-enter the initial state), you can use a flow-level onStart block instead:
def beginTestFlow = {
onStart {
flow.survey = Survey.get(params.id)
}
showSurvey{
on("cancel").to "cancelSurvey"
// ...
Ivo Houbrechts wrote an excelent tutorial about grails 2.0 webflow. You can read it here:
http://livesnippets.cloudfoundry.com/docs/guide/