Sidenav on specific component - Angular 5 - angular

is it possible to add a sidenav specifically for a single component?
<app-toolbar></app-toolbar>
<mat-sidenav-container fullscreen>
<mat-sidenav #optionSidenav>
<button (click)="toggleOptionSidenav()"
</button>
</mat-sidenav>
<mat-sidenav #filterSidenav position="end">
<button (click)="toggleFilterSidenav()"
</button>
<a routerLink="/users">Lista de usuarios</a>
</mat-sidenav>
<div class="container-fluid">
<app-loader></app-loader>
<router-outlet></router-outlet>
</div>
</mat-sidenav-container>
I have that piece of code inside app.component.html, but the two sidenav are global, is it possible to add one inside a component that is displayed in the router-outlet?

Related

Vue on click inside component

I have component like this:
<template>
<!-- Content for section1 -->
<div id="section1" class="container-fluid home-div">
<h1 class="text-center">Create Your own Website!</h1>
<p>Welcome to website builder a place where magic comes true. This website will allow you to create your own website, host it on our webserver and change the content or add content as you go!
</p>
<button v-on:click="next" class="btn btn-primary"></button>
</div>
</template>
and my js:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Section1 from '../vue/components/homepage.vue';
import Section2 from '../vue/components/section2.vue';
const routes = [
{ path: '/', component: Section1 },
{ path: '/about', components: Section2, },
];
Vue.use(VueRouter);
const router = new VueRouter({
routes,
});
new Vue({
el: '#homepage',
router,
});
html:
<div id="homepage">
<nav class="navbar navbar-default navbar-fixed-top">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ url('template') }}">Website Builder</a>
</div>
<div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav">
<li><router-link to="/">Create</router-link></li>
<li><router-link to="about">How</router-link></li>
</ul>
</div>
</div>
</nav>
<router-view></router-view>
</div>
So now when I click on the link nothing happens, it has a path of /#/ and /#/about respectively, and are being transformed to tags, what is wrong with my current code? Should the navigation be as a template maybe or within the template?
Your component has local scope, meaning it will try and call a next method on the component itself and not on your root instance where you have actually defined your method.
Depending on your situation and what you want you need to either move the method inside your homepage or section2 component.
Or you need to notify your root Vue instance whenever the click event has been called in a child component. There are many communication patterns possible with Vue.js for child-parent communication an easy one would be this:
https://vuejs.org/v2/guide/components.html#Custom-Events
On click you would emit an event from your child component and use a v-on to listen to the event in your root instance.
But by the looks of it you want to implementing routing with one component per page:
https://vuejs.org/v2/guide/routing.html
in your 'new App', when you set 'el' property it should refer to an ID of an html element (the root element).
your html should be like this instead:
<div id="homepage">
<homepage v-if="seen"></homepage>
<section2 v-else></section2>
</div>

Angular Material few instances of “sidenav” in one component

