Angular mat-sidenav property isHandset$ | async explain - angular-material

<mat-sidenav-container class="sidenav-container">
<mat-sidenav #drawer class="sidenav" fixedInViewport="true" [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
[mode]="(isHandset$ | async) ? 'push' : 'push'" [opened]="!(isHandset$ | async)">
<mat-toolbar color="primary">Menu</mat-toolbar>
<mat-nav-list>
<a mat-list-item href="#">Link 1</a>
<a mat-list-item href="#">Link 2</a>
<a mat-list-item href="#">Link 3</a>
</mat-nav-list>
</mat-sidenav>
I do not understand what is written in the code (isHandset$ | async)please explain

'Handset' is one of the breakpoint names of angular material layout. The list of breakpoint names is Handset, Tablet, Web, HandsetPortrait, TabletPortrait, WebPortrait, HandsetLandscape, TabletLandscape, WebLandscape.
Please check https://material.io/design/layout/responsive-layout-grid.html#breakpoints for more information about material layout breakpoints
In your example above, isHandset$ is coming from the corresponding component .ts file. Please look for code similar to below in your component file.
isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
.pipe(
map(result => result.matches)
);
When you resize the browser and when browser width matches with handset (mobile phone screen) width isHandset$ sets to true. ! (isHandset$ | async) in turn sets 'opened' attribute of sidenav drawer to false and collapses the sidenav drawer.
As isHandset$ is an Observable property, therefore 'async' pipe is used for the asynchronous call.

With regard to #MuhammadMehdi's comment:
[attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
is used for accessibility. People that have disabilities and for example are blind need to use a screen reader, for that purpose they are adding the 'dialog' role on the small screen size (because the menu pops out like a dialog) and 'navigation' role on the desktop size because its always displayed and used for navigation.
Here you have some more info on aria roles
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles

Related

routerLinkActive id coupled with [ngClass]

Below web-link demonstrates the routerLinkActive id working when used as a boolean value for a distinct HTML element' [ngClass]
https://stackblitz.com/edit/routerlinkactivesimple?file=src%2Fapp%2Fapp.module.ts
In contrast the routerLinkActive id is not working with #angular/material instance below web-link, but the error disappears by commenting lines 5 and 6 , however not rectifying the usability of routerLinkActive id:
https://stackblitz.com/edit/mat-routerlinkactive?file=src%2Fapp%2Fnav%2Fnav.component.html
your second link has a lot of issues, the app-nav is not even used, so "commenting lines" is not enough to make it work..
but anyway
there is no issue with routerLinkActive, the problem is :
<button mat-button color="white" fxHide.xs *ngIf="true">
<span>
<a routerLink="city-list" routerLinkActive="active-link citNgClassList" #rla_clist="routerLinkActive"
[routerLinkActiveOptions]="{exact: true}">
<mat-icon class="mr">maps_home_work</mat-icon>
Cities
</a>
</span>
</button>
your link is inside a button..
remove the button, keep the "a" and it works
and what's the point of *ngIf="true" ?
Edit :
you can keep the button and remove the 'a' if you want to keep the button style (but it's bad usability wise to display link as button..), just put routerLink, routerLinkActive & routerLinkActiveOption on the button directly
Thanks, JiBi , for your observations. Indeed stripping off the material button wrapper of the links does not longer gives an error on the second StackBlitz link line 5 span , but it hurts to the over all page with styling in a bad way that breaks the harmony of the page that is not easy to substitute. I have removed some of the comments , that were left in place to give an easy idea of what I have tried.
The *ngIf= "true" of the buttons was meant to be a *ngIf= "!rla_clist" or *ngIf= "!rla_cform" so the button sender to the link will not displayed if I am on the link itself ,.....but this is another problem of which better solution I am awaiting.

What happened to w3-sidenav? Is it possible to use w3-sidebar instead without the drawbacks?

What happened to w3-sidenav? We now only seem to have w3-sidebar which is not as good as it always displays in large (laptop, desktop) machines.
Is it possible to use w3-sidebar, but avoid the always-on problem for large screens? I want it visible only when I say.
The w3 tutorials suggest that you use a class="w3-sidebar w3-bar-block" to build a side nav. You have different option of always display etc:
1) Always Display: Add Style="width=25%", and then to the adjacent div, add style="margin-left:25%"
2)Open over content:
a) add to sidebar style="display:none" id="mySideBar" <button onClick="we-close" class="w3-bar-iitem w3-large">Close × </button>
b) Add to content (Adjacent Div): <button class="w3-button w3-large" onClick="W3-open()">☰ </button>
c) Add script
function w3-open(){
document.getElementById("mySideBar").style.display="block";
}
function w3-close(){
document.getElementById("mySideBar").style.display="none";
}
Another option with this is to open the sidebar over the whole page, in which case you will use the same code as option 2 above, just add to the JS w3-open() function: document.getElementById("mySideBar").style.width="100%";
3) Collapsible & Responsive: (I think this is the one you will probably prefer):
a) Define sidebar div with
class="w3-sidebar w3-bar-block w3-collapse w3-card w3-animate-left" style="width: 200px" id="mySideBar">
<button class="w3-bar-item w3-button w3-large we-hide-large" onClick="w3-close()">close × </button>
b) Define the main wrapper div with
<div class="w3-main" style="margin-left:200px">
<div class="w3-blue">
<button class="w3-button …." onClick="w3-open()"> ☰ </button>
</div>
</div>
c) insert the javascript as per the above option 2, both w3-open() & w3-close()
Do not quote my code above, I just typed it freehand, so its probably riddled with errors.
Here is the w3school script for option 3
You can read more about sidebars here.

