Umbraco Navigation - Partial View - asp.net-mvc

I have a True/False editor in my page doc type and I am using if to create the site navigation.
If topNavigation Checkbox is checked display item in the navigation
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
var root = Umbraco.TypedContentAtRoot().First();
var nodes = root.Children.Where(x => x.GetPropertyValue("topNavigation") != "True");
}
<ul class="nav navbar-nav">
#foreach (var page in nodes)
{
<p>#page.GetPropertyValue("topNavigation")</p>
<li class="#(page.IsAncestorOrSelf(Model.Content) ? "current" : null)">
#page.Name <span class="glyphicon glyphicon-chevron-down"></span>
</li>
}
</ul>
#*}*#
I can't seem to compare against a true value.
This shows everything -
var nodes = root.Children.Where(x => x.GetPropertyValue("topNavigation") != "True");
..and this show nothing
var nodes = root.Children.Where(x => x.GetPropertyValue("topNavigation") == "True");
Even though the checkboxes are checked.

You should able to use GetPropertyValue<bool>
var root = Umbraco.TypedContentAtRoot().First();
var nodes = root.Children.Where(x => x.GetPropertyValue<bool>("topNavigation"));

Related

ASP.NET Core MVC route based localization with areas

I have created a project in ASP.NET Core and wanted the language to be detected based on the url:
https://localhost:7090/en
If controllers and actions are used in the url, everything works as planned. However, when the registration or login page is called, it does not work (default asp.net identity registration page).
Works: https://localhost:7090/en/Home/Index
Does not work: https://localhost:7090/en/Identity/Account/Register
In the startup, I configured the following for MVC routing:
builder.Services
.AddLocalization()
.AddMvc(options => options.EnableEndpointRouting = false);
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = CultureHelper.GetSupportedCultures();
options.DefaultRequestCulture = new RequestCulturne("en");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
var provider = new RouteDataRequestCultureProvider
{
RouteDataStringKey = "culture",
UIRouteDataStringKey = "culture",
Options = options
};
options.RequestCultureProviders = new[] { provider };
});
builder.Services.Configure<RouteOptions>(options =>
{
options.ConstraintMap.Add("culture", typeof(LanguageRouteConstraint));
});
var options = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(options.Value);
app.UseMvc(routes =>
{
app.MapRazorPages();
routes.MapRoute(
name: "LocalizedDefault",
template: "{culture:culture}/{controller=Home}/{action=Index}/{id?}"
);
});
The language constraint is then used to set the CurrentCulture and CurrentUICulture.
Here is a code snippet for calling the login/register pages:
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Register">
#Language.register
</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Login">
#Language.login
</a>
</li>
I've tried pretty much everything I've found on Google, but nothing seems to work....
I just think knowing that it does not work because of the pages
[UPDATE]
I was able to get the url to be valid with the following code:
builder.Services
.AddLocalization(options => options.ResourcesPath = "Resources")
.AddMvc(options => options.EnableEndpointRouting = false)
.AddRazorPagesOptions(options =>
{
options.Conventions.Add(new LanguageRouteModelConversion());
});
public class LanguageRouteModelConversion : IPageRouteModelConvention
{
public void Apply(PageRouteModel pageRouteModel)
{
var selectorModels = new List<SelectorModel>();
foreach (var selector in pageRouteModel.Selectors.ToList())
{
var template = selector.AttributeRouteModel?.Template;
selectorModels.Add(new SelectorModel()
{
AttributeRouteModel = new AttributeRouteModel
{
Template = "/{culture}/" + template
}
});
}
foreach (var model in selectorModels)
pageRouteModel.Selectors.Add(model);
}
}
But i still don't know how to call the page properly
You said you have no Account folder in Identity directory. If so then how you do you expect register,login page router will work?
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<YourDbContextName>();
Then Scaffold Register, Login, LogOut page etc. After scaffolded, you will find a separate Account folder in Pages folder. and Your Account folder actually contains login,register page. It should resolve your issue.
builder.Services
.AddLocalization(options => options.ResourcesPath = "Resources")
.AddMvc(options => options.EnableEndpointRouting = false)
.AddRazorPagesOptions(options =>
{
options.Conventions.AddAreaFolderRouteModelConvention("Identity", "/", pageRouteModel =>
{
foreach (var selectorModel in pageRouteModel.Selectors)
selectorModel.AttributeRouteModel.Template = "{culture:culture}/" + selectorModel.AttributeRouteModel.Template;
});
});
This did the trick for me, i finally figured it out...
Add the culture param to the URL asp-route-culture=...
#{ var culture= System.Globalization.CultureInfo.CurrentCulture.Name }
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Register" asp-route-culture="#culture">
#Language.register
</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Login" asp-route-culture="#culture">
#Language.login
</a>
</li>

