Sitecore Building a single page from child node data - sitecore

I have a Sitecore structure of items which comprises of
Range
Product 1
Product Name (text)
Product Image (image)
Product 2
Product Name (text)
Product Image (text)
I need to make a single page view that iterates through each of these nodes and collects and outputs the data for each - can anyone assist in the method I would best use to do this?
Sorry if this is a basic question but any example code would be appreciated.

You should really think about just using a single product template with a Product Name field and a Product Image field instead of having items with single fields under the product. But if this is your requirement, this is how you would do it.
SubLayout (or layout if need be)
<div>
<sc:Text runat="server" id="txtProductName" Field="ProductName"/>
<sc:Image runat="server" id="imgProductImage" Field="ProductImage"/>
</div>
Then in code behind you would take the current item (the product and find the child item that corresponds to what you are looking for and assign it as the field item.
private void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindData();
}
}
private void BindData()
{
txtProductName.Item = Sitecore.Context.Item.Children.FirstOrDefault(x => x.TemplateID == Constants.Templates.ProductName);
imgProductImage.Item = Sitecore.Context.Item.Children.FirstOrDefault(x => x.TemplateID == Constants.Templates.ProductImage);
}
In my example I am resolving it looking for an item of template type X, but you could go by name or some other way of knowing.

Related

How to make a NameValueCollection list editable in GlassMapper

I am trying to make a NameValueList collection editable with GlassMapper and I don't seem to be able to get to the bottom of this.
We have a list of validations that can be attached to a field and I would like to have the validation message editable in ExperienceEditor.
The collection is pre-processed when GlassMapper is retrieving the item:
Validations = glassItem.GetValidations();
#foreach(Validation validation in Model.Validations)
{
<div id="#validation.Identifier" ng-message="#validation.AngularKey" ng-cloak class="mtg-validation-msg">
#Html.Glass().Editable(validation, e => e.ErrorMessage)
</div>
}
Error that I am getting:
Failed item resolve - You cannot save a class that does not contain a property that represents the item ID. Ensure that at least one property has been marked to contain the Sitecore ID. Type: MyAssembly.Models.Validation
It is not possible to directly edit certain types of complex fields in the Experience Editor, such as Treelist, Multilist or Name Value Collection.
Instead, you should set up and use an Edit Frame. This will pop up a modal dialog allowing you to edit the field, it is not inline but means you do not need to leave the Experience Editor. This is the recommended approach to this problem.
Since you are using Glass Mapper, since version 4 you can declare Edit Frames all directly from code and now have to declare/set them up in the Core database first.
#if (Sitecore.Context.PageMode.IsExperienceEditor)
{
using (Html.Glass().BeginEditFrame(Model, "Edit", x => x.Validations))
{
<div>Edit Validations</div>
}
}
You might be interested in this blog post I wrote about adding a wrapper around the Edit Frame to make the UX more friendly.

How to access drop down list field type selected value in sitecore

