Have a number of Overlays that need to re-position after window-resize
event.
The current initialy configured PositionStrategy
has logic that is dependent on outside variables to align Overalys similar to CSS Grid / Flexbox behavior.
This material2 github issue seems to indicate can only use OverlayRef.dispose()
=> OverlayRef.create()
.
Is there any solution that meets the following:
Preferably able to be called from service and not OverlayRef
's component instance.
Edit 1 for clarity:
Given the following PositionStrategy
, OverlayRef.updatePosition()
seems to not apply as need to re-calculate px. *Note window.innerWidth
private setChannelPosition(): PositionStrategy {
const chatWidth = 280;
const chatSpace = 5;
const distanceFromEdge = 80;
const existingModalCount = this.channelModals.size;
const numModalsCanFit =
Math.floor((window.innerWidth - 2 * distanceFromEdge) / (chatWidth + chatSpace));
const distFromRight =
distanceFromEdge + ((existingModalCount % numModalsCanFit) * (chatWidth + chatSpace));
return this.overlay.position().global().bottom('0px').right(`${distFromRight}px`);
}
Edit 2:
The modals are transient.. So a solution with flexibleConnectedTo()
doesn't seem to apply as any modal may or may not be closed by user in any order.
Assuming you only call setChannelPosition()
once when making the OverlayConfig
, like:
export class MyComponent implements OnInit {
private overlayRef: OverlayRef;
constructor(
private overlay: Overlay
) { }
public ngOnInit(): void {
this.createOverlay();
}
@HostListener('window:resize')
public onResize(): void {
this.overlayRef.updatePosition();
}
private setChannelPosition(): PositionStrategy {
const chatWidth = 280;
const chatSpace = 5;
const distanceFromEdge = 80;
const existingModalCount = this.channelModals.size;
const numModalsCanFit = Math.floor((window.innerWidth - 2 * distanceFromEdge) / (chatWidth + chatSpace));
const distFromRight = distanceFromEdge + ((existingModalCount % numModalsCanFit) * (chatWidth + chatSpace));
return this.overlay.position().global().bottom('0px').right(`${distFromRight}px`);
}
private createOverlay() {
const config = new OverlayConfig({
positionStrategy: this.setChannelPosition()
});
this.overlayRef = this.overlay.create(config);
this.overlayRef.attach(/* template or component*/);
}
}
so the line this.overlay.position().global().bottom('0px').right(
${distFromRight}px);
only runs once creating a GlobalPositionStrategy
with bottom 0px and rigth being what ever the value of distFromRight
was at the time.
OverlayRef.updatePosition()
calls PositionStrategy.apply()
which GlobalPositionStrategy
implements and simply applyies css values based on its properties (in this case being bottom 0px and rigth being what ever the value of distFromRight
when setChannelPosition()
ran).
The solution would be to have PositionStrategy
that recalculates on PositionStrategy.apply()
.
class MyPositionStrategy implements PositionStrategy {
public apply(): void {
/* recalculates */
}
}
const config = new OverlayConfig({
positionStrategy: instanceOfMyPositionStrategy
});
or
Change the PositionStrategy
before calling OverlayRef.updatePosition()
by calling OverlayRef.updatePositionStrategy()
new to angular material 7 I think.
@HostListener('window:resize')
public onResize(): void {
this.overlayRef.updatePositionStrategy(this.setChannelPosition());
this.overlayRef.updatePosition();
}
So the setChannelPosition()
runs and PositionStrategy
changes every time the window resizes.
Note:
There was an old solution like
@HostListener('window:resize')
public onResize(): void {
this.overlayRef.getConfig().positionStrategy = this.setChannelPosition();
this.overlayRef.updatePosition();
}
but getConfig().positionStrategy
is now readonly and doesn't work