I'm trying to use the Multi-root treelist that Kam Figy made and that Zachary Kniebel extended. I used this guide to add the Field-type to the Core database.
All is well, until I put query:
anywhere in the fields source. In the use-case I have I need to have at least one of the two roots be a query like so:
query:./ancestor-or-self::*[@@templatename='Website']/Sitedata/Facets
The other root can be an absolute path if need be, or a query, for this example let's say it's the content
-root, I've tried these values in the Source-field of the template-field with Multi-root Treelist:
query:./ancestor-or-self::*[@@templatename='Website']/Sitedata/Facets|/sitecore/content
// yields only 1st root, the query, content-root isn't there.
datasource=query:./ancestor-or-self::*[@@templatename='Website']/Sitedata/Facets|/sitecore/content
// yields 2nd root correctly, 1st root defaults to /sitecore root
datasource=query:./ancestor-or-self::*[@@templatename='Website']/Sitedata/Facets|datasource=/sitecore/content
// both roots are now defaulting to /sitecore root
datasource=query:./ancestor-or-self::*[@@templatename='Website']/Sitedata/Facets|datasource=query:/sitecore/content
// again both roots now /sitecore root
query:./ancestor-or-self::*[@@templatename='Website']/Sitedata/Facets|query:/sitecore/content
// yields nothing, no roots shown, completely empty field in content-editor
Whether I use Kam's code or Zachary's code, the results are the same. What's going on?
EDIT:
I've done some digging and I think I've narrowed the problem down somewhat. If the value starts with query:
then Sitecore does the parsing and disregards anything after the |
before passing it on to the custom code. So I'm using the 2nd query, with format datasource=query:./ancestor-etc|/sitecore/content
. And I'm using Kam's code-base extended only with the parts of Zachary's code that parse the query:
as Kam's code didn't do that. So this is my version of Kam's CreateDataContext
:
protected virtual DataContext CreateDataContext(DataContext baseDataContext, string dataSource)
{
Item datasourceItem = null;
if (dataSource.StartsWith("query:"))
{
try
{
var currentItem = Sitecore.Context.ContentDatabase.GetItem(this.ItemID);
var results = LookupSources.GetItems(currentItem, dataSource);
datasourceItem = results.FirstOrDefault(item => item != null);
dataSource = datasourceItem.Paths.FullPath;
}
catch (Exception ex)
{
Log.Error($"Treelist field failed to execute query: '{dataSource}'", ex, this);
}
}
DataContext dataContext = new DataContext
{
ID = GetUniqueID("D"),
Filter = baseDataContext.Filter,
DataViewName = "Master",
Root = dataSource,
Language = Language.Parse(this.ItemLanguage)
};
if (!string.IsNullOrEmpty(this.DatabaseName))
{
dataContext.Parameters = "databasename=" + this.DatabaseName;
}
return dataContext;
}
Stepping into the code, it looks like LookupSources.GetItems()
doesn't like my query as it returns an empty Item
-array. To be clear, this query works perfectly fine when used as a datasource for a controller rendering, so it's not the query itself.
I tried the following in the debugger's Immediate Window while pauzed right after the LookupSources.GetItems()
line above:
LookupSources.GetItems(currentItem, "query:.");
'LookupSources.GetItems(currentItem, "query:.")' threw an exception of type 'Sitecore.Exceptions.LookupSourceException'
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146233088
HelpLink: null
InnerException: {"Index was outside the bounds of the array."}
InnerMessage: "Index was outside the bounds of the array."
Message: "Invalid lookup source \"query:.\": Index was outside the bounds of the array.."
// ^ so the "query:" part should be trimmed, aha
LookupSources.GetItems(currentItem, ".");
{Sitecore.Data.Items.Item[1]}
"Werken bij banner": Werken bij banner (en#1@master), id: {7D9F219F-19EA-4CEB-AC8B-BCE4894D71B1}
// This is the only child-item of the current item. I kinda expected the current Item, not its children.
// But at least LookupSources isn't completely kaput
LookupSources.GetItems(currentItem, "..");
{Sitecore.Data.Items.Item[2]}
// This is the current Item and its only sibling, so far so good
LookupSources.GetItems(currentItem, "./ancestor-or-self::*[@@templatename='website']/sitedata/facets");
{Sitecore.Data.Items.Item[0]}
// Nothing
LookupSources.GetItems(currentItem, "./ancestor-or-self::*");
{Sitecore.Data.Items.Item[0]}
// Nothing still?
LookupSources.GetItems(currentItem, "./ancestor::*");
{Sitecore.Data.Items.Item[57]}
// So maybe ancestor-or-self is kaput and I should use just ancestor?
LookupSources.GetItems(currentItem, "./ancestor::*[@@templatename='website']");
{Sitecore.Data.Items.Item[0]}
// Nope, still kaput
LookupSources.GetItems(currentItem, "./ancestor::*[@@templateid='{299B2290-E128-4633-8F9A-DCCC1CCBA9DE}']");
{Sitecore.Data.Items.Item[0]}
// Google searches use @@templateid in stead of @@templatename, but nope.
LookupSources.GetItems(currentItem, "./ancestor-or-self::*[@@templateid='{299B2290-E128-4633-8F9A-DCCC1CCBA9DE}']");
{Sitecore.Data.Items.Item[0]}
// ancestor-or-self combined with @@templateid just to be sure, alas
// maybe the string isn't parsed correctly before sending it to GetItems() to begin with so lets make it @""
LookupSources.GetItems(currentItem, @"./ancestor::*[@@templateid='{299B2290-E128-4633-8F9A-DCCC1CCBA9DE}']");
{Sitecore.Data.Items.Item[0]}
LookupSources.GetItems(currentItem, @"./ancestor::*[@@templatename='website']");
{Sitecore.Data.Items.Item[0]}
// still nothing...
TL;DR: LookupSources.GetItems()
doesn't seem to do ancestor-or-self
and doesn't do *[@@templatename='Website']
or *[@@templateid='{299B2290-E128-4633-8F9A-DCCC1CCBA9DE}']
. What to do about that or try differently?
_dataSources
has a value before any of the code is ever executed. I don't understand how this can happen. The value of_dataSources
is the result of the query at that point (so a string[1] with an absolute Sitecore path in the only array value).