KnockoutJS with MVC Partialview

I am having problems persisting data from KO observableArray in a MVC Partialview...
I have a side navigation menu where one of the nodes is dynamically built using KOjs 'foreach', and this navigation menu should persist across the site. The menu is rendered ok on the first View page but when I navigate on other page (clicking on menu option or any way) the dynamic node is empty, although the observableArrays were fetched and loaded with the correct data.
It seems like the navigaition menu (which is a partial view) is not refreshing/reloading to render the menu nodes/options again.
Any help si much appreciated. TIA!
self.reports = ko.observableArray([]);
self.reportCategories = ko.observableArray([]);
self.getReports = function () {
App.Server.get("/.../reports/")
.then(function (vm) {
self.reports(vm.reports);
self.reportCategories(vm.categories);
});
};
self.init = function () {
self.getReports();
};
self.init();
<li>
<a class="level1" data-toggle="collapse" href="#report-submenu" aria-expanded="false" aria-controls="collapseExample">Reports</a>
<ul class="level1 collapse" id="report-submenu" data-bind="foreach: reportCategories">
<li>
<a class="level2 collapse" data-toggle="collapse" data-bind="text: label, attr: { href: '#' + value }"
aria-expanded="false" aria-controls="collapseExample"></a>
<ul class="level2 collapse" data-bind="foreach: reports, attr: { id: value }">
<li data-bind="if: category == $parent.categoryId">
<a class="level3" data-bind="text: menuName, attr: { href: reportName }"></a>
</li>
</ul>
</li>
Here's the other part of the code (a Nancy GET method):
Get["/"] = _ =>
{
var reportModel = new ReportModel();
var reports = reportService.GetList();
if (reports != null)
{
// Categories
reportModel.Categories = reports.Select(s => s.Category).Distinct().Select(c => new ReportCategoryModel()
{
CategoryId = c,
Label = c.TrimStart("Reports/".ToCharArray()),
Value = c.ToLower().Replace('/', '-')
}).ToList();
// Reports
reportModel.Reports = reports.Select(r => new ReportRecord()
{
MenuName = r.MenuName,
ReportName = r.ReportName,
Category = r.Category,
}).ToList();
}
return Response.AsJson(reportModel);
};

Problems with partialview data

