Is there a way to create a unordered list with subitems from 1 content-type - list

I would like to create a organogram like:
https://codepen.io/bernardoantunes/pen/inrbh using 2sic Content.
I would like to create a content-type 'organogram' with the following fields:
Title as String
Parent as Entity (of type Organogram)
Description as String
Link as Hyperlink
Using this content-type i would add some elements where child elements could be created.
for example:
- Root
- Child 1 (Root is selected in the Parent field)
- Child 2 (Root is selected in the Parent field)
- Child 3 (Child 2 is selected in the Parent field)
Could this be done using 2sic content App?
I created the content-type and added some elements. Created a razor template and then it gives an error.
operator '==' can not be applied to operands of type System.Collections.Generic.List and ToSic.SexyContent.DynamicEntity
Razor template:
#using Connect.Koi;
#{
var first = AsDynamic(Data["Default"]).First();
var all = AsDynamic(Data["Default"]);
}
<div>#first.Title</div>
var children = all.Where(x => x.parent == first).ToList();
<div>#children.Count</div>

Basically the AsDynamic(...) creates wrapped entity-objects, whereas ...parent gives you a list of related items (because it could have more than 1 parent). If this is the code you want to use, I suggest 1 things.
On the .parent (which should probably be .Parent) use the [0] or .FirstOrDefault() so it's .Parent.FirstOrDefault() == first - remember to enable LINQ by #using System.Linq
Don't compare the AsDynamic objects, because they will be different objects. Better compare the id using .EntityId or something.
So you're resulting compare will probably be .Parent[0].EntityId == first.EntityId.
What I don't like about your solution is the idea, that the first item in the Default-list will somehow be the important one. This doesn't feel right, but I don't know your whole solution...

Related

EcorResCategory get childrens x++

I need to get all childrens (and its childrens) for a parent product category
example:
Parent
-- child 1
-- child 2
---- child 2.1
---- child 2.2
-- child 3
I am using the EcoResCategory.getChildren() method but it gets the first children only.
"but it gets the first children only"
I don't think that is correct. If you take a look at the references of the EcoResCategory.getChildren() method, there is method WarrantyLookupProcessingJob.updateLookupCategory() that shows the following pattern:
EcoResCategory childCategory = parentCategory.getChildren();
while (childCategory)
{
next childCategory;
}
The next keyword retrieves the next record from the childCategory table buffer. See also https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-ref/xpp-data/xpp-select
Also note that the getChildren method has a _levelLimit parameter with the following documentation:
An <c>EcoResCategoryLevel</c> value that indicates the maximum level of children categories to retrieve.

Oracle APEX Compare Two Items Values to Fire a Dynamic Action

I want to create a Dynamic Action thats when my page item P2014_BALANCE < P2014_CURRENT_PRICE then P2014_CURRENT_PRICE gets the static value 0.
The problem is that i can't compare these two page items. I try to when section in my Dynamic Action to use Javascript expression like this:
if(apex.item( "P2014_CURRENT_PRICE " ).getValue() < apex.item( "P2014_CURRENT_PRICE " ).getValue()){
alert('Wrong Number');
};
but when my page loads gets an error (even Fire on Initialization = False).
I also try this:
still nothing.
This is a web application. All page items contain string values. So if you want to do number comparison, make them numbers:
if (Number(apex.item( "P2014_BALANCE" ).getValue()) < Number(apex.item( "P2014_CURRENT_PRICE" ).getValue())) {
alert('Wrong Number');
};
Note that in your example you have P2014_CURRENT_PRICE twice - that will always yield false anyways.
This is how you would implement this in a dynamic action. Note that I tried on 21.1 but it should be similar in 5 (consider upgrading):
Dynamic Action on Change of Item P2014_CURRENT_PRICE with client Side Condition of type Javascript Expression
Source:
apex.locale.toNumber(apex.item( "P2014_CURRENT_PRICE" ).getValue()) > apex.locale.toNumber(apex.item( "P2014_BALANCE" ).getValue())
True Action with Action Set Value
Set Type Static Assignment
Value "0"
Affected Element Item P2014_CURRENT_PRICE

