Slick Carousel with Angular 2
Asked Answered
R

2

21

Hi I'm starting with Angular 2 and trying to make this carousel plugin to work: slick

After a while I managed to make it work like a Component like this:

import { Component, Input, ElementRef, AfterViewInit, AfterContentInit} from '@angular/core';
declare var jQuery: any;

@Component({
    selector: 'slick-slider',
    template: `
        <ng-content></ng-content>
    `
})
export class SlickSliderComponent implements AfterContentInit{
    @Input() options: any;

    $element: any;

    defaultOptions: any = {};

    constructor(private el: ElementRef) {
    }

    ngAfterContentInit() {
        for (var key in this.options) {
            this.defaultOptions[key] = this.options[key];
        }

        this.$element = jQuery(this.el.nativeElement).slick(this.defaultOptions);
    }
}

And I would use it like this on a template:

<slick-slider>
    <div><img class="btn btn-lg" src="/assets/img/img1.png" /></div>
    <div><img class="btn btn-lg" src="/assets/img/img2.png" /></div>
    <div><img class="btn btn-lg" src="/assets/img/img3.png" /></div>
    <div><img class="btn btn-lg" src="/assets/img/img4.png" /></div>
    <div><img class="btn btn-lg" src="/assets/img/img5.png" /></div>
</slick-slider>

This works fine. But when I try to use it inside *ngFor like this:

<slick-slider>
    <div *ngFor="let source of sources">
        <img class="btn btn-lg" (click)="watchSource(source)" src="/assets/img/{{source.name}}.png" />
    </div>
</slick-slider>

It stops working. I assume is because the init of the slider is done before the <div> elements are being rendered. Because I end up with this rendered html:

<slick-slider class="slick-initialized slick-slider">
    <div>
      <img ... >
    </div>
    <div>
      <img ... >
    </div>
    <div>
      <img ... >
    </div>
    <div>
      <img ... >
    </div>

    <div aria-live="polite" class="slick-list draggable">
      <div class="slick-track" role="listbox" style="opacity: 1; width: 0px; transform: translate3d(0px, 0px, 0px);">
        <!-- Divs should be rendered here with slick styles included -->
      </div>
  </div>
</slick-slider>

Any idea how to make this work? I tried using "ngAfterContentInit" and "ngAfterViewInit" neither seem to work.

This is the component using the SlickSliderComponent:

import { Component, OnInit } from '@angular/core'
import { DeviceSource } from './device-source'
import { RemoteService } from './remote.service';

@Component({
    selector: 'device-selector',
    moduleId: module.id,
    templateUrl: 'device-selector.component.html',
    providers: []
})



export class DeviceSelectorComponent implements OnInit {

    sources: [DeviceSource];

    ngOnInit(): void {
        this.getDeviceSources();
    }

    constructor(private remoteService: RemoteService){}

    getDeviceSources(): void {
        this.remoteService.getDeviceSources().then(sources => this.sources = sources);
    }
}

And here is the service used:

import { Injectable } from '@angular/core'
import { DeviceSource } from './device-source'

export const DEVICE_SOURCES:[DeviceSource]=
[
    {id: 1, dispayName: 'TV', name:'tv'},
    {id: 2, dispayName: 'Chrome', name:'chrome'},
    {id: 3, dispayName: 'Cable', name:'cable'},
    {id: 4, dispayName: 'XBox', name:'xbox'},
    {id: 4, dispayName: 'Pi', name:'pi'},

];


@Injectable()
export class RemoteService {
    getDeviceSources(): Promise<[DeviceSource]> {
        return Promise.resolve(DEVICE_SOURCES); 
    }
}
Roquefort answered 19/10, 2016 at 16:50 Comment(7)
How are you populating your sources variable, is it via http call?Pastel
No, but I'm using a service mock, eventually it will. Now it's just calling that service and it's resolving a Promise (like in the firsts steps of the Tour Of Heroes Tutorial link)Roquefort
@Roquefort Could you pls share steps to work with slick in angular2Maniple
I don't understand how the import 'slick-slider' is resolved ?Littoral
I am new in angular2 Please can you help me with this issue:#42925838Riess
@Littoral you can remove the import 'slick-slider'; then it works. I removed it in the questionPreconcert
what have you done to resolve jQuery here?Appellative
P
12

You should add *ngIf directive to your slick-slider so it is inserted into DOM after data source is populated, in this case it is variable sources:

<slick-slider *ngIf="sources">
    <div *ngFor="let source of sources">
        <img class="btn btn-lg" (click)="watchSource(source)" src="/assets/img/{{source.name}}.png" />
    </div>
</slick-slider>
Pastel answered 19/10, 2016 at 17:7 Comment(1)
Excellent! I was trying to find a work around that every time the source collection got updated, replace the template used and call something like $(elemnt).slick('addSilder', template). This work around is much simpler. Thanks!Roquefort
C
0

In my case the trick with *ngIf was not enough. Im calling REST service in ngOnInit and receiving response where in subscription I'm defining the array. The only possible workaround for me was to add slick items manually by slick function 'slickAdd' directly from typescript.

jQuery('.my-slick').slick('slickAdd', '<div><h3>ahoj</h3></div>');

Maybe it will help somebody...

Copulate answered 20/6, 2017 at 22:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.