Imported angular module doesn't work the first time a route is visited, but it works in the subsequent visits - css

I have a simple Loader Module hosted in a private npm repository. This module only intercepts http calls and displays a css loader. The code is simple: it has a public api that exports the module and a component. The module has an http interceptor that calls a service which sets a variable isLoading.
The component code is split into three files, as usual (ts, html and scss).
loader.component.ts
import { Component, OnInit, AfterViewInit } from '#angular/core';
import { LoaderService } from '../service/loader.service';
#Component({
selector: 'loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.scss']
})
export class LoaderComponent implements OnInit {
public isLoading: boolean;
constructor(private loaderService: LoaderService) { }
ngOnInit(){
this.loaderService.isLoading.subscribe(status => this.isLoading = status);
}
}
loader.component.html
<div *ngIf="isLoading" class="overlay">
<div class="loader center-block"></div>
<p class="wait">
<strong>Wait... </strong>
</p>
</div>
The loader.component.scss file defines the loader, overlay and wait css classes (not shown for brevity).
The interceptor code is here:
#Injectable()
export class LoaderInterceptor implements HttpInterceptor {
constructor(private loaderService: LoaderService) {}
intercept(
request: HttpRequest<unknown>,
next: HttpHandler
): Observable<HttpEvent<any>> {
this.loaderService.show();
return next.handle(request).pipe(finalize(() => this.loaderService.hide()));
}
}
And finally, the service code:
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class LoaderService {
public isLoading: Subject<boolean>;
constructor() {
this.isLoading = new Subject<boolean>();
}
show() {
this.isLoading.next(true);
}
hide() {
this.isLoading.next(false);
}
}
This module is imported at the app.module.ts of an application and declared in the imports array of the decorator.
The application has some routes with lazy load feature modules.
The loader module is used at the app.component.html file, as follows:
<loader></loader>
<router-outlet></router-outlet>
The problem: the loader does not work the first time we visit a route, but it works if we click the previous button at the browser or we click to go back to homepage or any other way I tested visiting a route twice or more. Otherwise, it doesn't work.
I tried to find similar questions, I tried to see the order of css imports, I also tried to analise the loader module, the import order, but no clue about what is happening.

Related

kendo-card tag not formatting a card on angular app

Looking for help to troubleshoot this.
When I try to create a card on the UI using kendo, it works on stackblitz:
https://stackblitz.com/edit/5zvomp--run?file=app/app.component.ts
but when trying to create in my angular app, it doesnt show up properly. There are no errors in the console and import { LayoutModule } from '#progress/kendo-angular-layout'; is also there.
html template:
<kendo-card class="user-card">
<kendo-card-header class="k-hbox">
<div>
<h1 kendoCardTitle>Turtle</h1>
<p kendoCardSubtitle>Turtle is a small animal</p>
</div>
</kendo-card-header>
</kendo-card>
angular component:
import { Component, OnInit, Input } from '#angular/core';
import * as faEllipsisH from '#fortawesome/pro-regular-svg-icons/faEllipsisH';
#Component({
selector: 'user-card',
templateUrl: './user-card.component.html',
styleUrls: ['./user-card.component.css']
})
export class UserCardComponent implements OnInit {
#Input() public card: any;
public faEllipsisH = faEllipsisH;
public constructor() { }
public ngOnInit(): void {
}
}
The only way that I was able to replicate this was if you did not import the Kendo-UI stylesheet.
Take a look at this example: https://stackblitz.com/edit/angular-pnudiu?file=index.html
If you uncomment out the commented line in index.html, you get the properly styled card. For more information on how to include the styling and themes, visit this documentation: https://www.telerik.com/kendo-angular-ui/components/styling/#toc-including-themes-by-using-precompiled-css

Attach event to all elements with a specific class

I would like to attach an event listner in my component that will fire for all elements that have a specific class.
These are generated by a third party component so i cannot attach it at the point where they are created.
i would like to do effectively do the equivalent of the following jquery statement but in angular where .day is the class.
$(document).on('mousedown','.day',function(jsEvent){
});
Thanks
You can use a Directive to attach the listener:
import { Directive, HostListener } from '#angular/core';
#Directive({
selector: '.day'
})
export class DayDirective {
#HostListener('mousedown', ['$event'])
yourFunction(event: Event): void { ... }
}
To wire up the Directive, you add it to the module that requires it. This could be your app module, a shared module or a feature module.
import { NgModule } from '#angular/core';
#NgModule({
declarations: [
DayDirective,
],
...
})
export class YourModule {}

Angular 6 http not working with single JSON item