Add empty option to List Validator

I'm trying to add the option to my users that, on a List Validator, to allow select any of the options or a blank option. Spreadjs has the IgnoreBlanks setting, which I use, so when the user uses the delete key or the backspace and deletes the cell it validates correctly.
However, I would love to use the same functionality as in Excel, which allows blank options in the list validator, in part of the list.
I've tried to target the <select> element that holds the list and programmatically add the empty element, however, it crashes after the user selects the empty option.
I've also tried to add different escaped characters to the list. If I select a character that represents an empty string or a tab, it won't add a new option to the list. If I use any strange character, or even the null character \0 you get a new option to select, but the content is that typical rectangle you see when your font doesn't have the character you're trying to display.
I've also tested using a regular ListValidator like in the example pages, not our custom functionality and doesn't work either.
https://www.grapecity.com/demos/spread/JS/TutorialSample/#/demos/basicDataValidator
I have also tried creating a FormulaListValidator, and if my range has empty cells I could then get an empty option on my list, however, because the range may have duplicates, I get duplicated options.
After researching a little bit I found a workaround in a different language which I adapted to Typescript (Angular 6)
export const getListValidatorFromArray = (spread: GC.Spread.Sheets.Workbook, data: any[]) => {
// saving validation list values in a hidden sheet
spread.addSheet(spread.getSheetCount());
const sheet = spread.getSheet(spread.getSheetCount() - 1);
sheet.visible(false);
for (let i = 0; i < data.length; i++) {
sheet.setValue(i, 0, data[i]);
}
// create validator based on the values
const dv = GC.Spread.Sheets.DataValidation.createFormulaListValidator(
'=' + sheet.name() + '!$A$1:' + sheet.name() + '!$A$' + data.length
);
return dv;
};
Note: This creates an extra sheet for each validator you create. Makes sure you reuse them as much as possible (i.e. assigning it to a variable when it's created, and reusing the variable for other columns/rows that use the same one).

Can I programmatically find a Sitecore item's parent matching a certain template id?

I have a custom Sitecore command that I would like to expand upon to determine if the current item has a parent item matching a certain template id.
When the command/button is clicked, I will have access to the current Item.
My initial attempt, since I had issues with escaping the FullPath for use in a query, was to loop through the parent item (and then that item's parent, etcetera) to determine if any matched the template.
However, there seems like there should be a better way to do this.
So given an item, what's the best way to find whether it has a parent item that is of a certain template?
SXA way
public static Item GetParentOfTemplate(this Item item, ID templateId)
{
if (item == null)
{
return null;
}
ItemRelationCacheValue itemRelationCacheValue = ParentOfTemplateCache.GetCacheForDatabase(item.Database.Name)?.Get(item, templateId);
if (itemRelationCacheValue != null)
{
return item.Database.GetItem(itemRelationCacheValue.OutputID);
}
Template template = TemplateManager.GetTemplate(templateId, item.Database);
if (template == null)
{
return null;
}
ID iD = item.ID;
while (item != null)
{
Template template2 = TemplateManager.GetTemplate(item);
if (template2 != null && template2.DescendsFromOrEquals(template.ID))
{
ItemRelationCacheValue value = new ItemRelationCacheValue(iD, item.Database.Name, templateId, item.ID);
ParentOfTemplateCache.GetCacheForDatabase(item.Database.Name)?.Set(value);
return item;
}
item = item.Parent;
}
return null;
}
There's not really a good way to do it. In a regular system you'd do it in SQL, but Sitecore has obfuscated their 'Nexus' code which I believe is where all of this data access/mapping logic happens thus I don't really know how that part of Sitecore works so it's a difficult to try to reverse engineer a query to do this efficiently.
What I use in my projects I use a recursive function like this.
I use a delegate to determine if the item is a match for what I'm looking for, and just recurse up the tree - dropping out to return null if it reaches the root node.
public delegate bool ItemSelectionCondition(Item sitecoreItem);
public static Item GetAncestor(Item sitecoreItem, ItemSelectionCondition selectionCondition)
{
Item parent = sitecoreItem.Parent;
if (selectionCondition(parent))
{
return parent;
}
else if (Sitecore.ItemIDs.RootID == parent.ID)
{
return null;
}
else
{
return GetAncestor(parent, selectionCondition);
}
}
So to work with this you'd need to define a delgate something like:
public static bool IsTemplateX(Item item)
{
return item.TemplateID == Constants.TemplateXId;
}
It's quite a simple solution that's flexible enough to work with any Ancestor or Parent type things that I've needed to do.
Be warned though it will take several seconds to run the first time if Sitecore hasn't cached all of the items it needs to look at, but subsequent times it will take a bearable amount of time.
EDIT: Since this answer has gotten a few downvotes I thought I'd explain why it's the best way to do this in Sitecore.
The reson why a recursive approach is better that iterative is two-fold. First, it's less code so it looks nicer - but if that's not enough the second reason is that if you're careful about how you've structured your code and are compiling your project you'll be able to take advantage of tail recursion.
The reason why using Item.Axes.Ancestors (Or Item.Axes.GetAncestors() in later versions of Sitecore) is bad is because it has five steps:
Allocate a List of Items
Iteratively add All Ancestors to that list
Reverse the order of the List
Convert the list to an array
Use Linq to filter the array
This means that you're doing twice as much allocation as if you were to just recurse to the top of the content tree, but you're also ruling out the possibility of exiting the recursion at the first relevant item - and avoiding unecessary calls to the database.
I do have to conceed that the comment about using a Lucene Index however is right - that's the way that is potentially the fastest in almost all scenarios just because it can reduce your time finding the item down to a single Sitecore Query - or no Sitecore Query if you index the data about that ancestor that you need.

Sencha Touch 2 list background change

I have a list within my application, but was wondering if it is possible to have each list displayed show a different background colour, rather than the same one through out each item?
I have created a template but would be nice to have the background of each change colour.
Thanks
EDIT: I have also created the same list via a 'Ext.dataview.component.DataItem' / 'DataView' so if this is easier to control separately then great, as I am looking at interfering in te process of creating each and setting its background, if that is at all possible.
You could try to do that with simply XTemplate:
var tpl = new Ext.XTemplate(
'<p>Name: {name}</p>',
'<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>',
'<p>Kids: ',
'<tpl for="kids">',
'<div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
'{name}',
'</div>',
'</tpl></p>'
);
take a look at their explanations, might find something interesting:
http://docs.sencha.com/touch/2-0/#!/api/Ext.XTemplate
I have seen many variants on the Ext.query('class').up().addCls('backgroundClass'); hack, which makes perfect sense to me, but my question is WHEN are people calling this? I can't put it in 'painted', since DOM doesn't seem to exist yet.. where/when are you guys executing the Ext.get(..) call?
I have been looking for this also, and I had a hard time finding out how to access the individual items of a xlist...
This is the way I finally did it:
in your itemTpl, add a class to your < div >, using the property 'id' of your model:
itemTpl:'< div class="my_list_item_{id}"> ... content ... < /div>'
the tricky part is that if you want to set the background color of the whole item area, you have to access to < div > with class 'x-item-label' that is wrapping your itemTpl < div >.
Here is how I did it (for the first item as an example):
Ext.select('.my_list_item_1').first().up('div.x-list-item-label').addCls('background_item');
where 'background_item' is a CSS style, defining your background color.
(Since there is no way (at least that I know of) to get the index count of your items in the 'itemTpl' config, I had to use to automatic 'id' property of my model/store.
Note that if you apply filtering/sorting/... on your store, this property will not be sorted anymore. So if you want to link the order displayed in your list to the 'id' property, you have to do something like 'Ext.StoreManager.get('MyStore').getAt(indexInList).get('id') )
Hope this helps...
Since Sencha Touch 2.2.1 it's also possible to use striped parameter (more info here). It will add x-list-item-odd class to odd items of your list.