Navigation Menu and Universal Viewer Webpart

0
Comments
2
Votes
Login to vote
Recently, I was tasked to help create multi-level main navigation within the master page of a website.  After a little investigation and finding that the CSS List Menu would not work for my implementation, I concluded that it would be the perfect opportunity to use either a Universal Viewer or a Universal Viewer with custom query; both of which I implemented with Hierarchical Transformations.
 
I. Universal Viewer
 
Add the Universal Viewer web part to your master page, set the appropriate content and content filtering properties (just as you would for a CMS Repeater) and then check the boxes for Load hierarchical data, Use default hierarchical order and make sure that the Hierarchical display mode is set to: Inner.  Select the 'OK' button and navigate to the Site Manager to define a new Hierarchical Transformation.
UViewer_webpart-(1).png
 
The Universal Viewer and Hierarchical Transformation provide the ultimate flexibility to display nested data that exists within the content tree.  The Hierarchical Transformation is basically a collection of Transformation Types that can be defined for each level (note: levels always start at zero and transformations are inherited from a parent level if not defined) and also for each Document Class Type.
 
For a navigation with two levels, define a item transformation, header transformation and footer transformation for each level.  Select the "New transformation" button, just as you would for any transformation. 
 
For HeaderTransformationZero:
<nav id="MainNavigation">
    <ul class="Menu0"> 
 
For FooterTransformationZero:
    </ul>
</nav>
 
For ItemTransformationZero:
<li class="MenuItem0">
<a href="<%# IfEmpty(Eval("DocumentMenuRedirectUrl"),GetDocumentUrl(),Eval("DocumentMenuRedirectUrl")) %>" <%# IfEmpty(Eval("DocumentMenuJavascript"),""," onclick=\""+Eval("DocumentMenuJavascript")+"\"") %>><%# IfEmpty(Eval("DocumentMenuCaption"),Eval("DocumentName"),Eval("DocumentMenuCaption")) %></a></li>
 
For HeaderTransformationOne:
<ul class="Menu1">
 
For FooterTransformationOne:
</ul>
 
For ItemTransformationOne:
<li class="MenuItem1">
<a href="<%# IfEmpty(Eval("DocumentMenuRedirectUrl"),GetDocumentUrl(),Eval("DocumentMenuRedirectUrl")) %>" <%# IfEmpty(Eval("DocumentMenuJavascript"),""," onclick=\""+Eval("DocumentMenuJavascript")+"\"") %>><%# IfEmpty(Eval("DocumentMenuCaption"),Eval("DocumentName"),Eval("DocumentMenuCaption")) %></a></li>
 
Select "New hierarchical transformation" on the Transformations tab.  Add all of the transformations by type and assign them to the appropriate level (remember to start at level zero).  Go back to your Universal Viewer web part and select your Hierarchical Transformation.
 
hierarchicalMainNav-(1).png
 
 
What should render is something like:
 
<nav id="MainNavigation">
    <ul class="Menu0"> 
         <li class="MenuItem0">
              <a href="[url]">[Name]</a>
         </li>
         <ul class="Menu1">
               <li class="MenuItem1">
                    <a href="[url]">[Name]</a>
               </li>
               <li class="MenuItem1">
                    <a href="[url]">[Name]</a>
               </li>
         </ul>
         <li class="MenuItem0">
              <a href="[url]">[Name]</a>
         </li>
    </ul>
</nav>
 
For my navigation, I needed to embed sub <ul> within their parent <li>. Go to each Item Transformation and remove the </li> closing tag.  
 
Create another transformation called SeparatorTransformationZero with just:
</li>
 
Add this transformation to your Hierarchical Transformation at the ZERO level (it will be inherited by all other levels without a Separator transformation).
hierarchicalMainNavWSeparator-(1).png
 
You navigation should now render like:
 
<nav id="MainNavigation">
    <ul class="Menu0"> 
         <li class="MenuItem0">
              <a href="[url]">[Name]</a>
              <ul class="Menu1">
                   <li class="MenuItem1">
                        <a href="[url]">[Name]</a>
                   </li>
                   <li class="MenuItem1">
                        <a href="[url]">[Name]</a>
                   </li>
              </ul>
         </li> 
         <li class="MenuItem0">
              <a href="[url]">[Name]</a>
         </li>
    </ul>
