Can't get Properties of a Specific Child Page - umbraco

I just started using umbraco 4 days ago and I'm stuck with this problem.
I have a page named "About Us" that is a child under "Home" and I need to get some of its properties in the "Home" Page.
I created a partial view macro to do this but I get the error loading partial view script instead.
Below is my code:
#{ var selection = CurrentPage.Children.Where(x => x.Name == "aboutus"); }
#if (selection.Any())
{
<ul>
#foreach (var item in selection)
{
<div class="sc-inner">
<h4>
#item.PageTitle</h4>
<p>
#Umbraco.Truncate(#item.mainAboutDescription, 100)</p>
<a class="btn btn-danger" href="#item.Url">Read More...</a>
</div>
break;
}
</ul>
}
Can someone please tell me what I'm doing wrong?
Thanks in advance.
Edits:
The error on the website I got is below;
Error loading Partial View script (file: ~/Views/MacroPartials/homePage_aboutUsSection.cshtml)

Assuming the partial is inheriting UmbracoTemplatePage the CurrentPage property is a dynamic, you cannot use lambda expressions as an argument to a dynamically dispatched operation.
If you wish to use Linq to query the content use Model.Content rather than CurrentPage which is an IPublishedContent e.g.
#{ var selection = Model.Content.Children.Where(x => x.Name == "aboutus"); }
Note: the Name property will return the documents Name as entered in the CMS most likely 'About Us' instead of 'aboutus'
Using the about will return an IEnumerable<IPublishedContent> so you will need to use the GetPropertyValue method rather than accessing the content dynamically:
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{ var selection = Model.Content.Children.Where(x => x.Name == "aboutus"); }
#if (selection.Any())
{
<ul>
#foreach (var item in selection)
{
<li class="sc-inner">
<h4>
#item.GetPropertyValue("pageTitle")
</h4>
<p>
#Umbraco.Truncate(#item.GetPropertyValue<string>("mainAboutDescription"), 100)
</p>
<a class="btn btn-danger" href="#item.Url">Read More...</a>
</li>
break;
}
</ul>
}

Very bad practice to use the Name property for querying in your code - what if somebody changes the Name to About for example. Your code would break. If there is something else that is unique on the node then it would be better.
For example if you have an aboutUs document type for your about us page you could use:
Model.Content.Children.Where(x => x.DocumentTypeAlias == "exactNameOfYourDocTypeAliasHere")
or, although not so robust, the Id of the page could be used.
Model.Content.Children.Where(x => x.Id == 1234)
The Id is far less likely to change than the Name of a key page like this.
I would generally not use the Id in code either but it is far better than Name

Related

Sitefinity Custom Fields for list widgets and how to use them in MVC view templates

