NgbDropdownConfig allows us to set the NgbDropdown menu placement at the constructor call. However, it doesn't take it into consideration if it changes later.
Basically, I have a page (component) with angular-l10n enabled where I'm listening for the locale change to switch the NgbDropdownConfig.placement over bottom-right or bottom-left based on the page dir. In other words:
constructor(public dropdownConfig: NgbDropdownConfig, public locale: LocaleService, public translation: TranslationService) {
dropdownConfig.placement = 'bottom-left';
}
// Below method will be called upon locale change via a 'ISubscripion'.
onLocaleChange(): void {
this.dropdownConfig.placement = (this.locale.getLanguageDirection() == 'rtl') ? 'bottom-right' : 'bottom-left';
console.log(this.dropdownConfig.placement);
}
The above code will work and the textual value of dropdownConfig.placement will be changed, however, no actual effect on the page. It seems that NgbDropdown compnenet doesn't update the value or listens for it if it's updated.
Angular: v5 (cli: 1.6.0, compiler: 5.1.3)
ng-bootstrap: 1.0.0-beta.9
Bootstrap: 4.0.0-alpha.6
My use case is slightly different, using an Input binding in my component to pass in the placement. The value is not available until AfterViewInit and there is no way I know of triggering the NgbDropdown to re-configure after the constructor. A method on the config like config.reinitialize would be a nice feature.
So if the dropdown is inside of a component and I want to set placement different depending on where it is used, using an input binding will not work because the binding occurs too late.
<my-comonent-with-dropdown [placement]="'bottom-right'"></my-comonent-with-dropdown>
Inside component template... this does not work
<div>
<div ngbDropdown [placement]="placement">
And this does not work inside component
@Input() public placement: string;
constructor( public config: NgbDropdownConfig ) {
// placement is not defined yet
// this.config.placement = (this.placement as PlacementArray);
}
public ngAfterViewInit(): void {
// placement is defined but dropdown has already configured
// this.config.placement = (this.placement as PlacementArray);
}
Using a CSS class binding works
<my-comonent-with-dropdown [ngClass]="{'bottom-right': isRight}"></my-comonent-with-dropdown>
with
.dropdown-menu {
left: 0;
right: auto;
&.bottom-right {
right: 0;
left: auto;
}
}
I need a hack to change the position dynamically ... any advice appreciated ...
I used a flag variable to display the dropdown until it received the configs from prop bindings...
<!-- template of my-customized-dropdown -->
<!-- use ngIf to hide the dropdown at first -->
<div ngbDropdown *ngIf="initDone">
...
</div>
```html
```typescript
@Component({
selector: 'my-customized-dropdown',
templateUrl: './my-customized-dropdown.component.html',
styleUrls: ['./my-customized-dropdown.component.scss'],
providers: [NgbDropdownConfig]
})
export class NbDropdownComponent implements OnInit {
@Input() closeMethod: boolean | 'inside' | 'outside' = true;
@Input() placement: string = 'bottom'
// initDone is default to false
initDone = false;
constructor(private ngbDropdownConfig: NgbDropdownConfig) {}
ngOnInit() {
// in ngOnInit, pass the props to ngbDropdownConfig and set initDone to true
this.ngbDropdownConfig.placement = this.placement;
this.ngbDropdownConfig.autoClose = this.closeMethod;
this.initDone = true;
}
}
Most helpful comment
I used a flag variable to display the dropdown until it received the configs from prop bindings...
```html