Reputation: 6697
I'd like a way to tell if the components inside of a container overflow the container. If it does overflow, I'd like to get the index of the item that causes the overflow.
The goal of this problem is to add a show more button when it overflows and to split the object into two; the items that fit, and the items that don't.
The components are generated by *ngFor.
Here's a minimal example of what's going on
<div class="my-container">
<div
class="item"
*ngFor="let item of items; let i = index; trackBy: trackById"
>
{{ item.val }}
</div>
<div>
.my-container {
overflow: hidden;
max-width: 100%;
display: flex;
}
As my container fills up horizontally with the items, it can overflow horizontally if there's enough items. I'd like to tell if it does overflow, and determine the index of which item causes the overflow.
Here's my attempt:
// this fn gets called in ngOnChanges
determineShowMore() {
const container = document.querySelector('.my-container') as HTMLElement;
const viewItems: any = container ? Array.from(viewsContainer.children) : [];
let totalWidth = 0;
viewItems.forEach((x: HTMLElement) => {
totalWidth += x.offsetWidth;
});
const isOverflow = totalWidth > viewsContainer.offsetWidth ? true : false;
// missing: determine which item causes the overflow
}
It doesn't seem to work well, maybe because it's happening before the html is fully rendered? I can't run this fn on ngAfterViewInit()
because my items
can change dynamically and I need it to run every time that changes.
Upvotes: 0
Views: 1446
Reputation:
First of all, I would not use document.querySelector()
if you're using Angular. You can import ElementRef and use that instead. Secondly, I think you can achieve this by running a callback each time one element is added. Try creating a subcomponent out of a single item and use an event emitter to tell the parent whether or not to add a read more button.
import { Component, ElementRef, Output, EventEmitter } from '@angular/core'
@Component({
selector: 'single-item',
templateUrl: './single-item.component.html',
styleUrls: [ './single-item.component.css' ]
})
export class SingleItem {
@Input index: number
@Output onAddItem = new EventEmitter()
constructor(private elementRef: ElementRef) {
const container = this.elementRef.nativeElement
const wrapper = this.container.parentElement
this.onAddItem.emit({
isOverflowed:
container.clientHeight > wrapper.clientHeight ||
container.clientWidth > wrapper.clientWidth,
index: this.index:
})
}
}
And then in the parent's HTML:
<div class="container">
<ng-container
*ngFor="let item of items; let i = index; trackBy: trackById"
>
<single-item
(onAddItem)="handleAddItem($event)"
[index]="i"
>
{{ item.val }}
</single-item>
</ng-container>
</div>
In the JS, you might handle it like this.
overflowingIndex: number
handleAddItem(event) {
if (!event.isOverflowed) return false
this.overflowingIndex = this.overflowingIndex || event.index
// add your read more button here
}
Upvotes: 3
Reputation: 1635
You can use the Intersection Observer api for it.
It will help you in to notifying whether which div item is visible full or partially. The docs link and the angular implementation link is below.
https://usefulangle.com/post/113/javascript-detecting-element-visible-during-scroll
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
Upvotes: 1