I've added a Custom Field to the List Widget in Sitefinity 8.1, it's Type is Related data and it's Data type is Pages. The field name is LinkedPageUrl.
Works perfectly in the back end allowing me to select a page from system and store it against that particular List Item.
I can't find any place in Sitefinity's documentation that explains how I would programmatically use this field in a MVC based List.SimpleList.cshtml view template that I'm customizing.
I've seen this being used in the News widget where there is an associated Image for each News Article:
<img src="#Html.Raw(item.Fields.RelatedImg.Fields.MediaUrl)" class="img-responsive" />
But I don't get close to this because I don't have the slightest idea where to begin... What's the model structure, syntax, etc.
My objective is to change each list item rendered out into an anchor and the anchor should make use of this Related Data field's URL for it's Href property.
EDIT:
You can do something like this in the widget template:
#foreach (var item in Model.Items)
{
<h3 #Html.InlineEditingAttributes(Model.ProviderName, Model.ContentType.FullName, (Guid)item.Fields.Id)
#Html.InlineEditingFieldAttributes("Title", "ShortText")>
#item.Fields.Title
</h3>
<ul>
#foreach (var listItem in ((ListViewModel)item).ListItemViewModel.Items)
{
<li #Html.InlineEditingAttributes(Model.ProviderName, ((ListViewModel)item).ListItemViewModel.ContentType.FullName, (Guid)listItem.Fields.Id)>
<div #Html.InlineEditingFieldAttributes("Title", "ShortText")>
#listItem.Fields.Title
</div>
<div class="sfMultiRelatedItmsWrp">
<h2 class="sfrelatedItmTitle">Related pages</h2>
#foreach (var link in listItem.Fields.LinkedPageUrl)
{
var node = PageManager.GetManager().GetPageNode(link.Fields.Id);
var url = PageExtesnsions.GetFullUrl(node);
<div>#link.Fields.Title - #url</div>
}
</div>
</li>
}
</ul>
}
This is given that you selected that multiple pages can be selected per list item.
EDIT: Make sure to include the following namespaces
#model Telerik.Sitefinity.Frontend.Mvc.Models.ContentListViewModel
#using Telerik.Sitefinity.Frontend.Lists.Mvc.Models;
#using Telerik.Sitefinity.Frontend.Mvc.Helpers;
#using Telerik.Sitefinity.Modules.Pages;
EDIT2: If the custom field allows for only 1 page to be selected then it should look like this:
<div class="#Model.CssClass">
#foreach (var item in Model.Items)
{
<h3 #Html.InlineEditingAttributes(Model.ProviderName, Model.ContentType.FullName, (Guid)item.Fields.Id)
#Html.InlineEditingFieldAttributes("Title", "ShortText")>
#item.Fields.Title
</h3>
<ul>
#foreach (var listItem in ((ListViewModel)item).ListItemViewModel.Items)
{
<li #Html.InlineEditingAttributes(Model.ProviderName, ((ListViewModel)item).ListItemViewModel.ContentType.FullName, (Guid)listItem.Fields.Id)>
<div #Html.InlineEditingFieldAttributes("Title", "ShortText")>
#listItem.Fields.Title
</div>
<div class="sfMultiRelatedItmsWrp">
<h2 class="sfrelatedItmTitle">Related pages</h2>
#{
var node = PageManager.GetManager().GetPageNode(listItem.Fields.LinkedPageUrl.Fields.Id);
var url = PageExtesnsions.GetFullUrl(node);
}
<div>#listItem.Fields.Title - #url</div>
</div>
</li>
}
</ul>
}
A good starting point is this article

MVC getting id on button click