Angular Material does not work in manner clearly apparent! :(
how to use a few instances of " material sidenav" ??
(THE MY CASE)
I have a few of buttons and i want that each to open another cointainer of sidenav.
solution 1°
each one individually works!, but all each together unfortunately not works!
<mat-sidenav-container>
<nav>
<button mat-fab (click)="menuA.toggle()">/button>
<button mat-fab (click)="menuB.toggle()">/button>
<button mat-fab (click)="menuC.toggle()">/button>
</nav>
<aside>
<mat-sidenav #menuA align="start" mode="over" opened="false">
<!-- sidenav content -->
</mat-sidenav>
<mat-sidenav #menuB align="start" mode="over" opened="false">
<!-- sidenav content -->
</mat-sidenav>
<mat-sidenav #menuC align="end" mode="over" opened="false">
<!-- sidenav content -->
</mat-sidenav>
</aside>
</mat-sidenav-container>
I wonder why above solution does not work!?
solution 2°
Vicariously - I try make this in another way. But this method will require that each "sidenav" has the same input parameters.
Depending which the button, had used, will have been displayed various
the contents, (I keep only one instances of sidenav, but inside I created new vicariously-skelet: such a lot of instances of child "div" of the "sidenav",
how many to need various instances of the "sidenav")
But can I do this otherwise, without adds extra of outlandish ?
Thank you in advance for your support.
Hooray!
I was able to do it!
at this point it works correctly, partly in response to my expectations (how to make that one be open in right side and the other on the left side?)
This is my fix Solution:
My.component.html
<mat-sidenav-container>
<nav>
<button(click)="toggleSideNavSetIn('panelA')"> A </button>
<button(click)="toggleSideNavSetIn('panelB')"> B </button>
<button(click)="toggleSideNavSetIn('panelC')"> C </button>
<button(click)="toggleSideNavSetIn('panelD')"> D </button>
<button(click)="toggleSideNavSetIn('panelE')"> E </button>
</nav>
<main>
<!-- primary content -->
</main>
<mat-sidenav #MyInstSideNav align="start" mode="side" opened="false" [ngSwitch]="toggleSideNavSetOut">
<div *ngSwitchCase="'panelA'">
<mat-toolbar><h1>{{toggleSideNavSetOut}}</h1></mat-toolbar><div> <!-- sidenav content A --> </div>
</div>
<div *ngSwitchCase="'panelB'">
<mat-toolbar><h1>{{toggleSideNavSetOut}}</h1></mat-toolbar><div> <!-- sidenav content B --> </div>
</div>
<div *ngSwitchCase="'panelC'">
<mat-toolbar><h1>{{toggleSideNavSetOut}}</h1></mat-toolbar><div> <!-- sidenav content C --> </div>
</div>
<div *ngSwitchCase="'panelD'">
<mat-toolbar><h1>{{toggleSideNavSetOut}}</h1></mat-toolbar><div> <!-- sidenav content D --> </div>
</div>
<div *ngSwitchCase="'panelE'">
<mat-toolbar><h1>{{toggleSideNavSetOut}}</h1></mat-toolbar><div> <!-- sidenav content E --> </div>
</div>
</mat-sidenav>
</mat-sidenav-container>
My.component.ts
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { ViewChild } from '#angular/core';
import { NgStyle, NgClass, NgSwitch } from '#angular/common';
#Component({
selector: 'app-My',
templateUrl: './My.component.html',
styleUrls: ['./My.component.scss'],
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
})
export class MyComponent implements OnInit {
#ViewChild('MyInstSideNav') MyInstSideNav:any;
constructor() { }
ngOnInit() { }
toggleSideNavSetOut: string ="";
toggleSideNavSetIn(toggleSideNavGet: string){
if (this.MyInstSideNav.opened===false) {
this.toggleSideNavSetOut = toggleSideNavGet;
this.MyInstSideNav.toggle();
} else if (this.MyInstSideNav.opened===true && this.toggleSideNavSetOut != toggleSideNavGet) {
this.toggleSideNavSetOut = toggleSideNavGet;
} else {
this.MyInstSideNav.toggle();
}
}
}
Can it be done in yet another way?

Angular Material 2 - Responsive Toolbar

