Image Slider in NEOS backend

Hi there

In my Frontend I have an image-slider (unslider js).
In my model, the images of the slider are content-nodes in a content-collection node.

My problem is in the backend now:

  • If I add a new image, the page has to be re-rendered to trigger the unslider-js to setup the slider
  • If I delete an image, same issue

I can set “reloadPageIfChanged” for the image-property itself, but this does not trigger reload properly on the two cases described above.

If I save the selected image asset, the page gets reloaded, but it does not trigger the unslider-setup. The images show up stacked instead of in the form of the slider.

Any useful hints / inputs to this challenge are very welcome!

Regards

I tried to include the trigger for the unslider-setup at the bottom of the body-partial. But this doesn’t work either.

Are there javascript-hooks in the backend I can use to react on content changes?

Total frontend-backend transparency seems to be a concept that does not like to face reality… :wink:

Regards
Thĩs

Hello Thĩs,

you have to listen to the Neos.PageLoaded event aswell since neos avoids fully reloading the site (with the current ui) and mostly just reloads the body part.

// If the Neos backend re-renders the page, re-parse the document.
document.addEventListener('Neos.PageLoaded', function(event) {
    // do the same as on dom-ready
}, false);

Regards Martin

Thanks, now I found what I was looking for:
https://neos.readthedocs.io/en/1.2/IntegratorGuide/InteractionWithTheNeosBackend.html

PageLoaded is not enough, as I also have to react on added / removed nodes.

1 Like

Now I developed a really nice solution. I would like to share this here.

First, information about interaction with NEOS backend (JS Events): http://neos.readthedocs.io/en/stable/ExtendingNeos/InteractionWithTheNeosBackend.html

Finally (after trying other popular sliders) I stick to http://sachinchoolur.github.io/lightslider/

The Images are nodes in a ContentCollection, rendering as

<div class="images-slider">
  <ul class="slides">
    <li class="image-collection-item"><img ..../></li>
    <li class="image-collection-item"><img .../></li>
    <li class="image-collection-item dummy"><!--showing dummy image--></li>
  </ul>
</div>

Frontend js (always included):

// -------------- initialize ----------------
$(document).ready(function(){
  LightSliderImageSliders.setup();
});

// ------------ LightSliderImageSliders object/namespace --------------
LightSliderImageSliders = {};

LightSliderImageSliders.setup = function (){
  $('.images-slider ul.slides').each(function(){
    if( $(this).find('li').length < 2 )
      return; // just one slide or already set up!
    var slider = $(this).lightSlider({
      item: 1,
      slideMargin: 0,
      slideEndAnimation: false,
      gallery: false
    });
    // attach API to the ul-node
    this.lightSliderObj = slider;
    // display hidden slides
    $(this).find('li').css('display', 'initial');
  });
}

LightSliderImageSliders.refresh = function (slider){
  var refreshSlider = function(slider){
    if(slider.lightSliderObj){
      slider.lightSliderObj.refresh();
      return true;
    }
    return false;
  }
  // refresh specific slider
  if(slider){
    return refreshSlider(slider);
  }
  // refresh all sliders
  $('.images-slider ul.slides').each(function(){
    refreshSlider(this);
  });
}

Backend js (only included in backend, using VH {neos:rendering.inBackend()} ):

// ----------- Extend LightSliderImageSliders ------------

LightSliderImageSliders.CheckForAddedSlide = function(element){
  var $el = $(element);
  if($el.hasClass('image-collection-item') ){
    console.log('added image-collection-item');
    $el.addClass('lslide').css('display', 'initial');
    LightSliderImageSliders.refresh(element.parentNode);
    // move slider to the added item
    LightSliderImageSliders.MoveSliderToElement(element);
  }
}

LightSliderImageSliders.CheckForRemovedSlide = function(element){
  var $el = $(element);
  if($el.hasClass('image-collection-item') ){
    console.log('removed image-collection-item');
    LightSliderImageSliders.refresh(element.parentNode);
  }
}

LightSliderImageSliders.MoveSliderToActiveContentElement = function(){
  $el = $('.image-collection-item.neos-contentelement-active');
  if( $el.length ){
    LightSliderImageSliders.MoveSliderToElement($el[0]);
  }
}

LightSliderImageSliders.MoveSliderToElement = function(element){
  if(!element.parentNode.lightSliderObj)
    return false;
  // move slider to the li element
  element.parentNode.lightSliderObj.goToSlide(
    $(element.parentNode).find('li').index(element)
  );
  return true;
}

// ---------- NEOS events ------------------
document.addEventListener('Neos.PageLoaded', function(event) {
  console.log('Neos.PageLoaded');
  LightSliderImageSliders.setup();
  LightSliderImageSliders.MoveSliderToActiveContentElement();
}, false);

document.addEventListener('Neos.ContentModuleLoaded', function(event) {
  console.log('Neos.ContentModuleLoaded');
  LightSliderImageSliders.MoveSliderToActiveContentElement();
}, false);

document.addEventListener('Neos.NodeSelected', function(event){
  console.log('Neos.NodeSelected');
  LightSliderImageSliders.MoveSliderToElement(event.detail.element);
}, false);

document.addEventListener('Neos.NodeCreated', function(event) {
  console.log('Neos.NodeCreated');
  LightSliderImageSliders.CheckForAddedSlide(event.detail.element);
}, false);

document.addEventListener('Neos.NodeRemoved', function(event) {
  console.log('Neos.NodeRemoved');
  LightSliderImageSliders.CheckForRemovedSlide(event.detail.element);
}, false);

document.addEventListener('Neos.LayoutChanged', function(event) {
  console.log('Neos.LayoutChanged');
  LightSliderImageSliders.refresh();
}, false);

Like this the editor can add an image with “add element after / before” directly in the Content. The slider moves to the new element. Also (thanks to the ‘Neos.NodeSelected’ - Event) it moves to the edited slide when a node in the navigate-tree is selected.

Perfect solution for me like this, maybe it’s useful for someone else too.

3 Likes