November Happy Hour will be moved to Thursday December 5th.

Grid Template vs List Template Listing Block

Vote:
 

I have been doing some reading up on blocks, display options, rendering and template discriptors, and trying to imlement a display option for either a grid view listing or a list view listing.

I have the display options added for grid and list options but, and correct me if I am wrong, I now want to select a different template based on the display option that has been selected upon the block.

I am working with the Alloy Template and the below is what I have added so far:

DisplayRegistryInitialization

var options = ServiceLocator.Current.GetInstance();
options
.Add("grid", "/displayoptions/grid", Global.ContentAreaTags.Grid, "", "epi-icon__layout--full")
.Add("list", "/displayoptions/list", Global.ContentAreaTags.List, "", "epi-icon__layout--full")

TemplateCoordinator

viewTemplateModelRegistrator.Add(typeof(PageListBlock), new TemplateModel
{
Name = "PageListBlockGrid",
Tags = new[] { Global.ContentAreaTags.Grid},
AvailableWithoutTag = false,
Path = BlockPath("Grid.cshtml")
});
viewTemplateModelRegistrator.Add(typeof(PageListBlock), new TemplateModel
{
Name = "PageListBlockList",
Tags = new[] { Global.ContentAreaTags.List },
AvailableWithoutTag = false,
Path = BlockPath("List.cshtml")
});

But it doesn't seem to pick-up my grid.cshtml template and list.cshtml template.

Would anybody be able to point me in the right direction?

#120295
Apr 14, 2015 18:30
Vote:
 

What is rendered instead? If you are using Alloy block preview template - what is shown under `Global.ContentAreaTags.Grid` and `Global.ContentAreaTags.List` preview regions in that template?

I just replicate your setup in Alloy and correct templates are picked up..

#120298
Apr 14, 2015 19:06
Vote:
 

Hi Valdis

Just checked in the admin and the display option is showing correctly.

I have the following in Global:

public static class ContentAreaTags
{
public const string Grid = "grid";
public const string List = "list";
public const string FullWidth = "span12";
public const string TwoThirdsWidth = "span8";
public const string HalfWidth = "span6";
public const string OneThirdWidth = "span4";
public const string NoRenderer = "norenderer";
}

I think what I am getting confused with is how does this know how to select either grid.cshtml or list.cshtml?

Thanks

#120300
Edited, Apr 14, 2015 19:21
Vote:
 

Tags are added to block instance when placed inside content area - content area item. You can change display option for block via context menu for that block - when editting content of the area.

When you open that block in Edit (where all supported display modes are shown) - what is shown in "Grid" and "List" regions?

#120307
Apr 14, 2015 20:05
Vote:
 

Here should be some screenshots of the views in episerver,

Grid Display Option and List Display Option

https://www.dropbox.com/s/atf3sqgojsht3ic/Block%20Edit.JPG?dl=0

Source

Edit Display Option source

https://www.dropbox.com/s/405n5zcnsrxdlr7/Block%20Edit%20Source.JPG?dl=0

From what I can see all this is doing is added a class of grid or list not actually taking the grid.cshtml view or list.cshtml view

Thanks

Paul

#120320
Edited, Apr 15, 2015 10:42
Vote:
 

Do you have controller for PageListBlock?

#120329
Apr 15, 2015 11:33
Vote:
 

Yip sure do see below:

