Getting children of a page by name - umbraco

I'm trying to do something I thought was obvious, but I can't find a doc on this to save my life.. Basically, I want to build a list of links for all children of a page by it's name.. I'm trying this with no luck.. Is there an easy way to accomplish this?
#foreach (var page in Model.Content.Where(page => page.Name.Equals("About")).Children) {
...
}

If you mean you want links to the current page's children who are named "About" then you can do:
#foreach(var page in #Model.Content.Children.Where(x => x.Name == "About"))
{
#page.Name
}

Related

Insert current URL into #Html.RouteLink parameter to build a link

I am probably going about this the wrong way as i'm a noob to .NET MVC, but is there a way to insert the current url as a parameter into an #Html.Routelink?
I'm passing a partial view into a page to display a list of subcategories based off of the current category.
Here is my controller logic:
public PartialViewResult SubcategoryMenu(string category)
{
IEnumerable<string> subcategories = repository.Products
.Where(x => x.SubCategory.Category.CategoryName == category)
.Select(x => x.SubCategory.SubCategoryName)
.Distinct()
.OrderBy(x => x);
return PartialView(subcategories);
}
Here is my partial view which I'm trying to get the current category url into:
#model IEnumerable<string>
#foreach (var link in Model)
{
#Html.RouteLink(link, new
{
controller = "Product",
action = "List",
category = "INSERT CURRENT URL HERE",
subcategory = link,
page = 1
}, new { #class = "btn btn-block btn-default btn-lg" })
}
When the page displays, all products and categories are listed, no problem. When I click a Category, the URL is http://localhost/Category2 which is what I want.
Click a category, then all of the associated subcategories display in a separate div based on the linq query in the controller just fine.
However, to properly display the products, the url generated for the subcategory view needs to be http://localhost/Category/Subcategory and no matter how I tweek the #Html.RouteLink or even an #Html.Actionlink, all I can get is http://localhost/Subcategory If i pass in text into the #Html.Routelink for controller= "something" that will display http://localhost/something/Subcategory so I've been trying to get the current URL which matches the required category passed into the subcategory #Html.Routelink with no success.
If there is a way to insert the current URL into the subcategory RouteLink it would solve my woes. If there is a way to accomplish, or a better way to do so, please help.
Thank you all!
RouteLink and ActionLink use the RouteTable to build outgoing URLs, so it is the RouteTable you need to modify to customize URLs, not the RouteLink configuration.
You can do this many ways, but the most flexible way to make URLs that are driven off of database data is to subclass RouteBase.

Partial View different model

I am trying to use a partial view that uses a different model than the one used in the main view. The partial view has
to show a list with the products recently added. But I am stuck on how and where to implement the logic for retrieving the data I need from the database.
Home/Index.cshtml:
#Html.Partial("~/Views/Shared/_LatestProducts.cshtml", new List<Website.Models.LatestProductsList>())
Shared/_LatestProducts.cshtml:
#model List<Website.Models.LatestProductsList>
#foreach (var item in Model)
{
<a href="#" title="img">
<img src="~/Content/images/latest-product-img.jpg" alt="" /><p>#item.ProductName</p>
</a>
}
And I have the following code that I am trying to use in order to get some products for tests and show them in the partial view:
public PartialViewResult _LatestProducts()
{
List<LatestProductsList> latestProd = (from p in db.Products
where p.ID < 5
select new LatestProductsList { ProductName = p.Title }).ToList();
return PartialView(latestProd);
}
I thought that I might use it in the HomeController, but that obviously doesn't work and I am not sure if partial views should have their own controller, if I can
just call it from another class. I am still wrapping my head around ASP MVC, so any help will be appreciate it.
Just call the action that renders the partial view in Index.cshtml.
#Html.Action("_LatestProducts", "Product")
Second parameter is the name of the controller that has the _LatestProducts method.
Just a reminder: Names with _ prefix is for partial views only, not action methods. You should rename it to LatestProducts.

Model binding a list of checkboxes problem

In my EditorTemplates, i Have two Views. One for my Category (called _Category)
#model com.example.Models._Category
#Html.CheckBox(Model.Name, Model.Selected)
#Html.LabelFor(c => c.Name, Model.Name)
<br />
and one for the List of Categories (called _Categories)
#model List<com.example.Models._Category>
#for (int i = 0; i < Model.Count; i++)
{
#Html.EditorFor(c => Model[i]);
}
In the view that shows these categories, i have a list of Categories which is being used like so:
#Html.EditorFor(m => m.Categories, "_Categories")
When I view the page, there are multiple checboxes with names next to them which is good. The name of the checkboxes is not so good however as they turn out to look like this:
....name="Categories.[1].Batman"....">
There is an extra dot in the name which needs to go away. Any ideas on how to fix this?
Thanks in advance
Please refer to this and this for collections databinding, those are two ultimate resources for that.
I saw this post that I believe talks about the same issue that you are having. Might be helpful.

How to access the Model from the View?

I have a search page that display a search result. The search result is a list of persons that matched the specific search. I'm iterating through this list displaying them in a table. As headers for this table I want the DisplayName from the model. If I don't inherit IEnumerable I wouldn't be able to iterate through the list. I'm new at this MVC thing =)
I iterate through the result like this:
<% foreach (var item in Person) { %>
<%: item.surname %>
<% } %>
But how do I print the "DisplayName" of an attribute without iterating through the whole list? I would just like to do:
<%: Html.LabelFor(m => m.surname) %>
If it's any help I inherit an IEnumerable at the top of the page:
<%# Page Inherits="System.Web.Mvc.ViewPage<IEnumerable<RegistryTest.Models.Person>>" %>
Edit
I want to display "Your surname" but I don't know how to access it from the view.
[DisplayName("Your surname")]
public object surname { get; set; }
Here's a very similar question that hasn't been answered either: Can I use LabelFor() when the page inherits from IEnumerable<T>?
If you only need to display specifics of one person; you should consider sending only one person to the view instead of a complete list of persons. In that case
Model.Surname
would work just like that. So instead of:
Inherits="System.Web.Mvc.ViewPage<IEnumerable<RegistryTest.Models.Person>>"
do
Inherits="System.Web.Mvc.ViewPage<RegistryTest.Models.Person>"
In this case a single person is loaded into your Model and Model.Property works fine. If you want an IENumerable<>, think about what that means. You are sending a list of persons, so the only thing in your "Model" is a IENumerable<> of persons. There is no way that the view can know what you want if you call Model.Property, since in the Model there are multiple Objects and the view doesn't know which Object you want to get the Property from.
Bottom line, if you want to call Model.Property (Model.surname) but also want to send an IENumerable you are having a design flaw. If you send a list you should want to do something with the complete list (iterate through and do something with the contents). If you just want to do something with one person in that list, re-design your view/controller and send that single person; then you can use Model.Property.
//EDIT BASED UPON COMMENTS
As I see it now you either want to do one of those two things (I do not know which):
Show the records of an item in your list in a table and put the DisplayName of the current object shown in the table in the header.
Show all items of the list in your table and put some sort of DisplayName in the header. This makes less sence but it could be that you mean to name your list.
Situation 1
This is working as the rest of your code? The following would work just fine.
<% foreach (var item in Model) { %>
<table>
<th>item.DisplayName</th>
<tr>
<td>item.Property1</td>
<td>item.Property2</td>
</tr>
</table>
<% } %>
Situation 2
If you want a DisplayName of the list (??) you should create a ViewModel containing the IENumerable of Persons and a public string ListName. Now you can do something like:
<table>
<th>Model.ListName</th>
<% foreach (var item in Model) { %>
<tr>
<td>item.Property1</td>
<td>item.Property2</td>
</tr>
<% } %>
</table>
this would create a table with the name of your List (given in the ViewModel) as header and as items in the table you have your persons.
Design problem?
However, I would love to see you write some more information in your question above. Give us some more information on what you want to do. Do you want to show records of each Person in the list one-by-one? In that case I would recommend you create a Partial View where you put your table. Then you would get something like:
<% foreach (var item in Model) { %>
<% Html.RenderPartial("TablePerson",item); %>
<% } %>
tableperson.ascx:
...
Inherits="System.Web.Mvc.ViewPage<IEnumerable<RegistryTest.Models.Person>>"
...
<table>
<th>Model.DisplayName</th>
<tr>
<td>Model.Property1</td>
<td>Model.Property2</td>
</tr>
</table>
So, we need more information I'm afraid :)
If it's a collection with every entry having the same surname then try model[0].surname or model.ToList().First().surname
You don't need ToList() if its a List<T> already. Then it would be just model.First()
You are specifying that the page model is IEnumerable, and you say you would like to print a property of an element. Since you have a list of elements, you need to specify which of the elements you would like to retrieve the property from.
I you want a specific index in the list you will need to convert the IEnumerable collection to IList (ToList()), depending on the criteria, you may also be able to find the required element using something like a LINQ Single() operation.
Otherwise you could select the property from all the element in the list using Model.Select(m => m.PropertyName) which will give you a list of just this property, and then concatenate this list to a single string.