I am trying to get the id of the selected button.
This is my code below
<% foreach (var item in Model.getLeagues) { %>
<a href=Teams.aspx class="leagueImage">
<img src="../../<%: item.image %>" alt="<%: item.name %>" />
</a>
<% } %>
With this code I am generating 5 buttons and then I need the id of the clicked button.
Any help of how I can get this id ?
Thanks
If you want to get the ID from the controller, why not take the suggestion Marko made, but instead of putting it into the id attribute, instead put make it part of your href tag and pass the ID attribute.
By default, the routing in MVC expects back an ID which is part of your route in:
http://sitename/{Controller}/{Action}/{Id}
So, you could do something like this (I'm going to use Razor syntax, but, you can adjust):
#for(var i = 0; i < Model.getLeagues.Count; i++) {
Html.ActionLink("Button Name", "Index", "MyController", new { id = Model.getLeages[i] }, new { #class="classname", alt = "#Model.getLeagues[i].name" }) %>
}
And, in your controller (rename as appropriate) you would have:
public class MyController : Controller {
public ActionResult Index(int id) {
// Do stuff with the ID that you get back here.
}
}
Also, you'll notice that I broke out your image information. Instead, make a class in your stylesheet like:
a.classname
{
background: url(../Images/image.gif) no-repeat top left;
/* Do whatever else you need to do here to style your buttons. */
}
I didn't check any of the code, so can't guarantee it's syntactically perfect, but that should get you going down a right path.
I did notice your path to Teams.aspx. If you are coming from WebForms, you can edit your routing file to direct towards the RESTful route like this:
routes.MapPageRoute("Teams", "MyController/Index", "~/WebForms/Index/Teams.aspx");
(Credit to: https://stackoverflow.com/a/10175580/132528)
If you change your loop to following:
<% for (var i = 0; i <= Model.getLeagues.Count; i++) { %>
<a href="Teams.aspx" id="link_<%: i %>" class="leagueImage">
<img src="../../<%: Model.getLeagues[i].image %>" alt="<%: Model.getLeagues[i].name %>" />
</a>
<% } %>
now you have anchor tags with unique IDs (link_0, link_1, ...). So now using jquery click event like this:
$(document).ready(function() {
$(".leagueImage").click(function() {
alert($(this).id);
});
});
will get you a popup box that will display the ID of the clicked anchor tag.
If you are looking to get the index of the collection you are looping though, try this:
Model.getLeagues.indexOf(item)

How can I save the order a list of hidden form inputs which represent an array in ASP.NET MVC?

I have a sortable list of items which are generated from an array property on a model. I want to use jquery UI sortable to reorder the items and save this order in my Action method.
Here is the code I am using to output the items:
#using(#Html.BeginForm("Save", "MyController", FormMethod.Post))
{
<input type="submit" value="Save"/>
#Html.HiddenFor(x=>x.Id)
<ul id="sortable2" class="connectedSortable">
#{
int count = 0;
}
#foreach(var item in Model.CollectionOfThings)
{
<li class="ui-state-default">
#Html.Hidden("Things[" + count + "].Id", item.Id)
#Html.Hidden("Things[" + count + "].Title", item.Title)
#item.Title
</li>
count++;
}
</ul>
}
When I receive the model in my action method the order is the same as when I started. I understand that this is because of the index but I can't figure out a way (without writing some custom javascript to update the name attribute of each hidden input) to have the items bound to the array in correct order.
Can anyone suggest a way this could be achieved? I can probably write a bit of Javascript to do it but I hoped I could do this purely with model binding.
I tried outputting the inputs like this:
#Html.Hidden("Things[].Id", item.Id)
However this just resulted in my collection being null.
I have discovered a blog post from Phil Haack which contained the answer.
By using arbitrary indexes in a seperate hidden input with the name of my collection + .Index, the model binder seems to handle it and maintain the order.
#using(#Html.BeginForm("Save", "MyController", FormMethod.Post))
{
<input type="submit" value="Save"/>
#Html.HiddenFor(x=>x.Id)
<ul id="sortable2" class="connectedSortable">
#{
int count = 0;
}
#foreach(var item in Model.CollectionOfThings)
{
<li class="ui-state-default">
#Html.Hidden("Things.Index", "item" + count)
#Html.Hidden("Things[item" + count + "].Id", item.Id)
#Html.Hidden("Things[item" + count + "].Title", item.Title)
#item.Title
</li>
count++;
}
</ul>
}
Easier solution for you can be to collect only Ids. I assume titles can be recreated on server side. In this case you can just define:
#Html.Hidden("ThingIds", item.Id)
and bind to
List<int> thingsIds

Can we dynamically change the URL with Ajaxy call on ASP.NET MVC page?

I have an ASP.NET MVC application that has a view called Products.
This Products View has a Left Menu Navigation that is implemented using NavMenuProducts.ascx Partial View.
This Menu is implemented using JQuery Treeview so that it has the list of ProductNames as the Parent Node and it is expandable(For Example: 10 Products).
Each of these Products have a ChildNode as DocTypeName and it is a hyperlink(For Example: 3 DocTypeNames).
When the user clicks ChildNode Hyperlink all the matching Documents are displayed and is implemented using Ajaxy call. So that the user has better UI experience.
But the problem with this is the url always is static(Example: http://DocShare )
But based on the Node that is clicked, I want the url like http://DocShare/Products/Product1/Letter
I am wondering how to make this dynamic url using Ajaxy call.
NOTE: If I am using HTML.ActionLINK, then I am getting dynamic URL. But this ActionLink, while the Page is loading, we are getting random treeview screen. TO avoid that flickering tree effect, I am making Ajax call for better UI experience.
Any solution would be appreciated for getting dynamic url with Ajaxy call.
Here is the Code:
NavigationProducts.ascx Page:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MedInfoDS.Controllers.ProductViewModel>" %>
<script type="text/javascript">
$(document).ready(function () {
$(".docId").click(function () {
alert("DocTypeName: " + this.id);
$("#docDetails").load('<%= Url.Action("DocumentDetails") %>', { ProductName: "darbepoetin alfa", DocTypeName: this.id }, function (responseText, status) {
});
return false;
});
});
<div id="treecontrol">
<a title="Collapse the entire tree below" href="#">Collapse All</a> | <a title="Expand the entire tree below"
href="#">Expand All</a> | <a title="Toggle the tree below, opening closed branches, closing open branches"
href="#">Toggle All</a>
</div>
<div id="divByProduct">
<ul id="red" class="treeview-red">
<% foreach (var item in Model.Products)
{ %>
<li><span>
<%=item.Name%></span>
<ul>
<%foreach (var item1 in Model.DocTypes) { %>
<li><span>
<%= Html.ActionLink(item1.DocTypeName, "Products", new { ProductName = item.Name, DocTypeName = item1.DocTypeName })%>
<br />
<a class="docId" href="#" id="<%=item1.DocTypeName%>"><%= item1.DocTypeName%></a>
<%= Html.Hidden("ProductName", item.Name)%>
</span></li>
<% } %>
</ul>
</li>
<% } %>
</ul>
</div>
Controller Method:
// Response to AJAXy call to populate details for given ProductName and DocType
[HttpPost]
public virtual ActionResult DocumentDetails(string ProductName, string DocTypeName)
{
var entities = new MIDSContainer();
if (ProductName == null) return View();
int ProductId = (entities.Products.FirstOrDefault(p => p.Name == ProductName)).ProductId;
int DocTypeId = (entities.DocTypes.FirstOrDefault(d => d.DocTypeName == DocTypeName)).DocTypeId;
var documents = (from d in entities.Documents.Where(p => p.ProductId == ProductId && p.DocTypeId == DocTypeId && p.AvailableForUse == true && p.Status == "Approved") orderby (d.Description) select d).ToList();
return View(documents);
}
There's a pretty comprehensive solution here: http://ajaxpatterns.org/Unique_URLs
I assume you want to "change the url" so that the Back button works in the browser to navigate between the different products. You can't actually change the URL without a postback, but you can change the url's Hash value. By changing the Hash value you will be able to support the browsers Back button just like the URL itself was changed but without any postbacks.
In the following URL:
http://site/page#SomeValue
The Hash value is "#SomeValue".
You can set the Hash using "document.Hash" in JavaScript.
To make it much easier to work with the "document.Hash" value and setup a function to get notified when it changes, I create the jHash project.
You'll probably want to look at jHash to help you do what you're looking for.
http://jhash.codeplex.com/

Hide table or grid and display "No records found" message in ASP.NET MVC

What is the best practice for hiding a custom grid or a table or a div and display a "No Records Found" message when there are no records.
I have come up with this idea.
<div class="<%= Html.IsVisible(Model.Count)">
...
..
..
</div>
.displayNone {display:none;} .displayInherit {display:inherit;}
public static string IsVisible(this HtmlHelper helper,int recordCount)
{
return recordCount == 0 ? "displayNone" : "displayInherit";
}
Your solution would work fine, but I think you might be overthinking it a little :)
This would work perfectly fine:
<% if (Model.Count == 0) { %>
No Records Found
<% } else { %>
// do something to show the Model information here
<% }
Make the if in the controller?
if Model.Count == 0 display the "EmptyView" else show the GridView
Empty view could be made generic to be use from several objects.
Following solution is better for razor engine
#model IEnumerable<WebApp.Models.ArticleViewModel>
<div id="answers">
#if (Model.Count() == 0)
{
<div class="question-summary">
<p>No answer found</p>
</div>
}
else
{
foreach (var item in Model)
{
<div class="question-summary">
#Html.Raw(item.Body)
</div>
}
}
</div>

Resources