MvcSiteMapProvider on View side with razor get parents of current node - asp.net-mvc

I am using MVC Site Map Provider for creating some breadcrumbs
what i wanna do; creating breadcrumbs on view using razor
i would like to do some calls like shown below
<div id="navbar">
<div>YOU ARE HERE:
// There is no calls like this but you get the idea
#if (SiteMap.CurrentNode.HasParentNodes == true)
{
// I'd like to loop trough each parent till the RootNode
foreach (SiteMapNode Snode in SiteMap.CurrentNode.ParentNodes)
{
#Snode >>
}
} else {
// If there is no parent just show current node
#SiteMap.CurrentNode
}
</div>
<div>#DateTime.Now.Date.ToLongDateString()</div>
</div>
so how can i achieve this using Razor on View?

The #Html.MvcSiteMap().SiteMapPath() HTML helper already does this. It is a templated control that you can modify by editing the /Views/Shared/DisplayTemplates/SiteMapPathHelperModel.cshtml file, so basically you can get whatever HTML output you want.
If you still prefer to do it your way after knowing that, you can also do this with MvcSiteMapProvider.SiteMaps.Current.CurrentNode.Ancestors property (version 4 and up).

Related

cannot applybindings multiple times knockout in MVC partial view

Hi have a parent page in which i have used knockout js to bind model with html element.
Now i make a ajax call to receive a partialviewresult which i place it in a div conbtainer.
All works fine if use the inbuilt mvc model binding.
But when i go for knockout in my partial view as well. I get the errorcannot applybindings multiple times knockout in MVC partial view.
I have even tried using
ko.applybindings(new vm(),document.getelementbyId("div1"))
ko.applybindings(new vm1(),document.getelementbyId("div2"))
But still get the same error. Is it not possible to get the partial view result from the action method and use knockout in partial view ? I do not want hide the div in my parent page and get a JsonResult and bind it to my div element.
If you have the following (general layout):
<div id="parent">
content
<div id="partialTarget"></div>
</div>
and you've already applied your bindings to #parent, you have to clean #partialTarget before applying the viewmodel again. #partialTarget has already been bound from the first pass, so to apply the bindings to the loaded contents, you need to do something like this:
var reapplyBindings = function(element){
var vm = ko.dataFor(element);
if( vm ) {
ko.cleanNode(element);
ko.applyBindings(vm, element);
}
};
element.load(‘path/to/fragment.html’, function() {
//the [0] selector is needed to be sure we have an actual dom element, not the jQuery wrapper
reapplyBindings(element[0]);
//do whatever you’re already doing
});

Proper way to handle _Layout needing access to scope in .NET MVC

I am using angular with an existing .NET MVC application. All of our .cshtml views are based include a partial _Layout.cshtml. We have a left sidebar generated in this _Layout. Depending on the web route the content in that left bar will change.
Problem is at one point I need get and put information into the sidebar in _Layout from $scope. The only way I know to do this is to go into the layout and wrap it with a ng-app. Something like so:
_Layout:
#(ViewBag.HotList != null ? " ng-app=hotListApp" : "")
if (ViewBag.Hotlist != null)
{
<ul ng-controller="someCtrl" id="hotlist" class="hotlist">
</ul>
}
#RenderBody()
But this is messy I have tons of pages. I would have to do this ng-app decision for most my pages. Is there a better way to separate this? How have others conquered this issue?
We put our ng-app at the body tag level:
<body id="ng-app" ng-app="app">
This way you can interact with any of your UI elements wherever they may live. You may want to consider making your HotList into an Angular Directive. You could then put attributes on your directive that you can interact with in your controller for the sidebar. You directive could look like:
<div ng-controller="sidebarController"
<HotList data="myData" />
</div>
The sidebarController would be responsible for retrieving the data and assigning it to the $scope variable "myData". The logic inside your HotList controller would know how to render that data in an unordered list.

Using an #section inside a ChildAction to add additional scripts to a page