.NET MVC - List and Detail Views

I think there is a simple answer to this, but for some reason I am hitting a writers block today. I have an app which people can search (like any app :) ) and generate a list view. From that list view, you can view details, which will take you to a details view. No JS, just another page. But, what I would like to do is to have a back/next button within the details view so that you can parse the result set without having to go back to the list and then select the next record.
I have had two ideas on accomplishing this. Idea 1) Have a next/previous record field in my custom class. However, this wouldn't work as the search query will not necessarily return consecutive results and I would have to query the DB each time to get those next/prev listings. Idea 2) Have a list of IDs or some custom object passed in the view state for each detials view corresponding to the search results. On this one, I am not sure of the 'overhead' associated with this method.
Any suggestions from the SO community?
Thanks!
Construct the link that opens the details view so that it has next and previous parameters that contain a list of the previous/following elements as well as the id of the current element. Probably easiest to do if you iterate through the list model data by index rather than using foreach -- that way you just reference the previous/next element relative to the current element when finding their ids. Make sure to handle the first and last elements correctly.
In your controller action the next/previous parameters should be nullable -- if you don't get there from the list, you don't render the next/previous buttons. You could "post" the details view action and put the extra parameters in the form rather than the URL so the user can still bookmark the url. Note that this has it's own issues though with regards to the browser's back/forward button and refreshing.
<% for (int i = 0, len = Model.Count(); i < len; ++i)
{
Foo model = Model.ElementAt(i);
string prev = i == 0 ? null : string.Join( ",", Model.Take(i).Select( m => m.ID.ToString() ).ToArray() );
string next = i == (len - 1) ? null : string.Join( ",", Model.Skip(i).Select( m => m.ID.ToString() ).ToArray() )
%>
<% using (Html.BeginForm("Details","Bar", new { id = model.ID } )) { %>
<%= Html.AntiForgeryToken() %>
<%= Html.Hidden( "Prev", prev ) %>
<%= Html.Hidden( "Next", next ) %>
<input type="submit" value="Details" />
<% } %>
<% } %>
I would probably also use some jQuery to change the input button to a link that submits the enclosing form with a click event handler, but that's just my preference for the UI.

Resources