angular material mat-sidenav async content area not rendering in correct position

I have a sidenav that works great with mock data, but when I load the data for the sidenav asynchronously from a rest service, the content part renders on the entire page area, and then when the async call returns, the sidenav renders, and ends up covering part of the content area. If I close the sidenav and open again, it looks find. However, on initial load, I can't see the left part of the content.
<mat-sidenav-container fullscreen class="main-sidenav-container">
<mat-sidenav #sidenav mode="side" opened>
<mat-nav-list>
<mat-list-item disa *ngFor="let navBarItem of observableNavBarItems|async" (click)="onSelected(navBarItem.value)">
<img mat-list-icon class="{{navBarItem.icon}}" />
<h4 mat-line>{{navBarItem.name}}</h4>
</mat-list-item>
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
Any thoughts on how to fix this?
i fixed a similar Problem (using the MatDrawer) by setting the following MatDrawerContainer property according to the Angular Materials documentation: https://next.material.angular.io/components/sidenav/api
#Input()
autosize: boolean
Whether to automatically resize the container whenever the size of
any of its drawers changes.
Use at your own risk! Enabling this option can cause layout thrashing
by measuring the drawers on every change detection cycle. Can be
configured globally via the MAT_DRAWER_DEFAULT_AUTOSIZE token.
in my case:
<mat-drawer-container autosize="true" >
<mat-drawer #drawer mode="side" opened="true">
...
</mat-drawer>
<mat-drawer-content>
...
</mat-drawer-content>
</mat-drawer-container>
i had the same problem and i've found a solution that works fine in my case.
First of all, i needed my component hosting the mat-nav-list being invoked as soon as its view had been rendered.
In order to do this, i choose to decorate mat-nav-list with a directive (renderingDetector).
Here is the code:
import { Directive, AfterViewInit, Output, EventEmitter } from '#angular/core';
#Directive({
selector: '[renderingDetector]'
})
export class RenderingDetectorDirective implements AfterViewInit {
#Output() onViewRendered = new EventEmitter<void>(true);
ngAfterViewInit() {
this.onViewRendered.emit();
}
}
NOTE: as a possible solution, i also tried to move the whole mat-nav-list content into a separate component in order to control its life-cycle as well as it's been done inside the directive, but this approach headed to the application recharging the page every time i clicked on an item (so that all benefits of Single Page Application went lost).
On the other side, the hosting component keeps watching on it.
<mat-nav-list renderingDetector (onViewRendered)="viewRendered()">
In order to have the mat-sidenav-content being rendered exactly beside the menus we should properly set the margin-left property.
#ViewChild('sidenavRef') sideNavRef: MatSidenav;
#ViewChild('sidenavContentRef', {read: ElementRef}) sideNavContentRef: ElementRef;
viewRendered() {
this.sideNavContentRef.nativeElement.style.marginLeft = String(this.sideNavRef._width) + "px";
}
sidenavRef and sidenavContentRef refer to the mat-sidenav and mat-sidenav-content elements in the html file
<mat-sidenav-container>
<mat-sidenav #sidenavRef>
...
</mat-sidenav>
<mat-sidenav-content #sidenavContentRef>
...
</mat-sidenav-content>
</mat-sidenav-container>

