Nesting of components (get slider content)

Hey,
i have a hero-slider, but i cant manage to get the content of the slides.
I tried a lot of different things but i miss something.
What am i missing?

The structure looks like this:

Slider:

'WG.BaseSite:Content.Hero.Slider':
  superTypes:
    'Neos.Neos:Content': true
    'Neos.Neos:ContentCollection': true
  ui:
    label: 'Hero Slider'
    icon: 'icon-picture'
    group: 'general'
    inspector:
      groups:
        slider:
          label: 'Slider Einstellungen'
  constraints:
    nodeTypes:
      '*': false
      'WG.BaseSite:Content.Slider.Slide': true
  childNodes:
    '':
      type: 'WG.BaseSite:Content.Slider.Slide'

Slides:

'WG.BaseSite:Content.Slider.Slide':
  superTypes:
    'Neos.Neos:Content': true
  ui:
    label: 'Slide'
    icon: 'icon-picture'
    inspector:
      groups:
        image:
          label: 'Bild'
          position: 'start'
        text:
          label: 'Text'
          position: 'end'
  properties:
    image:
      type: Neos\Media\Domain\Model\ImageInterface
      ui:
        label: 'Bild'
        reloadIfChanged: true
        inspector:
          group: 'image'
          position: 10
    text:
      type: string
      ui:
        label: 'Text'
        inspector:
          group: 'text'
          position: 20

Inside the page node, its set as childNode:

'WG.BaseSite:Document.Page':
  superTypes:
    'WG.BaseSite:Document.AbstractPage': true
  ui:
    label: i18n
    icon: icon-file-o
    position: 100
    inspector:
      groups:
        options:
          label: 'options'
          position: 10
  properties:
  childNodes:
    slider:
      type: 'WG.BaseSite:Content.Hero.Slider'
      ui:
        label: 'Slider'
      position: 10
    main:
      type: 'Neos.Neos:ContentCollection'
      ui:
        label: 'Inhalt'
      position: 20

On the fusion site, the structure is like this:

The page is based on the default layout:

prototype(WG.BaseSite:Document.Page) < prototype(WG.BaseSite:Document.AbstractPage) {

    body = WG.BaseSite:Component.DefaultLayout {
        content = ''
        @process.normalize = CodeQ.UnicodeNormalizer:Normalizer
    }

    body.content = Neos.Fusion:Component {
        main = Neos.Neos:ContentCollection {
            nodePath = 'main'
        }

        renderer = afx`
            <main class="page-content" id="main">
                {props.main}
            </main>
        `
    }
}

the default layout includes structure components:

prototype(WG.BaseSite:Component.DefaultLayout) < prototype(Neos.Fusion:Component) {
    content = ''

    renderer = afx`
        <WG.BaseSite:Component.SkipNavigation />
        <WG.BaseSite:Component.TopBar />
        <WG.BaseSite:Component.Header />
        <WG.BaseSite:Component.HeroSection />
        <WG.BaseSite:Component.Breadcrumb />
        {props.content}
        <WG.BaseSite:Component.Footer />
    `
}

Inside the HeroSection, the slider is included.

prototype(WG.BaseSite:Component.HeroSection) < prototype(Neos.Fusion:Component) {

    node = ${node}

    hero = WG.BaseSite:Content.Hero.Slider {
        node = ${q(node).children('slider').get(0)}
        @if.hasSlider = ${q(node).children('slider').count() > 0}
    }


    menuItems = Neos.Neos:MenuItems {
        startingPoint = ${site}
        maximumLevels = 3
    }

    polygonLeft =  Neos.Fusion:Tag {
      tagName = 'img'
      attributes {
        src = Neos.Fusion:ResourceUri {
          path = 'resource://WG.BaseSite/Public/Frontend/images/polygon-left.svg'
        }
      }
    }

    renderer = afx`
        <section class="hero">
            {props.hero}

              <!-- Off-canvas Menu -->
      <div class="off-canvas-wrapper">
        <div class="off-canvas position-right" id="offCanvas" data-off-canvas>
          {props.polygonLeft}
          <ul class="vertical menu">
            <li class="border-below">
                <button class="close-button" aria-label="Close menu" type="button" id="closeOffCanvas">
                <span aria-hidden="true">&times;</span>
              </button>
            </li>
            <Neos.Fusion:Loop items={props.menuItems} itemName="menuItem">
              <li class={menuItem.state == 'current' ? 'active' : ''}>
                <Carbon.Link:Link
                  node={menuItem.node}
                  backendLink={true}
                  renderDefaultTagIfNoLink={true}>
                  <span>{String.toUpperCase(menuItem.label)}</span>
                </Carbon.Link:Link>
              </li>
            </Neos.Fusion:Loop>
          </ul>

        </div>
      </div>
        </section>

    `
}

