November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
Hi,
In your ItemBlock, if you could set a ContentReference property for the ItemsGroupBlock, it would be pretty easy from there to get an IContent from the ContentReference, then cast that as an ItemsGroupBlock. From there, you would have access to all the string properties to populate the ISelectionFactory of your ItemBlock.
Hope that helps.
Thanks!
John
Hey there, it helps a little. I'm afraid I'm a newbie at this. Would you mind spelling it out a little more? I have added the contentreference property to my item block. Where do I go from here?
Hi,
So, after thinking about this more and playing around a bit, what I described above will not work, unless you are going to only have 1 ItemsGroupBlock and 1 ItemBlock ever (which really defeats the purpose of blocks in Episerver). The problem is that your ItemSelectionFactory class is completely separate from your block class, and there is no way (that I know of anyway) to get a ContentReference to a specific block inside of it, and also no way to pass that reference into the attribute that decorates your string in the ItemBlock.
Let's say you would only have 1 instance of either. Then, you could add the ContentReference of the ItemsGroupBlock to the StartPage model. Inside of the ItemSelectionFactory class, you can easily get a reference to the StartPage using IContentLoader and from there, get the reference you your ItemsGroupBlock and it's properties. But like I said, it would only work for 1 instance each of the blocks, which I assume is not what you want. Perhaps someone else has an idea?
-John
OK, thank you for the time in answering. I knew it was a stretch. Hopefully there's a solution but if not, oh well, the client will get what they get.
Hey,
You can fetch the block in the selection factory, try sth like this out:
public class SomeStringsSelectionFactory : ISelectionFactory
{
public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
{
List<SelectItem> selections;
dynamic contentMetadata = metadata;
var ownerContent = contentMetadata.OwnerContent as IContent;
// fetch from the current block the definition block (as a reference, perhaps, as John suggested or as a property on some page in the particular relation to the block)
// read the five unique properties and pack as ISelectItems
}
}
BR,
Marija
Hi Marija, I'm sorry but I'm a newbie. Could you spell it out for me a little more?
Hi, Nathan,
I'm sending an example block with this functionality. However, I am not sure how you imagined to fetch the other block, so in this example, I just took block's parent and if it's a NewsPage, I take it's content guid and take each character from it, just for fun. But, if you send how your blocks are structured or if you can have the block with string properties as a property on my "NewsPage", then you can simply read that instead of ContentGuid.
[ContentType] public class SomeBlock : BlockData { [UIHint("SomeStringHint")] public virtual string SomeString { get; set; } } [EditorDescriptorRegistration(TargetType = typeof(string), UIHint = "SomeStringHint")] public class SomeStringEditorDescriptor : EditorDescriptor { public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes) { SelectionFactoryType = typeof(SomeStringSelectionFactory); ClientEditingClass = "epi-cms/contentediting/editors/SelectionEditor"; base.ModifyMetadata(metadata, attributes); } } public class SomeStringSelectionFactory : ISelectionFactory { public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata) { List<SelectItem> selections; dynamic contentMetadata = metadata; var ownerContent = contentMetadata.OwnerContent as IContent; var parentPage = ownerContent.GetParent(); if (parentPage is NewsPage) { selections = parentPage.ContentGuid.ToString() .ToCharArray() .Select(c => new SelectItem { Text = c.ToString(), Value = c }).ToList(); } else { selections = "abcd".ToCharArray().Select(c => new SelectItem { Text = c.ToString(), Value = c }).ToList(); } return selections; } }
BR,
Marija
Heck yeah Marija! So, the piece I was missing was:
dynamic contentMetadata = metadata; var ownerContent = contentMetadata.OwnerContent as IContent;
So, Nathan, I just tested a working sample and here is the code for both blocks and the selection factory:
namespace AlloyTraining.Models.Blocks { [ContentType(DisplayName = "Items Group Block", GUID = "YourGUID", Description = "")] public class ItemsGroupBlock : BlockData { [CultureSpecific] [Display( Name = "String One", Description = "", GroupName = SystemTabNames.Content, Order = 1)] public virtual string String1 { get; set; } [CultureSpecific] [Display( Name = "String Two", Description = "", GroupName = SystemTabNames.Content, Order = 2)] public virtual string String2 { get; set; } [CultureSpecific] [Display( Name = "String Three", Description = "", GroupName = SystemTabNames.Content, Order = 3)] public virtual string String3 { get; set; } } }
namespace AlloyTraining.Models.Blocks { [ContentType(DisplayName = "ItemBlock", GUID = "YorGUID", Description = "")] public class ItemBlock : BlockData { [CultureSpecific] [Display( Name = "Items Group Block", Description = "", GroupName = SystemTabNames.Content, Order = 1)] [AllowedTypes(typeof(ItemsGroupBlock))] public virtual ContentReference ItemsGroupBlock { get; set; } [CultureSpecific] [Display( Name = "Select Items", Description = "", GroupName = SystemTabNames.Content, Order = 1)] [SelectOne(SelectionFactoryType = typeof(ItemSelectionFactory))] public virtual string Items { get; set; } public class ItemSelectionFactory : ISelectionFactory { public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata) { var loader = ServiceLocator.Current.GetInstance<IContentLoader>(); var list = new List<SelectItem>(); dynamic contentMetadata = metadata; var ownerContent = contentMetadata.OwnerContent as IContent; var block = ownerContent as ItemBlock; if (block.ItemsGroupBlock != null) { var itemsBlock = loader.Get<ItemsGroupBlock>(block.ItemsGroupBlock); if (itemsBlock.String1 != null) { list.Add(new SelectItem() { Text = itemsBlock.String1, Value = itemsBlock.String1 }); } if (itemsBlock.String2 != null) { list.Add(new SelectItem() { Text = itemsBlock.String2, Value = itemsBlock.String2 }); } if (itemsBlock.String2 != null) { list.Add(new SelectItem() { Text = itemsBlock.String3, Value = itemsBlock.String3 }); } } return list; } } } }
I am pretty sure this is what you were after. Basically, the OwnerContent variable gets an IContent of the block that contains the selection factory. I take that and cast it to an ItemBlock. From there, I check if the ContentReference to the ItemGroupBlock exists, and if it does, I use IContentLoader to load an instance of it and read the string properties into the list that gets returned. There may be a more elegant way to do all that, but I wanted to show a quick example of the concept. I tested it locally and it is working as expected.
Thanks!
John
Now there's another problem, I'm not sure how to buy you each a drink to say thanks! This worked exactly like I was looking. So thank you both for putting in the time to help me. If you're ever in New York City, hit me up! Merry Christmas to you both.
Haha, deal! Maybe we take a beer in Vegas for Ascend 2017 instead ;)
Cheers both and Merry Christmas!
Is it possible to connect properties from one block model to be the choices for an ISelectionFactory on another block model? Not sure if I'm wording that correctly, but like this...
ItemsGroupBlock
five unique String properties (String1, String2, String3...)
ItemBlock
one String property, using ISelectionFactory for the choices GetSelections(ExtendedMetadata metadata)
so it would read the string values in the ItemsGroupBlock model props and populate the SelectItem() objects' Text and Value with those values.
public class ItemSelectionFactory : ISelectionFactory
{
public IEnumerable
{
return new ISelectItem[] {
new SelectItem() { Text = "String1", Value = "String1" },
new SelectItem() { Text = "String2", Value = "String2" },
new SelectItem() { Text = "String3", Value = "String3" },
new SelectItem() { Text = "String4", Value = "String4" }
};
}
}
I hope this makes sense what I'm asking but if not, I'll try to clarify further. Is it possible? Thanks!