I have a problem with a partial view. The first time when it is rendered everything is ok, but after that some data is loosed.
This is how my page should look: this is when the partial view is rendered the first time
but when I'm clicking on a category to check his subcategories, the image is null, it is not visible anymore. (only the name is visible)
This is my partial view:
#model IEnumerable<OnlineCarStore.Models.CategoriesVM>
<div class="container">
<div class="row">
#using (Html.BeginForm("SubCategories", "Product"))
{
<div class="list-group col-sm-3" style="width:280px;">
#{var selected = string.Empty;
if (#HttpContext.Current.Session["selectedCar"] == null)
{
selected = string.Empty;
}
else
{
selected = #HttpContext.Current.Session["selectedCar"].ToString();
}
foreach (var c in Model)
{
<a href="#Url.Action("SubCategories", "Product", new { selected = #selected, id = #c.ID, category = #c.CategoryName })" class="list-group-item">
<span> #c.CategoryName</span>
</a>
}
}
</div>
<div class="col-sm-9">
#foreach (var c in Model)
{
<div class="card-group" style="width:200px; display: inline-block">
<div class="card card">
<a href="#Url.Action("SubCategories", "Product", new { selected = #HttpContext.Current.Session["selectedCar"].ToString(), id = #c.ID, category = #c.CategoryName })" id="linkOnImg" class="card-group">
<img class="card-img-top center-block" src="#string.Format("../content/images/categories/{0}.jpg", #c.AtpID)" alt=#c.CategoryName style="padding-top: 5px">
<div class="card-text text-center">
<p class="category-card-title ">
<span class="text-muted">#c.CategoryName</span>
</p>
</div>
</a>
</div>
</div>
}
</div>
}
</div>
and this is the Subcategoris view, where the partial view is rendered second time:
<div class="container">
<div class="row">
#Html.Partial("/Views/Home/CategorieTypes.cshtml");
Here is the Product controller Subcategories method:
public ActionResult SubCategories(string selected, int id, string category)
{
List<CategoriesVM> listOfCategories = new List<CategoriesVM>();
var list = db.Categories.ToList();
var root = list.GenerateTree(c => c.ID, c => c.ParentId).ToList();
TreeItem<Categories> found = null;
var test = new TreeItem<Categories>();
foreach (var rootNode in root)
{
found = TreeGenerator.Find(rootNode, (n) => n.Item.ID == id);
if (found != default(TreeItem<Categories>))
{
test = found;
break;
}
}
foreach (var item in found.Children.ToList())
{
CategoriesVM categoryv = new CategoriesVM();
categoryv.ID = item.Item.ID;
categoryv.AtpID = item.Item.AtpID;
categoryv.Childrens = item.Children.ToList();
categoryv.CategoryName = item.Item.AtpName;//.Name;
listOfCategories.Add(categoryv);
}
SiteMaps.Current.CurrentNode.Title = selected + " " + category;
var tests = found.Children.ToList();
if (found.Children.ToList().Count == 0 )
{
return View("Index");
}
else
{
return View("SubCategories", listOfCategories);
}
}
I've checked in developer tool if the source for the image is correct, and although it is correct, the image is not showed:
Can you please help me in this problem? What I do wrong? Why the images don't appear after the first render of the partial view? Thanks in advance!
The path of the partial view is /Views/Home/CategorieTypes.cshtml and the path of the images is /Content/images/categories. In the partial view you are using ../content/images/categories/ as the path of the images which means that it will search for the path /Views/Content/Images/Categories which is invalid.
Remove the two dots in the src property and add a ~ so it will be like: ~/Content/Images/Categories/{img}.
or
Add one more ../ in order to go one level down to the directory like:
../../Content/Images/Categories/{img}

Encountered end tag "li" with no matching start tag error when putting li inside if statement