I've got a MVC View which is made up of a main view and some additional content added via #Html.Action.
In the additional content (which is a ChildOnlyAction) I want to be able to add some JS to the page, but I want to add it to the #RenderSection("Scripts") block which I've defined in the layout.
Can my Child Action's View use this:
#section Scripts {
//Add scripts
}
So far I haven't been able to get it to work, so if it doesn't what would be an alternative approach?
Sections do not work in partial views. You could use a conjunction of extension methods that I illustrated here: https://stackoverflow.com/a/9663249/29407
So in your _Layout.cshtml you will have at some location:
#Html.RegisteredScripts()
and then in your partial:
#{Html.RegisterScript("~/scripts/foo.js");}
I was willing today to create a global dialog that would open under some conditions, I needed the script to be at bottom of the page. As others have already mention, a #section inside a child action is not possible.
I had the same problem as you did, the solultion to use custom helpers and js files should work, but I don't like, because usually I operate the javascript with razor and files make the requests longer to load.
the solution at https://stackoverflow.com/a/9663249/29407 is valid if you like that, for me no thanks.
I came with a new solution that is clean, the problem if you analyze it is that we have one controller and a view with 2 parts that have to be injected at different position in the final result.
After my analysis I realize that we have 2 views but one controller that has to control them once per request, below is how I did it, I moved the javascript to a new view with same name endig with script.
XDialogController.cs
XDialog.cshtml
XDialogScript.cshtml
Then before returning the ActionResult from the child action method, one sets the model or values for the other view inside the TempData object.
for example:
[ChildActionOnly]
public ActionResult Popup()
{
// pass variable or model if you need it to script view.
TempData[TempDataKeys.ScriptXDialogModel] = new ModelScriptX();
// pass variable or model to regular view.
return PartialView("XDialog", new ModelX());
}
Inside your ...Script.cshtml file you can read the variable or model as you need.
for example:
#if((TempData[TempDataKeys.DisplayXDialog] as bool?) == true)
{
<script type="text/javascript">
...jquery functions ....
</script>
}
Remember that TempData can only be read only once, one can keep the value inside a variable inside the view.
To invoke my dialog in the layout page I do the following:
<body>
#RenderBody()
#Html.Action("Popup", "XDialog")
#Scripts.Render("~/Scripts/core")
#RenderSection("ExtraScripts", required: false)
#Html.Partial("XDialogScript")
</body>
I hope that can help anybody.

ASP.NET MVC - Is partial view the right place to check if model is null or empty?

I have the following partial view:
#model IEnumerable<Foo>
<div id="foo">
#foreach (var foo in Model)
{
...
}
</div>
If collection is null or empty, I'd like to display some user friendly message, otherwise I'd like to list all collection items. Shell I make that check inside partial view, or inside calling method? What the best practice in this case and why?
Thank you!
Yes, the partial view is the right place - the reason to use a partial view is so your page only needs the view name and a reference to the collection. If you add the IsEmpty logic to the top level page you lose that encapsulation.
I'm not 100% familiar with Razor syntax, but I would create UI helper for that. To keep View simple I use following "rules": if I ever get if statement or a loop then I'll create UI helper.
I have static class for each context. Let's say I have a music store.. then I would have class called AlbumHelper
public static class AlbumHelper : {possible inheritance\
{
public static string CreateAlbumList(Model model)
{
// TODO: create list here using technique you prefer
// <ul><li>empty</li></ul>
return string.Empty;
}
}
That one I would call using (remember to add namespace to your Web.config):
<%= AlbumHelper.CreateAlbumList(Model) %>
If it would be commonly used control then I would create extension, so that it would be created using this line.
<%= Html.AlbumList(Model) %>
Here is a link to short tutorial for creating extension

ASP.NET MVC: How to render a partial view on all but one view?

I have a partial view/user control called LogOnUserControl which I display in a side bar on my site (defined in Site.Master). I also have a separate LogOn view, which also renders the LogOnUserControl.
I don't want two instances of the LogOnUserControl in the LogOn view, because it's just plain confusing, so my current thinking is to include a condition such as
// Semi-pseudocode
if (!Request.IsAuthenticated) && View.Name != "LogOn")
in the LogOnUserControl.
This feels wrong, as the partial view now knows about the LogOn view. Also, I can't find out how to get the View's name, which reinforces the feeling that I'm doing something wrong! :-)
Edit: There is the further complication that the same partial view is used for both the LogOn view and the sidebar in Site.Master.
Have you considered using a different master page for your login View without the login partial in the sidebar? If you are concerned about duplication of html markup you could use nested master pages to avoid that issue.
On the master page wrap the content of the sidebar area with content area tags and give it an id like SideBarContentArea or something. What this does is create a new content area that you can choose to override on pages based of the master and specifies default content that will show up when you do not implement in on the child pages. Now on the login page all you have to do is override the SideBarContentArea and not include the login control this time.
Bada Bing!
You could store a flag in ViewData to indicate this. Whether you want to strong-type it or just access it directly is up to you. So on your master page you could have this:
<% if (ViewData["HideLogOnUserControl"] == "Y") { %>
Insert HTML here
<% } else { %>
Insert HTML here
<% } %>

Resources