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:
Related
While adding an existing site column to a SharePoint list, we get an option to set if the column need to be added to all content types or not.
I tried to un-check this property and the site column gets added to the library locally (i.e. without being used in any content type).
Add Columns from Site Columns
List of columns
How can I achieve it programmatically? Currently I am using below code which always adds the column to the default content type.
I do not want the column to be added to any content type.
if (!list.Fields.ContainsField(reportField.ToString()))
{
list.Fields.Add(reportField);
list.Update();
}
An option would be to use the [AddFieldAsXml][1] method and set the AddFieldOptions parameter to AddToNoContentType. See example below:
list.Fields.AddFieldAsXml(fieldSchemaXml, false, (AddFieldOptions.AddToNoContentType));
list.Update();
If building the field Schema XML is not an option, then you could set the content types to read only whilst you add additional fields then set them back after. This will stop all fields being added to the content types by the AddField method that you are currently using.
Method AddFieldAsXml makes it possible to set 'add to all content types' to false. Option 'AddToNoContentType' should be added to the method AddFieldAsXml as the 3rd parameter.
PowerShell script example:
$ctx=New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
$ctx.Credentials = New-Object System.Management.Automation.PSCredential($Username, $(convertto-securestring $Password -asplaintext -force))
$fieldSchemaXml="<Field Type='Text' DisplayName='Name' Required='False' MaxLength='255' StaticName='Name' Name='Name' />"
#Add Column to the List
$List.Fields.AddFieldAsXml($fieldSchemaXml, $False, [Microsoft.SharePoint.Client.AddFieldOptions]::AddToNoContentType)
$List.Update()
$ctx.ExecuteQuery()
More detailed information about method AddFieldAsXml can be found in the documentation at the link: https://learn.microsoft.com/en-us/dotnet/api/microsoft.sharepoint.spfieldcollection.addfieldasxml?redirectedfrom=MSDN&view=sharepoint-server.
More detailed information about all AddFieldOptions can be found in the documentation at the link: https://learn.microsoft.com/en-us/dotnet/api/microsoft.sharepoint.spaddfieldoptions?redirectedfrom=MSDN&view=sharepoint-server.
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.
I am customizing NewForm.aspx in SP2013 in Designer 2013. I am struggling to get column values from XSLT list view web part in SharePoint designer 2013. I need to manipulate with columns in JQuery to do some action (like hiding, disabling etc.). Currently, I am getting column ID via Developer tool hovering over it but this is not proper way since ID will change in Quality/Production.
Example:-
$("#ctl00_ctl33_g_1ea47d6f_1fed_4426_8e49_cda9970429d6_ff21_ctl00_ctl00_TextField").val("Close");
I want something like:-
$("#column2").val("Close");
My XSLT in SP Designer 2013 looks like:-
<tr><td>
<H3>column2</H3>
</td>
<td>
<SharePoint:FormField runat="server" id="ff3{$Pos}" ControlMode="Edit"
FieldName="column2" __designer:bind="
{ddwrt:DataBind('u',concat('ff3',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(#ID)),'#column2')}"/>
<SharePoint:FieldDescription runat="server" id="ff3description{$Pos}" FieldName="column2" ControlMode="Edit"/>
</td>
</tr>
Please assist.
It's standard ASP.NET behavior that ID of server control is not ID of HTML element that is representing the control. And many of SharePoint controls are rendered by many DIVs and SPANs (especially columns like people, formatted text, ...). So reading and setting values of them is quite complicated process.
Generally you can use title attribute to search for HTML tag that contains HTML element of particular field. Title attribute contains name of the field. For required fields it contains also required information. Or you can try to search for elements with ID starting with internal name of the field. But in both cases you will need to add some additional logic to find the right control containing the value of the field. The logic will need to reflect the type of field you are looking for.
The easiest way is to use some libraries like SPJSutility or form designer to manipulate with form fields.
You can not disable even the simplest textboxes by setting enabled attribute to false because in that case the value will not be processed on the server.
I'm using a ColdFusion autosuggest for my UserID field. When a user starts to type in a UserID, a list of user ids and the user names associated with it pop up (populated by a cfc function). Sample code:
<cfinput name="userID" type="text" value="#userID#" autoSuggest="cfc:Utilities.suggestUser({cfautosuggestvalue})" matchcontains="true" />
The suggestions are listed in the format "User Name <userID>". So if the user would start typing 123, a sample suggestion that would pop up would be "Harvey Mann <1234>".
The problem is that if the user chooses that suggestion, I don't want to insert the whole suggested text into the input field - I just want to insert the user id ("1234" in this case). I would also like to be able to insert the user name ("Harvey Mann") into an adjacent field/area if possible. Is there any way to accomplish this?
Since you are using CF's built-in implementation of autosuggest, you are stuck with only having access to one returned value. Thus if the value consists of mutliple 'parts' and you want to insert different 'parts' of the value into different columns, you will have to parse the value and extract appropriate parts from the string. In your example case you could treat the value as a list delimited by <. In this case you can get the name 'part' with
trim(listfirst(form.userID, "<"))
and the id 'part' with
replace(listlast(form.userID, "<"), ">", "")
Alternatively, you can always use jQuery UI Autocomplete implementation - you'll have to write your own javascript for it, but it gives you far more control than the built-in cf's implementation. Check jQuery UI docs for more info: http://jqueryui.com/demos/autocomplete/
UPDATE:
On second thought, if you just want to display selected value's 'name' part in another area on the same page, you may be able to do it using just CF's built-in autosuggest and a bit of javascript. Try adding this code to the HEAD section of your page:
<cfajaxproxy bind="javaScript:showName({userID})">
<script type="text/javascript">
showName = function(strUserId) {
document.getElementById("someID").innerHTML = strUserId.split('<')[0];
}
</script>
I have data template dt1 in sitecore that has the field "header" in section "data".
I also have data template dt2 that has the field "header" in section "portal"
Finally I have data template dt3 that uses both dt1 and dt2 as base templates.
How can I, in xslt, find the content of portal/header?
In my code, when I write <sc:text field="header" />, I get the content of data/header (since this node comes first).
I know how to do this in .net, but I need to use xslt.
/callprat
I found a way around this in .Net on a project I was working on. One of the templates that the client had set up had "Buckets" which had different field sections, but the fields within were the same between buckets. I used LINQ to group the fields by Section name, then dealt with each grouping of fields.
var sections = currentItem.Fields.GroupBy(field => field.Section);
foreach (var section in sections)
{
if (section.Key.StartsWith("Bucket"))
{
buckets.Add(new Bucket(section)); //I made a bucket item,
//and passed each IGrouping<Field> to it
}
}
item.Fields.Where(field => field.Section.ToUpper() == "META DATA" &&
field.DisplayName.ToUpper() == "TITLE").First().Value;
You can't.
And frankly I don't know of any supported way to do it from .NET either.
This, straight out of the Data Definition Reference, section 2.1.1
2.1.1 Data Template Fields
A data template field defines the user
interface control and other properties
that influence how the field behaves
in the Content Editor and Page Editor.
For more information about fields, see
Chapter 4, The Template Field.
Note When defining field names, ensure
that they are unique even between
field sections. Both XSLT and .NET
code use field names alone, without
reference to sections, to extract
content from fields.
You can reference fields by their IDs:
C#:
string value = item["{00000000-0000-0000-000000000000}"]
or
Field field = item.Fields["{00000000-0000-0000-000000000000}"]
I haven't tried this, but I think it'll work in XSLT as well:
<sc:text field="{00000000-0000-0000-000000000000}" />