<span awesomeTooltip="'Tooltip text'"> </span>
<span [awesomeTooltip]="'Tooltip text'"> </span>
<input type="text" name="fname" #inputTag>
ViewChild
decorator: class SomeComponent implements AfterViewInit { @ViewChild('inputTag') inputTag: ElementRef; ngAfterViewInit(){ const input$ = fromEvent(this.inputTag.nativeElement, 'keyUp') } ... }
ViewChild
returns undefined
, look in the *ngIf
template. <div *ngIf="someCondition"> <input type="text" name="fname" #inputTag> </div>
ng-template
above the problem element.ViewChild
will be able to return a link to it in the ngAfterViewInit
hook. <div [hidden]="!someCondition"> <input type="text" name="fname" #inputTag> </div>
class SomeComponent { @ViewChild('inputTag') set inputTag(input: ElementRef|null) { if(!input) return; this.doSomething(input); } doSomething(input) { const input$ = keysfromEvent(input.nativeElement, 'keyup'); ... } }
inputTag
property, we create a stream from the data entered in the input field.ViewChild
in Angular 8 can be static and dynamic.*ngFor
. <div *ngFor="let item of itemsList; let i = index;" [customScroll] > <p *ngFor="let item of items" class="list-item">{{item}}</p> </div>
scrollDirective.update
to adjust the scrolling behavior taking into account the changes that occurred in the list.ngOnChanges
hook: class SomeComponent implements OnChanges { @Input() itemsList = []; @ViewChild(CustomScrollDirective) scroll: CustomScrollDirective; ngOnChanges(changes) { if (changes.itemsList) { this.scroll.update(); } } ... }
*ngFor
terminates?*ngFor
( #listItems
) is #listItems
. <div [customScroll]> <p *ngFor="let item of items" #listItems>{{item}}</p> </div>
ViewChildren
decorator. It returns an entity of type QueryList
.QueryList
class has a read-only changes property that QueryList
events each time the list changes. class SomeComponent implements AfterViewInit { @Input() itemsList = []; @ViewChild(CustomScrollDirective) scroll: CustomScrollDirective; @ViewChildren('listItems') listItems: QueryList<any>; private sub: Subscription; ngAfterViewInit() { this.sub = this.listItems.changes.subscribe(() => this.scroll.update()) } ... }
// app-routing.module.ts const routes: Routes = [ {path: '', redirectTo: '/home', pathMatch: 'full'}, {path: 'home', component: HomeComponent}, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], // #1 exports: [RouterModule] }) export class AppRoutingModule { } //app.module.ts @NgModule({ ... bootstrap: [AppComponent] // #2 }) export class AppModule { } // app.component.html <router-outlet></router-outlet> // #3 // app.component.ts export class AppComponent implements OnInit { title = 'QueryTest'; constructor(private route: ActivatedRoute) { } ngOnInit() { this.route.queryParams .subscribe(params => { console.log('saveToken', params); // #4 }); } }
#x
. Consider them:RouterModule
there. The routes are configured so that if the route is not provided in the URL, we redirect the user to the /home
page.AppComponent
.AppComponent
uses <router-outlet>
to output the corresponding route components.queryParams
for the route from the URL https://localhost:4400/home?accessToken=someTokenSequence
queryParams
will look like this: {accessToken: 'someTokenSequence'}
queryParams
object is queryParams
twice. The first object is empty, it is issued during the initialization process of the Angular router. Only after that we get an object containing the request parameters (in our case, {accessToken: 'someTokenSequence'}
).ActivatedRoute.queryParams
. As usual - consider a step by step solution to the problem.paramsInUrl$
, will output data if the queryParams
value queryParams
not empty: export class AppComponent implements OnInit { constructor(private route: ActivatedRoute, private locationService: Location) { } ngOnInit() { // // const paramsInUrl$ = this.route.queryParams.pipe( filter(params => Object.keys(params).length > 0) ); ... } }
noParamsInUrl$
, will output an empty value only if no request parameters were found in the URL: export class AppComponent implements OnInit { title = 'QueryTest'; constructor(private route: ActivatedRoute, private locationService: Location) { } ngOnInit() { ... // , , URL // const noParamsInUrl$ = this.route.queryParams.pipe( filter(() => !this.locationService.path().includes('?')), map(() => ({})) ); ... } }
export class AppComponent implements OnInit { title = 'QueryTest'; constructor(private route: ActivatedRoute, private locationService: Location) { } ngOnInit() { // // const paramsInUrl$ = this.route.queryParams.pipe( filter(params => Object.keys(params).length > 0) ); // , , URL // const noParamsInUrl$ = this.route.queryParams.pipe( filter(() => !this.locationService.path().includes('?')), map(() => ({})) ); const params$ = merge(paramsInUrl$, noParamsInUrl$); params$.subscribe(params => { console.log('saveToken', params); }); } }
param$
object param$
value only once - regardless of whether there is anything in the queryParams
(an object with query parameters is issued) or not (an empty object is issued). // home.component.html <div class="wrapper" (mousemove)="mouseCoordinates = {x: $event.x, y: $event.y}"> <div *ngFor="let item of items"> <span>{{formatItem(item)}}</span> </div> </div> {{mouseCoordinates | json}} // home.component.ts export class HomeComponent { items = [1, 2, 3, 4, 5, 6]; mouseCoordinates = {}; formatItem(item) { // const t = Array.apply(null, Array(5)).map(() => 1); console.log('formatItem'); return item + '%'; } }
formatItem
method.formatItem
function). As a result, if some heavy calculations are performed in the template functions, this will put a load on the processor and affect how users will perceive the corresponding page.formatItem
in advance and display the ready data on the page. // home.component.html <div class="wrapper" (mousemove)="mouseCoordinates = {x: $event.x, y: $event.y}"> <div *ngFor="let item of displayedItems"> <span>{{item}}</span> </div> </div> {{mouseCoordinates | json}} // home.component.ts @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.sass'] }) export class HomeComponent implements OnInit { items = [1, 2, 3, 4, 5, 6]; displayedItems = []; mouseCoordinates = {}; ngOnInit() { this.displayedItems = this.items.map((item) => this.formatItem(item)); } formatItem(item) { console.log('formatItem'); const t = Array.apply(null, Array(5)).map(() => 1); return item + '%'; } }
mousemove
event still leads to the launch of a change check. But, since we need the coordinates of the mouse, we cannot get rid of it.mousemove
event handler only needs to perform some calculations (which do not affect what is displayed on the page), then to speed up the application, you can do the following:NgZone.runOutsideOfAngular
inside the event handler function. This prevents the launch of a change check when a mousemove
event mousemove
(this will affect this handler exclusively). * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; //
Source: https://habr.com/ru/post/459304/
All Articles