i am using asp.net MVC 5 and Visual studio 2013
and working on Razor view
the view is working fine without if statement around the < li > start
if i enclosed any < li > start, with an if condition statement i get this error
Parser Error Message: Encountered end tag "li" with no matching start tag. Are your start/end tags properly balanced?
#using TheodorHR_App.Models
<div id="tree_CadreGroupLevel" class="tree-demo">
<ul>
#{
TheodorHrEntities db = new TheodorHrEntities();
var nodes = db.Cadres.ToList();
foreach (var node in nodes)
{
Cadre root = new Cadre();
root.Id = node.Id;
if (#Model.RuleElementCadres.Select(e => e).Where(e => e.Cadre == node.Id).Count() > 0)
{
<text>
<li id="Cnode_#node.Id" data-jstree='{ "selected" : true }'>
</text>
}
else
{
<text>
<li id="Cnode_#node.Id">
</text>
}
#node.Name
<ul>
#{
var nodes1 = db.JobGroups.Where(jg => jg.CadreId == #node.Id).ToList();
foreach (var node1 in nodes1)
{
Cadre root1 = new Cadre();
root1.Id = node1.Id;
<li id="Gnode_#node1.Id">
#node1.Name
<ul>
#{
var nodes2 = db.JobGroupJobLevels.Where(jl => jl.JobGroup == #node1.Id).ToList();
foreach (var node2 in nodes2)
{
Cadre root2 = new Cadre();
root2.Id = node2.Id;
<li id="Lnode_#node2.Id">
#node2.JobLevel1.Name
<ul></ul>
</li>
}
}
</ul>
</li>
}
}
</ul>
</li>
}
}
</ul>
</div>
Update after first answer
doesn't work
Razor understand it as c# and tried to enclose it with double quotes doesn't work because the literal contains already doubles quotes then tried to replace " with \" this doesnt work because it doesn't give a meaning to the js Tree i am building
i found the solution elsewhere
i think there is an issue on adding server side code inside html tags like this
< li /* adding server code here leads in many inconvenient issues */ >
i found the solution by adding #:< / li > at the end of the li instead of just < / li >
Oh I Forgot to put the quotes around the attribute.
I think using a conditional operator might solve the issue.
#using TheodorHR_App.Models
<div id="tree_CadreGroupLevel" class="tree-demo">
<ul>
#{
TheodorHrEntities db = new TheodorHrEntities();
var nodes = db.Cadres.ToList();
foreach (var node in nodes)
{
Cadre root = new Cadre();
root.Id = node.Id;
<li id="Cnode_#node.Id" #(Model.RuleElementCadres.Select(e => e).Where(e => e.Cadre == node.Id).Count() > 0 ? "data-jstree='{ 'selected' : true }'" : "") >
#node.Name
<ul>
#{
var nodes1 = db.JobGroups.Where(jg => jg.CadreId == #node.Id).ToList();
foreach (var node1 in nodes1)
{
Cadre root1 = new Cadre();
root1.Id = node1.Id;
<li id="Gnode_#node1.Id">
#node1.Name
<ul>
#{
var nodes2 = db.JobGroupJobLevels.Where(jl => jl.JobGroup == #node1.Id).ToList();
foreach (var node2 in nodes2)
{
Cadre root2 = new Cadre();
root2.Id = node2.Id;
<li id="Lnode_#node2.Id">
#node2.JobLevel1.Name
<ul></ul>
</li>
}
}
</ul>
</li>
}
}
</ul>
</li>
}
}
</ul>

How to make dynamically Tree in asp.net mvc

I have a table called "Tabel_Items" in database with these fields: id, parent, and child:
I want to generate html tags such as these:
<ul>
<li>parent1
<ul>
<li>child1</li>
<li>child2
<ul>
<li>child21</li>
<li>child22</li>
</ul>
</li>
</ul>
</li>
<li>parent2
<ul>
<li>child3</li>
</ul>
</li>
</ul>
I get my items with a LINQ query and pass them to view:
public ActionResult Index()
{
DataClasses1DataContext db = new DataClasses1DataContext();
var items = from i in db.Table_Items
select i;
return View(items);
}
How can I loop through the "items" in view and make a Tree list out of them?
I want a lambda expression to select those rows that have "parentId==null" at first. I test a code like this, but has an error:
#foreach (var i in Model)
{
#Html.DisplayFor(x => i.ItemName.Where(i.ParentId==null));
}
I solved my problem.Thank for me:
<ul>
#foreach (var x in Model.Where(f => f.ParentId == null))
{
<li>
#Html.DisplayFor(f => x.ItemName)
<ul>
#foreach (var y in Model.Where(c => c.ParentId == x.Id))
{
<li>
#Html.DisplayFor(c => y.ItemName)
<ul>
#foreach (var z in Model.Where(c => c.ParentId == y.Id))
{
<li>#Html.DisplayFor(c => z.ItemName)</li>
}
</ul>
</li>
}
</ul>
</li>
}
</ul>

Resources