When a new node is created it is always added at the bottom in the Umbraco tree. Is there an easy way for the created node to appear at the top in the tree right under the parent?
Should I create an event after a new node is created which updates the sort value of all nodes or is there a better way?
Yes, I'd say you have to sort the nodes in an event handler. Which can be tricky, programmatically, because you have to update the DB, the XML cache, the preview XML, etc etc etc.
That's what I thought. Guess that means I'll need to get all the nodes under the parent (as Document), update the sort value and publish them if they already are published:
Beware! One nasty bug here. If you publish a node that is already published, then you'll publish ongoing changes. That is, if you already have node A and B and both are published, and you edit and save (but do not publish) node A... then add node C, you'll inadvertently publish node A.
Here's some code we're using to reorder one document's children.
public static void ReorderChildren(this Document document, IEnumerable<Document> children, bool refreshEntireCache) { // this is copied and adapted from nodeSorter.asmx.cs
// this is insane, there is absolutely no concurrency management in umbraco ?! lock (LockObject(document)) { bool pathPublished = document.PathPublished;
int sortOrder = 0; foreach (Document child in children) { child.sortOrder = sortOrder++;
if (child.Published) { // refresh sort order in cmsContentXml child.refreshXmlSortOrder(); // refresh document in cache, only if cached if (pathPublished) umbraco.library.UpdateDocumentCache(child.Id); }
// refresh sort order in preview xml (cmsPreviewXml) child.refreshPreviewXmlSortOrder(); }
// refresh sort order on cached xml if (document.Published) { // use UmbracoContext because Instance.XmlContent fails with preview //var umbracoXML = umbraco.content.Instance.XmlContent; var umbracoXML = umbraco.presentation.UmbracoContext.Current.GetXml(); XmlNode node = umbracoXML.GetElementById(document.Id.ToString()); umbraco.content.SortNodes(ref node); }
I'm aware of the problem about of publishing ongoing changes. That's why I started a thread for it here, but I don't think it will be added to the core: https://groups.google.com/forum/#!searchin/umbraco-dev/partial$20publish/umbraco-dev/5LR6fxt6XJU/YVQF4qmolrkJ. Your code looks like a better solution :-). Thanks!
I have a solution using the ContentService in v6.1. Thanks to Murray for pointing me in the right direction.
It uses the splendidly named IRememberBeingDirty interface to check if the content is new. It also allows you to enter a list of the templates to restrict the event firing on and it will only fire on content lists with a single value, not e.g. when sorting the tree or moving multiple nodes etc.
public class UmbracoEventHandler : ApplicationEventHandler
{
public UmbracoEventHandler()
{
ContentService.Saving += OnSaving;
}
/// <summary>
/// On save, if there is one item to save, if the item is new (uses IRememberBeingDirty) and the template is in the acceptable list...
/// The sort order is set to one less than the current top child in the list to ensure the content appears at the top of its node tree.
/// </summary>
void OnSaving(IContentService sender, SaveEventArgs<IContent> args)
{
if (args.SavedEntities.Count() == 1)
{
var dirty = (IRememberBeingDirty)args.SavedEntities.First();
var isNew = dirty.WasPropertyDirty("Id"); // N.B. In 6.2+ use: content.IsNewEntity();
var templates = new List<string> { "ApplicationDetailPage", "EventGenericDetailPage", "GenericDetailPage", "TechnologyDetailPage" };
if (isNew && args.SavedEntities.First().Level > 1 && args.SavedEntities.First().Template != null && templates.Contains(args.SavedEntities.First().Template.Alias))
{
var firstChild = args.SavedEntities.First().Parent().Children().OrderBy(o => o.SortOrder).FirstOrDefault();
if (firstChild != null)
{
args.SavedEntities.First().SortOrder = firstChild.SortOrder - 1;
}
}
}
}
}
New node at top in the tree
Hello,
When a new node is created it is always added at the bottom in the Umbraco tree. Is there an easy way for the created node to appear at the top in the tree right under the parent?
Should I create an event after a new node is created which updates the sort value of all nodes or is there a better way?
Jeroen
Yes, I'd say you have to sort the nodes in an event handler. Which can be tricky, programmatically, because you have to update the DB, the XML cache, the preview XML, etc etc etc.
That's what I thought. Guess that means I'll need to get all the nodes under the parent (as Document), update the sort value and publish them if they already are published:
Can't wait for that new API in v6. Should make things like this easier :-).
Jeroen
Beware! One nasty bug here. If you publish a node that is already published, then you'll publish ongoing changes. That is, if you already have node A and B and both are published, and you edit and save (but do not publish) node A... then add node C, you'll inadvertently publish node A.
Here's some code we're using to reorder one document's children.
Hello,
I'm aware of the problem about of publishing ongoing changes. That's why I started a thread for it here, but I don't think it will be added to the core: https://groups.google.com/forum/#!searchin/umbraco-dev/partial$20publish/umbraco-dev/5LR6fxt6XJU/YVQF4qmolrkJ. Your code looks like a better solution :-). Thanks!
Jeroen
Hello,
I tried to use your code example, but I'm missing some pieces. Could you please show those parts as well? I'm missing:
LockObject(document)
document.PathPublished
child.refreshPreviewXmlSortOrder();
Thanks :).
Jeroen
Hi Jeroen,
I think you could also use Document Sorter and have it sort by createDate Descending to achieve the same effect.
HTH,
Tom
Here's my solution, which I devised to avoid updating any document apart from the one being inserted.
...
I have a solution using the ContentService in v6.1. Thanks to Murray for pointing me in the right direction.
It uses the splendidly named IRememberBeingDirty interface to check if the content is new. It also allows you to enter a list of the templates to restrict the event firing on and it will only fire on content lists with a single value, not e.g. when sorting the tree or moving multiple nodes etc.
is working on a reply...