Umbraco - Returning all grandchildren - umbraco

I have a section on my site which has been split into categories and I am trying to build a page which has all of the the content under each category. I am however stuggling to get the right query to achieve this.
This is my structure:
Home
- Section
- Category 1
- Content
- Content
- Category 2
- Content
- Content
and this is what I have tried playing with but I think im getting the logic wrong
> var sectionContent =
> Model.Content.Site().Children("section").Children("category").Children("content").Where(x
> => x.IsVisible());
>
> #foreach(var item in sectionContent){ #item.name }
What I am looking to get is all the content under the section.
can someone please showing what I am doing wrong?

You are looking for Descendants(string nodeTypeAlias)
using Umbraco.Web;
var sectionContent = Model.Content.Site().Children("section").Descendants("content").Where(x => x.IsVisible());

Related

RAZOR variable in variable

Hi i have a little question about razor ...
I need to send an email with multiple article bought by a client
I made a for-loop to generate one line per article.
But each line need to show different name for each product
Example if the client bought 3 articles :
Line 1 : Article_1
Line 2 : Article_2
Line 3 : Article_3
But actually my loop only shows Article_1 for each Line
![examle][1]
Anyone know how to replace the "X" according to "i" ?
#{
var i = 0;
}
<!-- SOME HTML -->
#for(i=1 ; i < Convert.ToInt32(NB_PRODUCT); i++){
<tr>
<td>TITLE_X</td>
<td>PRICE_X</td>
</tr>
}
In my database i can have a lot of products to display (each tr = 1 product)
Here an example of database
You must load the data from your database in your controller or model, into objects like lists (or arrays) first.
Then once you have a list or array you can actually go through it in the HTML.
your code should look kinda like this (note: not literally):
you should provide the code where you read your DB, so lets just asume that part
Controller:
string[] ArraywithTitles = //your DB data for Titles (the column Article1)
string[] ArraywithPrices = //your DB data for price1
ViewBag.TITLE_X = ArraywithTitles;
ViewBag.PRICE_X = ArraywithPrices;
The contents of your array should be (if you were to read them, do not set them manually):
ArraywithTitles[0] = "t-shirt";
ArraywithTitles[1] = "t-shirt";
ArraywithTitles[2] = "pants";
//View
#for(i=1 ; i < Convert.ToInt32(NB_PRODUCT); i++){
<tr>
<td>#TITLE_X[i]</td>
<td>#PRICE_X[i]</td>
</tr>
now if you want the different articles, you need to have all of them in arrays or lists
//note: you must add ifs (or a switch case) for each NB_Product case,
//this is only for when a client has 3 products
#for(i=1 ; i < Convert.ToInt32(NB_PRODUCT); i++){
<tr>
<td>#Article1[i]</td>
<td>#PRICE1[i]</td>
<td>#Article2[i]</td>
<td>#PRICE2[i]</td>
<td>#Article3[i]</td>
<td>#PRICE3[i]</td>
</tr>
if you need further assistance (or a more literal solution), you should provide your controller and model code as well.

How can I get children of a node?

How can I get all the children for the News item (in the standard project) in a partialview (razor)?
I've tried:
#{
var homePage = CurrentPage.AncestorsOrSelf(1).First();
var newsItems = homePage.Children.Where(x => x.GetProperty("Name").Value == "News");
}
But I get an error that states I can't do lambda expression, whitout casting it. "News" is a node in my webpage holding children and I want to create a macro listing the children. How and what can I cast it to?
Currently, you are looking for children of the home page, named "News". I think you want to go one level deeper.
I reccomend this approach:
// 1- Get root node
var site = Model.Content.AncestorOrSelf("Site");
// 2- Get news node
var news = site.Descendant("News");
var newsItems = news.Children;
Here you use the document type alias to traverse your tree, this is much more reliable than using names, as those can change. This of course may require to rework some elements.
Hope this helps!
Try this to get all of the news nodes that are children of homepage:
var newsItems = homePage.Children.Where("Name = #0", "News");
Then iterate through the children of News:
foreach (var newsChild in newsItems)
You could skip the first step if you already know the ID of your news node like so:
var newsNode = Umbraco.Content(1234);
This page has plenty of examples:
http://our.umbraco.org/documentation/reference/querying/DynamicNode/Collections#

Umbraco AncestorOrSelf(int) - what does it do?