public class PageListBlockController : BlockController<PageListBlock>
    {
        private ContentLocator contentLocator;
        private IContentLoader contentLoader;
        public PageListBlockController(ContentLocator contentLocator, IContentLoader contentLoader)
        {
            this.contentLocator = contentLocator;
            this.contentLoader = contentLoader;
        }

        public override ActionResult Index(PageListBlock currentBlock)
        {
            var pages = FindPages(currentBlock);

            pages = Sort(pages, currentBlock.SortOrder);
            
            if(currentBlock.Count > 0)
            {
                pages = pages.Take(currentBlock.Count);
            }

            var model = new PageListModel(currentBlock)
                {
                    Pages = pages
                };

            ViewData.GetEditHints<PageListModel, PageListBlock>()
                .AddConnection(x => x.Heading, x => x.Heading);

            return PartialView(model);
        }

        private IEnumerable<PageData> FindPages(PageListBlock currentBlock)
        {
            IEnumerable<PageData> pages;
            var listRoot = currentBlock.Root;
            if (currentBlock.Recursive)
            {
                if (currentBlock.PageTypeFilter != null)
                {
                    pages = contentLocator.FindPagesByPageType(listRoot, true, currentBlock.PageTypeFilter.ID);
                }
                else
                {
                    pages = contentLocator.GetAll<PageData>(listRoot);
                }
            }
            else
            {
                if (currentBlock.PageTypeFilter != null)
                {
                    pages = contentLoader.GetChildren<PageData>(listRoot)
                        .Where(p => p.PageTypeID == currentBlock.PageTypeFilter.ID);
                }
                else
                {
                    pages = contentLoader.GetChildren<PageData>(listRoot);
                }
            }

            if (currentBlock.CategoryFilter != null && currentBlock.CategoryFilter.Any())
            {
                pages = pages.Where(x => x.Category.Intersect(currentBlock.CategoryFilter).Any());
            }
            return pages;
        }

        private IEnumerable<PageData> Sort(IEnumerable<PageData> pages, FilterSortOrder sortOrder)
        {
            var asCollection = new PageDataCollection(pages);
            var sortFilter = new FilterSort(sortOrder);
            sortFilter.Sort(asCollection);
            return asCollection;
        }

I am guessing here I need to add some sort of Template Descriptor?

#120330
Apr 15, 2015 11:38
Vote:
 

Please dump content of `templates` list:

var repo = ServiceLocator.Current.GetInstance<TemplateModelRepository>();
var templates = repo.List(typeof(PageListBlock)).Where(t => t.TemplateTypeCategory == TemplateTypeCategories.MvcPartialView);
#120335
Edited, Apr 15, 2015 12:25
Vote:
 

Here is the output, it is only returning the norendertemplate.

templates render output

https://www.dropbox.com/s/ayvqk1jpwqyuvfr/templates.JPG?dl=0

#120341
Edited, Apr 15, 2015 13:41
Vote:
 

So as you see - template registration has failed for those tags. Can you verify that grid.cshtml and list.cshtml is really located in those folders, that view engine is capable to find them?

#120343
Apr 15, 2015 13:47
Vote:
 

I have changed the paths on the template resolver and they are now point tothe correct templates.

However I get an error 'The model item passed into the dictionary is of type 'Castle.Proxies.PageListBlockProxy', but this dictionary requires a model item of type 'Project.Models.ViewModels.PageListModel'.'

Would I need to add something to the PageListBlockController to handle the Grid or List view tags now and return a PageListModel?

#120365
Apr 15, 2015 18:51
Vote:
 

Oh, ok. Now I got it (I hope).

So, this is the detailed explanation: when you are using template registrator - you are instructing EPiServer - "please, if you see this block type and these tags applied and maybe these settings also applied, please go to specified path and render block using that template". This will prevent your controller to kick in. Basically you are helping EPiServer to complete registration for content templates that were not automatically discovered.

What you need to do instead is

a) delete template registrator entries for grid and list

b) add following attribute to your page list block controller:

[TemplateDescriptor(AvailableWithoutTag = false,
    ModelType = typeof(PageListBlock),
    Name = "pagelistblock",
    Default = true,
    Tags = new[] { Global.ContentAreaTags.Grid, Global.ContentAreaTags.List })]

Then template selection is up to the controller to decide. You can retrieve currently selected display option with following code (not sure that this is the most optimal though):

var settings = RouteData.Values["RenderSettings"] as Dictionary<string, object>;
if (settings != null)
{
    var displayOption = settings["tag"] as string;

    if (displayOption == Global.ContentAreaTags.Grid)
    {
        return PartialView("~/Views/Shared/Blocks/grid.cshtml", model);
    }
}

Keep in mind if editor will select other display option for that content and there will be no registered renderer for that `tag` - content will not be rendered.

#120368
Edited, Apr 15, 2015 21:24
Vote:
 

Thats it, i'll keep that in mind.

Thanks for the help.

#120405
Apr 16, 2015 10:25
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.