The slider fusion looks like this:

prototype(WG.BaseSite:Content.Hero.Slider) < prototype(Neos.Neos:ContentComponent) {

    node = ${node}

    slides = Neos.Fusion:Collection {
            collection = ${q(node).children().get()}
            itemName = 'node'
            itemRenderer = WG.BaseSite:Content.Slider.Slide {
                node = ${node}
            }
        }

    renderer = afx`
        <section class="page-intro">
            <div class="slider-wrapper">
                <div class="orbit" role="region" aria-label="" data-orbit data-use-m-u-i="false">
                    <div class="orbit-wrapper">
                        <ul class="orbit-container">
                            {props.slides}
                        </ul>
                    </div>
                </div>
            </div>
        </section>
    `
}

And the slide fusion looks like this:

prototype(WG.BaseSite:Content.Slider.Slide) < prototype(Neos.Fusion:Component) {
    renderFrontend = ${site.context.inBackend ? false : true}
    node = ${node}

    image = ${q(node).property('image')}
    imageUri = Neos.Neos:ImageUri {
        asset = ${q(node).property('image')}
        width = 1920
        height = 1080
        allowCropping = true
        allowUpscaling = true
    }

    text = Neos.Neos:Editable {
        property = 'text'
    }

    renderer = afx`
        <li class="orbit-slide">
            <figure class="orbit-figure">
                <Neos.Fusion:Tag
                    @if.hasImage={props.image}
                    tagName="img"
                    attributes={{
                        src: props.imageUri,
                        alt: ${q(node).property('title') || 'Slider image'},
                        class: 'orbit-image'
                    }}
                />
                <figcaption class="orbit-caption">
                    <div class="grid-container">
                        <div class="grid-x">
                            <div class="cell small-6 medium-4">
                                {props.text}
                            </div>
                        </div>
                    </div>
                </figcaption>
            </figure>
        </li>
    `
}

Hi @BoxerBuffa,

as far as I see, the way you pass the node from WG.BaseSite:Component.HeroSection to WG.BaseSite:Content.Hero.Slider does not work.

You pass it as a “local” property node to WG.BaseSite:Content.Hero.Slider

    hero = WG.BaseSite:Content.Hero.Slider {
        node = ${q(node).children('slider').get(0)}
        @if.hasSlider = ${q(node).children('slider').count() > 0}
    }

but within, WG.BaseSite:Content.Hero.Slider you try to access node from the current context ${q(node).children().get()}. But this might be you page node at this point (I assume). You need to put the new node into the context, to make it accessable within the slides collection.

prototype(WG.BaseSite:Content.Hero.Slider) < prototype(Neos.Neos:ContentComponent) {

    node = ${node}
    @context.node = ${this.node}

    slides = Neos.Fusion:Collection {
            collection = ${q(node).children().get()}
            itemName = 'node'
            itemRenderer = WG.BaseSite:Content.Slider.Slide {
                node = ${node}
            }
...

The Neos.Fusion:Collection is btw. deprecated and if you want proper UI integration you can simply use Neos.Neos:ContentCollectionRenderer without any additional props, as it will automatically render the current nodes (node set via @context or itemName in the loop) children with their matching prototypes assuming.

To prevent invalid markup when adding items you need to add the attribute

data-__neos-insertion-anchor = true
data-__neos-insertion-anchor.@if.onlyRenderInBackend = ${node.context.inBackend && node.context.currentRenderingMode.edit}

to the tag that wraps the items, so the UI knows where to put new elements.

1 Like