When using:
#Model.AncestorOrSelf(3)
In a .cshtml template in Umbraco, this would presumably limit the node traversal to 3 levels. Is this correct, and if so can anyone also confirm if the current node has the index zero?
#Model.AncestorOrSelf(3)
Model.Content is the current page that we're on. AncestorsOrSelf is all
of the ancestors this page has in the tree. (level) means: go up to
level 1/2/3/... and stop looking for more ancestors when you get
there.
Above is the comment that you get with Umbraco 7.x rc version.
Take an example of the content tree below that is kind of similar to that you normally see in contents section in umbraco admin area:
Each content document has a level and by default it starts with 1.
In a .cshtml template in Umbraco, this would presumably limit the node
traversal to 3 levels
As you can see in the example below, the level gets on increasing - level + 1. so, it starts by 1 and then just go on adding 1 to your sub levels.
- Content
-- Home (level = 1)
-- About Us (level = 2)
-- Contact Us (level = 2)
-- News Area (level = 2)
-- News Item 1 (level = 3)
-- News Item 2 (level = 3)
-- Other Node (level = 1)
So when you mention 3 as parameter for AncestorOrSelf, you are asking to move to 3rd level in the tree from the current element that can be any document/partial view and stop looking for any more ancestors when its found.
AncestorOrSelf(level) returns a single item which if of type DynamicPublishContent i.e. you will have access to many properties like id, name, url, etc.
#CurrentPage.AncestorOrSelf(1)
// based on content structure above, the above statement will give you an item - Home.
It is basically for fetching ancestors by level, doesn't matter what your current level or currentpage object is.
For example, if you want to create a navigation in your main layout so as to share it on all pages of your site, you will do something like this in your template:
<ul>
#foreach(var page in #CurrentPage.AncestorOrSelf(1).Children)
{
<li>#page.Name</li>
}
</ul>
Based on our example, it will give you:
About Us, Contact Us, News Area (in list form and with proper links)
Adding to the answer from SiddharthP I think the OP is possibly looking for the #CurrentPage.Up(int) method - this is traverses up the tree from the current level by the specified amount of levels.
So if you want the grandfather of the current node - #CurrentPage.Up(2) or #Model.Content.Up(2) for the strongly typed version.
Think of it as Ancestor starts from the root of the content tree down and Up starts from where you are going towards the root.
I think the confusing bit is you use the CurrentPage object but start traversing from the top root node towards the CurrentPage. When we think of our Ancestors in humanity we don't start from the beginning of time!
If my understanding of the code is correct, .AncestorOrSelf(int) returns the ancestor (or self) of a node at the given level in the argument.
Taken from lines 948 & 956 of https://github.com/umbraco/Umbraco-CMS/blob/6.2.0/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs
public DynamicNode AncestorOrSelf(int level)
{
return AncestorOrSelf(node => node.Level == level);
}
public DynamicNode AncestorOrSelf(Func<DynamicNode, bool> func)
{
if (func(this)) return this;
var content = this;
while (content.Level > 1) // while we have a parent, consider the parent
{
// see note in .Parent - strange things can happen
var parent = content.Parent;
if (parent == content) return null;
content = parent;
if (func(content))
return content;
}
return null;
}
Hope I've understood that correctly and that this helps.

CSV export customization

I have the following piece of code which export a csv file.
- if #product.type_id == 2
= "#{l(:user)} ID , #{l(:name)} , #{l(:company)} , #{l(:item)} , #{l(:total)} , #{l(:order_time_stamp)}"
- orders = #product.orders
- orders.each do |order|
- order_users = get_user_who_order order
- order_users.each do |order_user|
- user = order_user[:user]
- products , op_total = get_products_and_total order_user[:order_products]
- company = user.company.present? ? user.company.name : ''
- products = products.join('. ')
But we have list of items which is currently rendering in a single column however we need it to be in the different columns like item1, item2, item3 and so on.
Seems a bit crazy to me to do this with haml. There is a nice CSV library in Ruby you can use for this instead.
If you still insist on doing it with haml what you are missing is printing the extra , - you need to this yourself when using haml like this. I don't see any = in your loop at all. How is it possible that you get anything printed at all? (Except the header?)

Perfomance issue - .Count in MVC view

For several pages I use a .Count inside a foreach loop
#model ICollection<Item>
foreach(var item in Model)
{
#item.Flight.FlightReservations.count
}
Because of lazy loading the EF makes a round trip to the database for this.
Now I want to fix this by using this or linq version:
Include("List.Flight.FlightReservations")
Doing this makes loading my dbSet take even longer than those foreach round trips
How can I 'load' parts of only 1 object?
I would like to use context.Items.Single(p => p.id == id).Include(.....)
So I only load 1 item fully.
Or any other solutions for this?
(A way to force load item.List.item2.List inside controller)
Any suggestions are welcome :) Thanks
EDIT : now using
Where(..).ToDictionary(item => item, item => item.Flight.FlightReservations.Count);
Also noticed adding an index to my 'clustered index' table helped a little.
Still slow though
var f = _pr.FindBy(duifid);
var result = (from p in f.IngeschrevenVluchten
select new PrestatieModel
{
Eindpos = p.Eindpositie,
Locatie = p.Vlucht.Locatie.Naam,
AantalInschrijvingen = p.Vlucht.Inschrijvingen.Count(),
Vlucht = p.Vlucht
});
This query executes very fast, making a IEnumerable<Model>. But still it loads very slow once sent to the view.
return PartialView(result);

Resources