</nav>
 
Of course, you can customize your html attributes with any of the returned data for CSS purposes.

 
II. Universal Viewer with Custom Query
 
The Universal Viewer with Custom Query is ideal for data outside of the content tree, mixture of data inside/outside the content tree, or for just additional flexibility.  I will provide examples for the last two.
 
For a mixture of data inside/outside the tree, consider the following example:
 
I have a document type called Restaurant.  Restaurant is associated to States with a property called, "StateId."  StateId can be selected from a dropdown list that I populate using the CMS_State table.  I need to list out each State with Restaurants and also have the ability to implement different transformations.  
 
First, create a query for the Restaurant document type such as:
 
SELECT   StateID
	,1 AS ParentStateID
	,0 AS NodeLevel
	,StateID AS DocumentID
	,StateDisplayName AS Name
        ,'Foo.State' AS ClassName
        ,'Foo.State' AS NodeAliasPath
FROM CMS_State WHERE StateID IN (SELECT DISTINCT [StateID] FROM View_Restaurant_Joined WHERE ##WHERE##)
UNION
SELECT 
	 NodeId AS StateID
	,StateId AS ParentStateID
	,1 AS NodeLevel
	,DocumentID
	,DocumentName AS Name
        ,ClassName
        ,NodeAliasPath
FROM View_Restaurant_Joined INNER JOIN
	CMS_State ON CMS_State.StateID = View_Restaurant_Joined.StateID
WHERE ##WHERE##
(Note: Class names listed in Hierarchical Transformations do not have to be concrete document types.  Hence, Foo.State!)
 
Next, create a Hierarchical Transformation just as described above and add a Universal Viewer with Custom Query to your page template.  Select the Query and Hierarchical Transformation you created.  Fill out the Hierarchical settings and Extended settings as such:    
 
UniversalViewerQueryWebPartSetttings-(1).png
 
Done!
 
My next example is more of a Sql Server t-sql tip, but it works very well with the Universal Viewer with Custom Query web part.  Basically, it involves using Recursive Queries using Common Table Expressions.  You can read more about it here, but I will provide an example query.  I can create a 3-tiered navigation with this query:
 
WITH CTE_Nav as(
	SELECT treeAnchor.*
	FROM [View_CMS_Tree_Joined] treeAnchor
	WHERE treeAnchor.NodeSiteID = 1 and treeAnchor.NodeLevel = 1 and treeAnchor.DocumentMenuItemHideInNavigation = 0 AND
			treeAnchor.ClassName IN ('CMS.MenuItem','TEST.Section') AND treeAnchor.Published = 1
	UNION ALL
	SELECT treeOther.*
	FROM [View_CMS_Tree_Joined] treeOther 
	INNER JOIN CTE_NAV ON treeOther.NodeParentID = CTE_NAV.NodeId
	WHERE treeOther.NodeLevel > 1 and treeOther.NodeLevel < 4 and 
		treeOther.DocumentMenuItemHideInNavigation = 0 and 
		treeOther.ClassName IN('CMS.MenuItem','TEST.SubSection','TEST.SectionPage','TEST.Restaurant') AND treeOther.Published = 1
)

SELECT ##TOPN## ##COLUMNS##
FROM CTE_NAV
ORDER BY NodeLevel, NodeOrder
SELECT treeAnchor is the actual anchoring query that is only executed once.  SELECT treeOther is the looping query.  You could mess around parameterize-ing different parts to make it more reusable or turn it into a stored procedure.  Obviously, using the normal Universal Viewer web part is much less work.  But, if you're unable to do so, this is not a bad option.  

(note: No matter which node levels that are returned, your transformation levels should always start at zero.  For example, if my query returned data with node levels from 1 to 3, my transformation levels would still start at level zero.)
 
With any of these navigation tips, if you pair them with Josh Gipper's HTML5/WAI-ARIA compliant navigation developer tip, BOOM!  Life is good.
 
Posted by Jason Ellison on 2/22/2013 10:47:29 AM
Filed under: 7, CMS, HTML5, Kentico, Navigation
  
Comments
Blog post currently doesn't have any comments.