Trying to get Wordpress data into my Angular 6 component.
When I return a single post via Wordpress REST API it produces the right data (http://w3stage.com/tricap/wp-json/wp/v2/properties/174), but the data is not making it through to my template.
service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class WordpressService {
constructor(private http: HttpClient) { }
getProperty(id): Observable<any[]> {
return this.http.get<any[]>('http://w3stage.com/tricap/wp-json/wp/v2/properties/'+id);
}
}
component:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { Location } from '#angular/common';
import { Observable } from 'rxjs';
import { WordpressService } from '../wordpress.service';
#Component({
selector: 'app-property-detail',
templateUrl: './property-detail.component.html',
styleUrls: ['./property-detail.component.scss']
})
export class PropertyDetailComponent implements OnInit {
property: Observable<any[]>;
constructor(
private route: ActivatedRoute,
private location: Location,
private wp: WordpressService
) {
this.getProperty();
}
getProperty(): void {
const id = +this.route.snapshot.paramMap.get('id');
this.property = this.wp.getProperty(id);
console.log(this.property);
}
ngOnInit(): void {
}
}
template:
{{ property.title.rendered }}
This generates the following error:
ERROR TypeError: Cannot read property 'rendered' of undefined
at Object.eval [as updateRenderer] (PropertyDetailComponent.html:8)
at Object.debugUpdateRenderer [as updateRenderer] (core.js:10782)
at checkAndUpdateView (core.js:10158)
at callViewAction (core.js:10394)
at execComponentViewsAction (core.js:10336)
at checkAndUpdateView (core.js:10159)
at callViewAction (core.js:10394)
at execEmbeddedViewsAction (core.js:10357)
at checkAndUpdateView (core.js:10154)
at callViewAction (core.js:10394)
However, when I adapt the code to return a bunch of posts from wordpress, I can get the data to work just fine in conjunction with an *ngFor loop. When I try an *ngFor loop with the single post result, same thing - no go.
You need to use safe navigation operator or *ngIf inorder to handle the delay of response from your asynchronous request,
change your template as,
{{ property?.title?.rendered }}
also you need to subscribe to the observable,
this.wp.getProperty(id).subscribe(data => {
this.property = data;
});

Angular Dynamic Components - Add Class and other attributes

I am using the following code for creating the dynamic components
import {
Component, OnInit, ViewContainerRef, ViewChild, ViewChildren,
ReflectiveInjector, ComponentFactoryResolver, ViewEncapsulation, QueryList, Input, AfterViewInit
} from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { forEach } from '#angular/router/src/utils/collection';
import { IComponent } from 'app/app.icomponent';
#Component({
encapsulation: ViewEncapsulation.None,
selector: 'dynamic-component',
entryComponents: [HomeComponent, HighlevelSignalComponent],
template: `
<div #dynamicDiv [ngClass]="classFromMenu" >
<ng-template #dynamicComponentContainer></ng-template>
</div>
`,
styleUrls: [
'./dynamic-content.component.css'
],
})
export class DynamicComponent implements IComponent, OnInit, AfterViewInit {
classFromMenu: any;
#ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver, private route: Router,
private activatedRoute: ActivatedRoute, ) {
}
.......
buildComponent(passedData) {
// orderAndObjs has the data for creating the component
this.orderAndObjs.forEach(obj => {
var componentFactory = this.resolver.resolveComponentFactory(obj.component);
var compRef = this.dynamicComponentContainer.createComponent(componentFactory);
// compRef is the component that is created.
//Assuming the component that i am trying to create is <dynamic-component>.
//I want to add either a class or any other attribute like this
//<dynamic-component class="flex">
});
}
}
}
The dynamic-component is created perfectly fine and everything is working as expected. But the only issue is I want to add a class for dynamic-component so that it can be
<dynamic-component class="dynamicClass">
Any help is appreciated :(
Hmm.. I usually add it to the selector of component that is supposed to be an entryComponent ...
selector: 'dynamic-component.someclass',
^^^^^^^^^^^
to add attribute use attribute selector:
selector: 'dynamic-component[myattr=value]',
I call it hidden feature of entryComponents
but its declarative approach and can't be changed at runtime(indeed we can change it)
In Angular 5/6, using Renderer2 from #angular/core, you can do something like below:
constructor(private resolver: ComponentFactoryResolver, private route: Router,
private activatedRoute: ActivatedRoute, private renderer2: Renderer2) {
}
buildComponent(passedData) {
this.orderAndObjs.forEach(obj => {
var componentFactory = this.resolver.resolveComponentFactory(obj.component);
var compRef = this.dynamicComponentContainer.createComponent(componentFactory);
this.renderer2.addClass(compRef.location.nativeElement, 'flex');
});
}
High-level DOM operations are performed with Renderer2 provider. Considering that it was injected, it is:
this.renderer2.addClass(compRef.location.nativeElement, 'dynamicClass');
It should be noticed that depending on how dynamic element is attached to DOM, this may be unnecessary complication.
Considering that dynamicComponentContainer is real DOM element and not <ng-template>, the view of dynamic component can be directly mounted to the container, thus eliminating <dynamic-component> wrapper element:
Given the container:
<div class="dynamicClass" #dynamicComponentContainer></div>
It will be:
var compRef = componentFactory.create(
this.injector,
[],
this.dynamicComponentContainer.element.nativeElement
);

Binding is not working in Angular2 template

errorType is not showing when calling with Alert.showAlert("success","someMsg");from another Component but it's working when initializing at the declaration of errorType itself.
component :
import {Component} from 'angular2/core';
#Component({
selector: 'alert-component',
templateUrl: 'app/alert.template.html'
})
export class Alert {
public static errorType:string;
public static messageAlrt:string;
public static showAlert(type:string, message:string): void{
Alert.errorType=type;
}
}
template :
<div id="messageAlert" >
<strong>{{errorType}}:</strong> this is the error message at top of the page
</div>
Really apreciate your help in resolving this problem that errrorType value is not getting bound to erroType
It's because you use static fields. When using {{errorType}}, a non static property of the component is used.
I would refactor your component this way:
import {Component} from 'angular2/core';
#Component({
selector: 'alert-component',
templateUrl: 'app/alert.template.html'
})
export class Alert {
public errorType:string;
public messageAlrt:string;
}
When you want to display your alert, I would add it dynamically:
#Component({
(...)
template: `<div #target></div>`
})
export class SomeComponent {
#ViewChild('target', {read: ViewContainerRef}) target;
showAlert(type:string, message:string) {
this.resolver.resolveComponent(Alert).then(
(factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory);
this.cmpRef.type = type;
}
);
}
See this great Günter's answer:
Angular 2 dynamic tabs with user-click chosen components

Resources