I can access Single-Line text field type by following in Repeater:
<sc:FieldRenderer ID="frTitle" runat="server"
FieldName="Title"
Item="<%# (Sitecore.Data.Items.Item)Container.DataItem %>" />
but how to access drop-down list field type selected value defined in item.
Thanks
This depends on the exact field type you are using.
If using a Droplist field type
The value is stored in Sitecore as plain text representing the name* of the selected item. In this case you could use your code sample to render out the name of the selected item (if that's really what you want to do). *Note that the content editor will see the Display Name of the items in the droplist, but your code would render out the item name. Using this field type is not usually a good idea as it is not possible to translate item names.
If using a DropTree or Droplink field type
The value is stored in Sitecore is an ID of the linked item. In this case you would need to get the selected item using this ID, then render out the required field of that item. I would probably write a code-behind method to get the selected item, then call this method within your FieldRenderer. Something like this:
Code-behind:
public Item GetLinkedItem(Item item, string itemField)
{
string dropDownItemId = item[itemField];
return Sitecore.Context.Database.GetItem(dropDownItemId);
}
Ascx markup:
<asp:Repeater ID="rptChildren" runat="server">
<ItemTemplate>
<sc:FieldRenderer ID="frTitle" runat="server"
FieldName="Title"
Item='<%# GetLinkedItem((Sitecore.Data.Items.Item)Container.DataItem, "YourDropLinkFieldName") %>' />
</ItemTemplate>

droplink and treelist values in sitecore search

How to get droplink and treelist values in sitecore search .
Below are my code and config file . But when i am searching based on droplink and treelist value its not coming in search result .
var fquery = new FullTextQuery(search);
SearchHits searchHits = sc.Search(fquery, int.MaxValue);
return searchHits.FetchResults(0, int.MaxValue).Select(r => r.GetObject()).ToList();
config file entry .
I am not sure if i have to parse them or something else . Looking forward for help.
You don't say which version of Sitecore you're using, but speaking as someone who works with v6.6:
ID-based fields, like TreeList store GUIDs in the Sitecore database. At index time, Sitecore parses these into ShortID format and forces it to lower case. So the Lucene index entry actually contains a lowercase GUID with no curly braces or hyphens.
Chances are, your text-based query is not going to contain text that will match this.
I tend to use a Term based BooleanQuery object to match ID-based fields. Something like:
BooleanQuery query = new BooleanQuery();
query.Add(new TermQuery(new Term("myfieldname", ShortID.Encode(myGuidToMatch).ToLowerInvariant())), BooleanClause.Occur.MUST);
Note that the field name you want to query should be in lower case, as Sitecore / Lucene generally works in lower case.
You may find the code and UI example in this blog post helpful to see an example of building queries against ID-based fields:
http://jermdavis.wordpress.com/2014/06/09/faceted-search-in-sitecore-6-6/
If you want to be able to match the values contained in these fields from a free text type of search box, then you will have to pre-process the values from these ID-based fields before they are indexed.
Sitecore and Lucene allow for the idea of "computed fields" in your index - basically you can configure the indexing process to run bits of your own code in order to process data at index time, and to create new Lucene index fields from the results of your code.
This blog post of mine gives an example of a computed field:
http://jermdavis.wordpress.com/2014/05/05/using-dms-profile-cards-as-search-metadata/
That example is not doing what you want - but it does talk about how you might configure one of these custom fields.
You'd probably want your custom field code to:
Get the raw value of the ID-based field
Load the item that this ID points to
Process that item to turn it into the pattern of text you want to be indexed
Return this text, to be saved into the computed field in Lucene
With that done, you should find that your index will contain the text associated with your ID field(s). And hence you should be able to match it with a text-based query.
-- EDITED TO ADD --
More detail on creating computed index items:
Sitecore 6.6 doesn't directly support computed fields in your Lucene indexes. To get them you can make use of the Advanced Database Crawler - which is part of the Sitecore SearchContrib project available on GitHub: https://github.com/sitecorian/SitecoreSearchContrib
There are assorted blog posts about on getting started with this code.
[NB: In Sitecore 7.x I believe this behaviour has migrated into the core of Sitecore. However I think they changed the names of stuff. Details of that are available via google - things like Upgrading sitecore 6.6 index configuration to sitecore 7 (using ComputedFields) for example]
The code for a dynamic field to turn something ID-based into text might look like:
public class IndexIDField : BaseDynamicField
{
public override string ResolveValue(Sitecore.Data.Items.Item item)
{
Field fld = item.Fields["FieldYouAreInterestedIn"];
if (fld != null && !string.IsNullOrWhiteSpace(fld.Value))
{
string[] ids = fld.Value.Split('|');
StringBuilder text = new StringBuilder();
foreach (string id in ids)
{
Item relatedItem = item.Database.GetItem(id);
if (relatedItem != null)
{
text.Append(relatedItem.DisplayName);
text.Append(" ");
}
}
return text.ToString();
}
return null;
}
}
This is extracting the appropriate field from the context item that's being passed in. If it exists and is not empty, it splits it by "|" to get a list of all the IDs stored in this field. Then for each one it tries to load it. Note use of the appropriate database specified by the input item - Sitecore.Context.Database will point to Core at this point, and you won't find your items there. Finally, if we get back a valid item from the ID, we append its display name to our text to be indexed. You could use other fields than Display Name - depending on what makes sense in your solution.
With that code added to your solution you need to ensure it's called at index build time. The default config for the Advanced Database Crawler includes a config element for dynamic fields. (And again, SC7.x will have something similar but I don't know the names off the top of my head) You need to add your type to the configuration for dynamic fields. Snipping out all the extraneous bits from the default config:
<configuration xmlns:x="http://www.sitecore.net/xmlconfig/">
<sitecore>
<!-- snip -->
<search>
<!-- snip -->
<crawlers>
<demo type="scSearchContrib.Crawler.Crawlers.AdvancedDatabaseCrawler,scSearchContrib.Crawler">
<!-- snip -->
<dynamicFields hint="raw:AddDynamicFields">
<!-- snip -->
<dynamicField type="YourNamespace.IndexIDField,YourDLL" name="_myfieldname" storageType="NO" indexType="TOKENIZED" vectorType="NO" boost="1f" />
</dynamicFields>
<!-- snip -->
</demo>
</crawlers>
</search>
</sitecore>
</configuration>
That sets up a new field called "_myfieldname" with sensible options for indexing text.
Rebuild your search index, and you should find your free text queries will match the appropriate items. Testing this basic setup on an instance of SC6.6, I get hits with some test data I happened to have lying around. If I search my computed column for "blue" I get only rows which were tagged with a metadata item that had "blue" in its name:

Setting selected entry using helper.options?

Im am using Play 2.0.4 and
helper.options(myitems)
in my template (inside of a helper.select)
In this case, how can I define the default selected entry, which shall be one entry out of myitems? Thanks for any hint!
A little bit more about my case:
Imagine a news archive, showing all news titles. This news archive uses pagination, pagination uses GET to pass the next/previous page number.
The play framework however will only correctly select the currently selected "select" item (here: news category) when a POST request was used - while pagination uses GET!
Intended behaviour: While a filter is applied / a specific news category is selected, this shall always be visible to the user by preselecting the currently selected news category in the "select" form.
A "screenshot" for illustration:
So, anyone having a good idea on how to cope with this problem? Any way to tell Play manually which entry from the "select" form it shall select? '_default always adds a new entry instead of selecting one out of the given options ): Would be great, if one wouldn't have to build the complete "select" form manually.
Try passing '_default option to select helper:
#import views.html.helper._
#select(form("email"), options(List("first", "third")), '_default -> "second")
It seems, unfortunately, the only way to figure it out is to look up the source.
Update:
Specifying _default property doesn't set selected attribute on option tag. It looks like the only way to preselect entry is to pass prefilled form to the template. For example, suppose you have following form:
case class RegInfo(email: String, color: String)
private val registrationForm = Form(
mapping(
"email" → email,
"color" → nonEmptyText(minLength = 5, maxLength = 32)
)(RegInfo.apply)(RegInfo.unapply)
)
Then in the action prefill form before passing to the view:
def create = Action {
Ok(html.create(registrationForm.fill(RegInfo("user#qwe.com", "blue"))))
}
Then in template use helper:
#select(form("color"), options(List("red", "green", "blue")))
And value will be preselected.
Ended up with the pragmatic approach:
<select id="myfield" name="myfield" >
<option class="blank" value="">-- All items --</option>
#for((key, value) <- MyModel.options) {
#if(key == GETValuePassedToTemplate) {
<option value="#key" selected>#value</option>
} else {
<option value="#key">#value</option>
}
}
</select>
Still wondering if there is a better option / way to do it.
Actually, there is a nicer solution to it. If you call the template having the form partially bound you will achieve your goal. Here's the code for your controller:
Ok(views.html.myForm(myForm.bind(
Map("fieldName1" -> "value1",
"fieldName2" -> "value2"))))
Make sure you map fieldnames to the values of the options you want pre-selected.
Still wondering if there is a better option / way to do it.
Well, if your not hell-bent on using play to solve this particular problem, you could always solve it using JavaScript and jQuery:
$(function () {
$('#yourSelect_id').val(5);
}
Where your select options each has values and the one option you whish to pre select has value 5.

Changing context element dynamically regarding some condition in Sitecore CMS

I have user control under Sitecore CMS. It has some controls bound to some fields of context. For example:
<sc:text runat="server" field="HomePage_WelcomeText"></sc:text>
I have different content items based on the same template and I need to change context to some of them in PageLoad(). For example, if URLRefferer has certain value I want to have certain content item in context.
Any hints?
The sc:text control has a public property called Item that takes a Sitecore.Data.Items.Item. So, give your control an ID attribute, then on Page_Load you can dynamically set that Item property as needed.
<sc:text id="myTextControl" runat="server" field="HomePage_WelcomeText" />
protected void Page_Load(object sender, EventArgs e)
{
Sitecore.Data.Items.Item myItem = Sitecore.Context.Database.GetItem("/sitecore/content/home");
myTextControl.Item = myItem;
}