Umbraco 13 Extract Block List Content

Hello all,

I’m trying to extract some data from block list but having no luck, its probably my rendering code that is wrong.

Steps

  1. I created a data type called Matt Slide and then added “Carousel Slide” as an available block

  2. Carousel Slide is an Element type with all my propertys

  3. Then created a new partial view under block list in the componsents called “carouselSlide”

Inside that I have the following

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage;
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@using Umbraco.Cms.Core.Models.Blocks;
@{
    var variants = Model.Value<IEnumerable<BlockListItem>>("carouselSlide").Select(x => x.Content);
    foreach (var variant in variants)
    {
        <h4>@variant.Value("slideTitle")</h4>
    }
}

But I keep getting the following error

ModelBindingException: Cannot bind source type Umbraco.Cms.Core.Models.Blocks.BlockListItem`2[[Umbraco.Cms.Web.Common.PublishedModels.CarouselSlide, ModelsGeneratedAssembly, Version=0.0.0.1, Culture=neutral, PublicKeyToken=null],[Umbraco.Cms.Core.Models.PublishedContent.IPublishedElement, Umbraco.Core, Version=13.5.3.0, Culture=neutral, PublicKeyToken=null]] to model type Umbraco.Cms.Core.Models.PublishedContent.IPublishedContent.

Thanks

Hi @Matthew2016

Welcome to the forum!

The Content property is an IPublishedElement, so that part is correct.

Here the example from the docs:

@using Umbraco.Cms.Core.Models.Blocks
@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.TestBlockPage>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
    var variants = Model.Value<IEnumerable<BlockListItem>>("variants").Select(x => x.Content);
    foreach (var variant in variants)
    {
        <h4>@variant.Value("variantName")</h4>
        <p>@variant.Value("description")</p>
    }
}

Your issue is the @inherits line at the top - you need to remove it as that is for a page not a block.

Justin

@justin-nevitech

Thanks for getting back to me, ahh I just copied it from the document which included in the inherits.

I’ve removed that now getting the following error

Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.

Thanks

Hi @Matthew2016

Apologies, you do need an @inherits, but it needs to be the correct type based on how you are calling it, for example:

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>

See:

Justin

Thanks @justin-nevitech

Here is my code

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@using Umbraco.Cms.Core.Models.Blocks;
@{
    var variants = Model.Value<IEnumerable<BlockListItem>>("carouselSlide").Select(x => x.Content);
    foreach (var variant in variants)
    {
        <h4>@variant.Value("slideTitle")</h4>
    }
}

My error is

The type or namespace name ‘BlockList’ does not exist in the namespace ‘Umbraco.Cms.Core.Models.Blocks’ (are you missing an assembly reference?)

Any ideas?

Think there is some confusion here.. in that

You’ve created a partial/blocklist/component/carouselSlide.chstml and will be using
@Html.GetBlockListHtml(Model, “YOUR PROPERTY NAME FOR THE BLOCKLIST”) ??

That is used to render the individual items in your blocklist.
So the sample from the docs that applies is

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>;
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
    var content = (ContentModels.MyElementTypeAliasOfContent)Model.Content;
    var settings = Model.Settings as ContentModels.MyElementTypeAliasOfContent; // Cast Model.Settings safely using 'as' to avoid null reference exceptions
}

@* Output the value of field with alias 'heading' from the Element Type selected as Content section *@
<h1>@content.Value("heading")</h1>

So your code just needs to be rendering a single slide, no need for the loop. (and as you aren’t using modelsBuilder strong typing.. no need for the usings.)

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>
@{
    var slide = Model.Content;
        
    <h4>@slide.Value("slideTitle")</h4>
    
}

To add to this.. as it infers a carousel.. you probably want to wrap all those slides in surounding bit of html?

you could do that in in the view/partialview,
<div class="carousel">Html.GetBlockListHtml(Model, “YOUR PROPERTY NAME FOR THE BLOCKLIST”)</div>

Or maybe hijack in blocklist/default.cshtml seen as that already checks for no list items, so wouldn’t render the wrapper.

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListModel>
@{
    if (Model?.Any() != true) { return; }
}
<div class="umb-block-list">
    @foreach (var block in Model)
    {
        if (block?.ContentKey == null) { continue; }
        var data = block.Content;

        @await Html.PartialAsync("blocklist/Components/" + data.ContentType.Alias, block)
    }
</div>

(that’s where it’s looping and suing your carouselSlide.html single slide render)

check for your block list property alias, and have the extra wrapper :wink:

@mistyn8 Amazing I finally have some content being displayed! Thank you!!

using this code below;

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>
@{
    var slide = Model.Content;
        
    <h4>@slide.Value("slideTitle")</h4>
    
}

How would I get it to work using a for each loop? so its not just listing a long list of data so I can wrap my slider aorund it.

Thanks

as I mentioned above.. update the blocklist/default.cshtml to add extra in the loop for your propertyalias, would be the way to not have to drop the @Html.GetBlockListHtml(Model, “Alias”)

(though any updates later down the line might need the view synching with umbraco changes)
:slight_smile:

another approach is to drop that helper..

duplicate the blocklist/default.cshtml to say blocklist/carousel.cshtml and alter as you need.

maybe as easy as.. (update the div class from umb-block-list to carousel??)

@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListModel>
@{
    if (Model?.Any() != true) { return; }
}
<div class="carousel">
    @foreach (var block in Model)
    {
        if (block?.ContentKey == null) { continue; }
        var data = block.Content;

        @await Html.PartialAsync("blocklist/Components/" + data.ContentType.Alias, block)
    }
</div>

then you simply change @Html.GetBlockListHtml(Model, “{alias}”) to render the new partial

<partial name="partials/blocklist/carousel" model="{blocklistAlias}" />

or if you don’t want to still have carousel → loop and render carouselslide.cshtml that’s also where you could do the loop and render all in one go.. the code you had to start with

if you actually look at what the helper is doing.. it’s just returning a parital view from a known loacation.. eg <partial name="partials/blocklist/default" model="{blocklistAlas}" />
Umbraco-CMS/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs at main · umbraco/Umbraco-CMS

any looking there now there is in fact there is an overloaded method to pass your own template… :wink:

@Html.GetBlockListHtml(Model.{blockListAlias}, "carousel");

or if not using modelsbuilder..
@Html.GetBlockListHtml(Model, “{blockListAlias}”, “carousel”);

ps the reason I tend to go back to <partial name="partials/blocklist/carousel" model="{blocklistAlias}" />

is that you can also pass extra to the partialview… via view-data
<partial name="partials/blocklist/carousel" model="Model.ContentRows" view-data=""/>
which can be useful…

Hi @Matthew2016

Sorry, I didn’t have a chance to reply to your message this morning and then noticed that Mike has (thanks @mistyn8!).

I just wanted to point you at Paul Seal’s YouTube videos, he has one on the Block List which may be useful for you to watch. It is from Umbraco 10, but the same concepts apply in Umbraco 17.

The back-office is slightly different now, but the fundamentals and about setting up the Block List and templates should be the same.

Justin