Using Angular 4 I am trying to have a toolbar on the top of the page that has the following behaviour:
Big Screens
Show the "Main"-Logo/Link on the left, the other top-nav links
on the right.
Small screens
Show the "Main"-Logo Link centered and a menu button on the left for showing the sidenav (containing the links that were visible on the right if the screen is big).
Note:
The sidenav should not go over the toolbar if visible.
Note 2:
The centering of the "Main"-Logo/Link should be centered regarding the overall screen width. It should not be pushed to the right by the menu button.
What I have
<div fxLayout="column" fxFlex>
<md-toolbar color="primary">
<button md-icon-button (click)="sidenav.toggle()" fxHide="false" fxHide.gt-sm>
<md-icon>menu</md-icon>
</button>
<button md-button routerLink="/">
<md-icon>code</md-icon>
<span>{{title}}</span>
</button>
<div fxFlex fxShow="false" fxShow.gt-sm></div>
<div fxLayout="row" fxShow="false" fxShow.gt-sm>
<button md-button routerLink="/about">About</button>
<button md-button routerLink="/legal">Legal Notice</button>
</div>
</md-toolbar>
<md-sidenav-container fxFlex>
<md-sidenav #sidenav fxHide="false" fxHide.gt-sm>
<md-nav-list>
<a md-list-item href="">Main</a>
<a md-list-item href="/about">About</a>
<a md-list-item href="/legal">Legal Notice</a>
</md-nav-list>
</md-sidenav>
</md-sidenav-container>
</div>
Where I struggle
I do not know how to center the "Main"-Logo/Link correctly
If I show the menu in a small screen and switch back the layout to a bigger screen, the menu does not hide
Any help would be greatly appreciated, so thank you already!
Answer to your First Question:
Create a css class say fill-space and use that to center the logo:
.fill-space {
flex: 1 1 auto;
}
... and in your template:
<span fxFlex fxHide="false" fxHide.gt-sm class="fill-space"></span>
<button md-button routerLink="/">
<md-icon>code</md-icon>
<span>{{title}}</span>
</button>
<span class="fill-space"></span>
Answer to your Second Question:
You will have to close() the sidenav manually on screen resize. You can detect that using #HostListener('window:resize', ['$event']):
In your typescript, do the following changes:
// Import the following in your ts file
import { ViewChild, HostListener } from '#angular/core';
import { MdSidenav } from '#angular/material';
// Add the following in your component class to get sidenav
#ViewChild('sidenav') sidenav: MdSidenav;
// Add the method to detect screen-resize
#HostListener('window:resize', ['$event'])
onResize(event) {
if(this.sidenav !== undefined){
this.sidenav.close();
}
}
Link to working demo.

Angular4 material: How to load content to sidenav

So I have put my sidenav in app.component, something like:
<md-sidenav-container fullscreen>
<md-sidenav #sidepanel>...</md-sidenav>
<div class="app">
<main>
<router-outlet></router-outlet>
</main>
</div>
</md-sidenav-container>
now, I have put the reference to the sidenav to my siteService that is overlooking everything and I am able to control it from whenever component I inject siteService.
I would like to load content inside on the fly (similar to what router-outlet does with router-naviagtion...
let's say I would like to load XyComponent1 or XyComponent2 to the sidenav, how would I do that programatically?
You can do this using an aux route:
<md-sidenav-container fullscreen>
<md-sidenav>
<router-outlet name="sidenav"></router-outlet>
</md-sidenav>
<div class="app">
<main>
<router-outlet></router-outlet>
</main>
</div>
</md-sidenav-container>
And you can control it by passing the outlet name:
<a [routerLink]="[{ outlets: { 'sidenav': ['sidenav-component1'] } }]">
Click to apply new sidenav.
</a>
You'll also need to define the components for the routes. This guide is a great excerpt for more details on using aux routes.

How to open the MdSidenav from a children component?

I'm using the MdSidenav component from angular-material2 library and I want to open the MdSidenav from another component. So I'd like to use the functions of the local variable #sidenav (that is in the parent component) from another component (that is the children).
Parent component:
src/app/app.component.html
<md-sidenav-container>
<md-sidenav #sidenav>
<h1>Hello</h1>
</md-sidenav>
<div class="my-content">
<router-outlet></router-outlet>
</div>
</md-sidenav-container>
Child component: src/app/menu/menu.component.html
<div class="menu">
<button (click)="sidenav.open()"></button>
</div>
I had the same similar situation. You can do this:
<md-sidenav-container>
<md-sidenav #sidenav>
<h1>Hello</h1>
</md-sidenav>
<menu [nav]="sidenav"></menu>
</md-sidenav-container>
And then in the menu component:
#Input() nav;
openSideNav(){
this.nav.open();
}

Resources