Reputation: 177
I am trying to dynamically populate a bootstrap carousel with screenshots. Everything is working, besides the actual switching of the screenshots. I found out that this is caused by the <screenshots>
tag being placed by angular. If I would delete this <screenshots>
manually it would work. Is there a way to do this programatically? Or is my aproach just not good/wrong?
project-template.component.html (carousel part)
<div id="test" class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
<template #screenshots></template>
</div>
<a class="carousel-control-prev" href="#test" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#test" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
project-template.component.ts (carousel part)
import { Component, OnInit, ViewChild, ViewContainerRef, ComponentFactoryResolver, ComponentFactory, ComponentRef, Input, Output, EventEmitter } from '@angular/core';
import { Router } from '@angular/router';
import { ScreenshotsComponent } from './screenshots/screenshots.component';
@Component({
selector: 'app-project-template',
templateUrl: './project-template.component.html',
styleUrls: ['./project-template.component.css']
})
export class ProjectTemplateComponent {
@Input() screenshots: Array<Object>;
@Output() output = new EventEmitter();
@ViewChild("screenshots", { read: ViewContainerRef }) containerScreenshots;
componentRefScreenshots: ComponentRef<ScreenshotsComponent>;
constructor(private resolver: ComponentFactoryResolver) { }
ngOnInit() {
this.containerScreenshots.clear();
for(let i = 1; i < this.screenshots[0]["count"] + 1; i++){
const factory: ComponentFactory<ScreenshotsComponent> = this.resolver.resolveComponentFactory(ScreenshotsComponent);
this.componentRefScreenshots = this.containerScreenshots.createComponent(factory);
let put = this.componentRefScreenshots.instance
put.output.subscribe(event => console.log(event));
if(i == 1){
put.ac = " active"
}
put.number = i
put.project = this.screenshots[0]['project'] as string;
put.projectType = this.screenshots[0]['project-type'] as string;
}
}
}
screenshots.component.html
<div class="carousel-item{{ac}}">
<img class="d-block w-100 image" src="../assets/{{projectType}}/{{project}}/Screenshot-{{number}}.png" alt="{{number}} slide"
style="max-width: 15%; max-height: 15%;">
</div>
screenshots.component.ts
import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core';
@Component({
selector: 'screenshots',
templateUrl: './screenshots.component.html',
styleUrls: ['./screenshots.component.css']
})
export class ScreenshotsComponent implements OnInit {
@Input() projectType: string = "loading...";
@Input() project: string = "loading...";
@Input() number: number = -1;
@Input() ac: string = "";
@Output() output = new EventEmitter();
constructor() { }
ngOnInit() {
}
}
the result:
<div _ngcontent-c1="" class="carousel slide" data-ride="carousel" id="test">
<div _ngcontent-c1="" class="carousel-inner">
<template _ngcontent-c1=""></template>
<screenshots _nghost-c6="">
<div _ngcontent-c6="" class="carousel-item active">
<img _ngcontent-c6="" class="d-block w-100 image" style="max-width: 15%; max-height: 15%;" src="../assets/android-projects/school-diary/Screenshot-1.png"
alt="1 slide">
</div>
</screenshots>
<screenshots _nghost-c6="">
<div _ngcontent-c6="" class="carousel-item">
<img _ngcontent-c6="" class="d-block w-100 image" style="max-width: 15%; max-height: 15%;" src="../assets/android-projects/school-diary/Screenshot-2.png"
alt="2 slide">
</div>
</screenshots>
<screenshots _nghost-c6="">
<div _ngcontent-c6="" class="carousel-item">
<img _ngcontent-c6="" class="d-block w-100 image" style="max-width: 15%; max-height: 15%;" src="../assets/android-projects/school-diary/Screenshot-3.png"
alt="3 slide">
</div>
</screenshots>
<screenshots _nghost-c6="">
<div _ngcontent-c6="" class="carousel-item">
<img _ngcontent-c6="" class="d-block w-100 image" style="max-width: 15%; max-height: 15%;" src="../assets/android-projects/school-diary/Screenshot-4.png"
alt="4 slide">
</div>
</screenshots>
<screenshots _nghost-c6="">
<div _ngcontent-c6="" class="carousel-item">
<img _ngcontent-c6="" class="d-block w-100 image" style="max-width: 15%; max-height: 15%;" src="../assets/android-projects/school-diary/Screenshot-5.png"
alt="5 slide">
</div>
</screenshots>
<screenshots _nghost-c6="">
<div _ngcontent-c6="" class="carousel-item">
<img _ngcontent-c6="" class="d-block w-100 image" style="max-width: 15%; max-height: 15%;" src="../assets/android-projects/school-diary/Screenshot-6.png"
alt="6 slide">
</div>
</screenshots>
<screenshots _nghost-c6="">
<div _ngcontent-c6="" class="carousel-item">
<img _ngcontent-c6="" class="d-block w-100 image" style="max-width: 15%; max-height: 15%;" src="../assets/android-projects/school-diary/Screenshot-7.png"
alt="7 slide">
</div>
</screenshots>
<screenshots _nghost-c6="">
<div _ngcontent-c6="" class="carousel-item">
<img _ngcontent-c6="" class="d-block w-100 image" style="max-width: 15%; max-height: 15%;" src="../assets/android-projects/school-diary/Screenshot-8.png"
alt="8 slide">
</div>
</screenshots>
</div>
<a _ngcontent-c1="" class="carousel-control-prev" data-slide="prev" href="#test" role="button">
<span _ngcontent-c1="" aria-hidden="true" class="carousel-control-prev-icon"></span>
<span _ngcontent-c1="" class="sr-only">Previous</span>
</a>
<a _ngcontent-c1="" class="carousel-control-next" data-slide="next" href="#test" role="button">
<span _ngcontent-c1="" aria-hidden="true" class="carousel-control-next-icon"></span>
<span _ngcontent-c1="" class="sr-only">Next</span>
</a>
</div>
Upvotes: 0
Views: 1660
Reputation: 214
It seems to me that you are trying to use bootstrap and not ngx-bootstrap. I think you would be better off using the latter one, it is much more adapted to angular :)
Secondly, I don't see why you are trying to force the component creation procedure using the 'complicated' ComponentFactory
and so. Is there a reason for that? Just because if not, I would rather use the Dynamic Slides example from the ngx-bootstrap docs:
https://valor-software.com/ngx-bootstrap/#/carousel#dynamic-slides
So basically you'd just have a for loop (ngFor) in the template file, which generates the slides dynamically, depending on how many slide data you have in the bounded input.
The carousel
tag has an activeSlide
property, which is two-way bindable, so you can easily control the desired slide index to be active.
EDIT:
If the only problem is how to remove the wrapping tag of the screenshots
component then you can do the following:
instead of
selector: 'screenshots',
use
selector: 'screenshots, [screenshots-directive]',
instead of
<div class="carousel-inner">
<template #screenshots></template>
</div>
write a for loop as mentioned earlier:
<div class="carousel-inner">
<div class="carousel-item" *ngFor="let screenshot of screenshots;
let i = index" screenshots-directive [number]="i" [project]="screenshot.project">
</div>
</div>
Note that I took the carousel-item
div out of the screenshots
component. It is necessary because the for loop needs to be added to a html tag. Normally the ng-template
and ng-container
tags could be used when you want to use a for loop but you dont want the for loop's container to be rendered. However, it does not seem to work together with a directive, such as the screenshots-directive
, I don't know why.
Upvotes: 2