md-autocomplete in angular material - how to keep the class "md-not-found"

The md-autocomplete provides a class named md-not-found in the md-virtual-repeat-container when you are trying to search for an element that does not exist in the dropdown, displaying an error message underneath. When you remove focus from the input element, the md-not-found is removed. The autocomplete therefore gives a false impression of having a valid input, as the user is not presented with any feedback.
Is there any way to keep the class "md-not-found", even after you unfocus the input element?
md-autocomplete official demo: https://material.angularjs.org/latest/demo/autocomplete
Update
I have made a temporary solution:
<label class="{{selectedItem !== null || searchText === '' ? '' : 'label-error'}}">Name</label>
The label-error class applies a red color.
The solution is not an answer to the question per se, but offers an alternative quick fix
I used md-autocomplete inside the md-chips and its working as well as you want.
When request return noContent(204) md-not-found is being visible and it isn't disappear until user start texting again.
<md-content layout="column">
<md-chips
class="md-input"
ng-model="myItem"
md-autocomplete-snap
md-on-add="change()"
md-on-remove="change()"
required
md-require-match="true"
md-transform-chip="reformr($chip)"
md-separator-keys="keys">
<md-autocomplete md-selected-item="selectedItem"
md-no-cache="true"
md-search-text="search.text"
md-items="item in getSuggestedItems()"
md-item-text="item.name"
md-min-length="0"
placeholder="{{ 'textItemName' | translate }}"
required
md-input-name="suggestedItem"
md-search-text-change="listSuggestedItems(search.text)">
<span md-highlight-text="search.text" md-highlight-flags="^i">{{item.name}}</span>
<md-not-found>
{{'no_item_found' | translate}}
</md-not-found>
</md-autocomplete>
</md-content>

Making first mobile Safari tap a 'clickable action'

I have seen variations on the theme, but no clear answer. Basically I want an AngularJS Directive that registers a click and inserts extra content into a page, and then scrolls down a bit to make the new content visible. Here is the HTML
<li class="btn btn-default" ng-show="resto.link !== 'none'">
<p scroll-down onclick="void(0)">
Full review
<span class="glyphicon glyphicon-chevron-right right"></span>
</p>
</li>
</ul>
<div class="row">
<div class="col-xs-12" ng-bind-html="fullReview">
</div>
</div>
The onlick part is an Apple suggestion, that seems not to work.
And then I have:
.directive 'scrollDown', () ->
restrict: 'A'
link: (scope, $elm, attrs) ->
$elm.on 'click', (e) ->
e.preventDefault()
scope.getFullReview () ->
console.log "Scrolling'
$("body").animate
scrollTop: $elm.offset().top - 100
, "slow"
getFullReview() updates the model after an AJAX call, and then runs the callback.
This works fine in Chrome but not on the iOS simulator - basically a first tap makes the page move (but without triggering the console log - I think this is the URL bar regrowing) and a second is needed to trigger the Directive's link function. I have also installed fastclick as that was mentioned in some posts, but it did not help.
Need ideas :-) (Even some code that would tell me what event is being triggered by safari)
OK, Wow, I do not understand why, but the html above was the last markup on the page, so all of this was happening at the bottom of the screen. When I added some extra margin to the <ul> element, everything started working perfectly!! Bug in Safari?

Resources