Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2: set md-fab button 'position: fixed' in inner component

I use the md-fab-button from the original angular2 material-framework. I want to set the md-fab-button(for adding a new entity) position: fixed but I want to place the button in an inner component inside the md-sidenav-layout but if I do so then the position: fixed doesn't work.

The code above:

<div class="{{themeService.ActualTheme}}">
    <md-sidenav-layout class="full-height" fullscreen>

This class attribute is just for theming the app I also tried it without fullscreen and set with the class "full-height" the md-sidenav-layout to 100% height and absolute, but it doesn't work.

First try(position: fixed doesn't work):

        <button (click)="onPlusClickAction()" class="add-group-button" color="accent" md-fab>
            <md-icon class="md-24 plus-icon">add</md-icon>
        </button>

    </md-sidenav-layout>
</div>

Instead of the router-outlet the inner component will be replaced(standard angular2 routing).

Now I tried to put the md-fab-button here:

        <router-outlet></router-outlet>

    </md-sidenav-layout>

    <button (click)="onPlusClickAction()" class="add-group-button" color="accent" md-fab>
        <md-icon class="md-24 plus-icon">add</md-icon>
    </button>
</div>

If I do so, then the position: fixed works, but now the md-fab-button is outside of the md-sidenav-layout and always when I open my sidenav, the fab-button lays over the sidenav. z-index doesn't work because then the fab-button disappears completly.

Has anyone a good idea to solve this problem?

Thank you in advance!

like image 614
Nico Avatar asked Dec 07 '16 14:12

Nico


2 Answers

The fixed position does not work because there is a transform: translate3d CSS attribute set on the md-sidenav-layout element. In such cases

the object will act as a containing block for position: fixed elements that it contains

see https://developer.mozilla.org/en-US/docs/Web/CSS/transform

There is already an open issue on the Material 2 project requesting to remove the translate3d value from sidenav, but so far the Material team did not address the issue: https://github.com/angular/material2/issues/998

I faced the same situation and solved it with a quite heavy workaround. I removed the FAB from the main content, defined a secondary router outlet in my template (outside md-sidenav-layout), created a standalone component for the FAB, and used an Observable in a service to broadcast the click events to the main components.

Layout

<md-sidenav-container>
    <md-sidenav #sidenav mode="side" class="app-sidenav">
        <md-nav-list>
            <a md-list-item routerLink="/">
                <span md-line>Home</span>
            </a>
    </md-nav-list>
  </md-sidenav>
    <md-toolbar color="primary">
        <button md-icon-button (click)="sidenav.toggle()">
            <md-icon class="icon-40">menu</md-icon>
        </button>
        <span>Angular Material 2 Sidenav with FAB</span>
    </md-toolbar>
  <router-outlet></router-outlet>
</md-sidenav-container>
<router-outlet name="fab"></router-outlet> 

FAB service

export class FabService {

  private actionSource = new Subject<string>();
  public actionStream = this.actionSource.asObservable();

  public broadcastAction(action: string) {
      this.actionSource.next(action);
  }
}

FAB component

@Component({
    template: '<button md-fab class="fab" (click)="actionHandler()"><md-icon>add</md-icon></button>',
    styles: [`
        button.fab {
            position: fixed;
            bottom: 12px;
            right: 12px;
        }
    `]
})
export class FabComponent {

    constructor(private fabService: FabService) { }

    actionHandler() {
        this.fabService.broadcastAction('click');
    }  
}

Main component

export class MainComponent implements OnInit, OnDestroy {
  private subscription: Subscription;

  constructor(private fabService: FabService)  { }

    ngOnInit(): void {
    this.subscription = this.fabService.actionStream.subscribe(event => this.events.push(event));
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }  
}

And the routing

const routes: Routes = [
    { path: '', children: [
        { path: '', component: MainComponent},
        { path: '', component: FabComponent, outlet: 'fab' }
    ]}

Full working example: http://plnkr.co/edit/GLFWfdy2JSXNKefhuNLA?p=preview

like image 78
András Szepesházi Avatar answered Nov 09 '22 04:11

András Szepesházi


I had the same problem. After a huge research, I found two good solutions:

Option 1:

You can add display: flex property to the md-sidenav component and to the md-sidenav-content. Please check the following working example: http://plnkr.co/edit/VItn3Y2AaTzpzIykTTyH?p=preview

Option 2:

As @András Szepesházi said the main problem is coming from the transform: translate3d property, so the easiest solution is to remove it:

.md-sidenav-content {
    transform: none !important;
}

NOTE: please check what exactly transform: translate3d(0,0,0) is doing. Here is a good SO answer: https://stackoverflow.com/a/18529444/2765346

like image 3
Hristo Eftimov Avatar answered Nov 09 '22 05:11

Hristo Eftimov