How to access _factories property from ComponentFactoryResolver in Angular9 which was available in Angular7? - angular9

I used ComponentFactoryResolver to access all the entry component factories and then add routes of those components dynamically in Angular 7.
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
var factories = this.componentFactoryResolver['_factories']
let route: Route = {
path: MyPath,
component: factories[0].factory[1].componentType
};
this.router.resetConfig(config);
I updated my project to Angular 9 and now _factories are not available in ComponentFactoryResolver.
var factories = this.componentFactoryResolver['_factories']
It returns undefined in Angular 9. It will be great help if someone can suggest some way to access all the entry component list on the go. The problem is that I have don't any information available about the entry components from which I may recompile the components through Compiler and add their routes.

I think a simpler approach might be to import the component and use it directly in place of factories[0].factory[1].componentType. Example:
import { MyComponent } from '#app/my.component';
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
let route: Route = {
path: MyPath,
component: MyComponent
};
this.router.resetConfig(config);

Related

How can I using angular when I want to click?

I'm a beginner to learn this component. And I going to try to create a online book shop like this link https://www.fishpond.com.hk/Books , and I'm facing some problem now. Could you guys please help me? And first in my website, it have backend and frontend, and now I can show all book , insert new book, and now I want to know how can I do when I click the title of the book and what I have to do to transfer to get that book detail.
How can I click the title and I will see those book detail on the book-details page. And I hope get the isbn code to find that book.
My code here
HTML
<h1>All Books</h1>
<ul *ngIf="books" class="info">
<li *ngFor="let book of books">
<p><img [src]="book.image" class="bookimg"></p>
<a routerLink="/book-detail"><h3>{{ book.title }}</h3></a>
<p>{{ "By "+ book.author }}</p>
<span class="price-block" >{{ "HK$" + book.price}}</span>
</li>
</ul>
ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
h1Style: boolean = false;
books: Object;
constructor(private data: DataService) {}
ngOnInit() {
this.data.getBooks().subscribe(data=> {
console.log({data}); //show data
this.books = data
//console.log(this.books);
})
}
And I have created a component for book-detail
<h1>Book-detail</h1>
<div *ngIf="books" class="book-detail-block">
<div *ngFor="let bookrecord of books" class="book-record">
<h1>{{bookrecord.title}}</h1>
<p>{{bookrecord.image}}</p>
<p>{{bookrecord.author}}</p>
<p>{{bookrecord.price}}</p>
<p>{{bookrecord.isbn}}</p>
<p>{{bookrecord.description}}</p>
</div>
</div>
ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
#Component({
selector: 'app-book-detail',
templateUrl: './book-detail.component.html',
styleUrls: ['./book-detail.component.scss']
})
export class BookDetailComponent implements OnInit {
h1Style: boolean = false;
books: Object;
constructor(private data: DataService) {}
ngOnInit() {
this.data.getOneBook().subscribe(data => {
this.books = data
console.log(this.books);
})
}
}
I can get the data in the service but how can I implement in show component
export class BookDetailComponent implements OnInit {
h1Style: boolean = false;
books: Object;
constructor(private data: DataService) {}
ngOnInit() {
console.log('-0-----' + this.books)
this.data.getBooks().subscribe(data=> {
console.log({data}); //show data
this.books = data
})
}
}
enter image description here
I may be late to the issue and you've already solved it but in the off-chance that you havent i'll hopefully provide some guidance.
What you want for accessing an individual item when clicking the title is to use a click-event on the tag representing the title, probably the h1-tag. It looks something like this:
<h1 (click)="getBookDetail(bookrecord)">{{bookrecord.title}}</h1>
The line above hooks up a clickevent to a function called getBookDetail and takes the individual object as a parameter, as of now this will render an error saying there's no function named getBookDetail(), so you'll need to create it in the component.ts file that corresponds to the view probably the homecomponent.ts and it looks like this:
getBookDetail(book: any) {
console.log(book);
}
If you now reload the application and click the title you'll see the individual book-object being logged in the console. What you'll need after is to set up routing if you havent already (you get the question to include app-routes module when creating the project) and to create a path for the bookDetailComponent. If you have routing in place add an array of routes as following:
const routes: Routes = [
{ path: '', redirectTo: '/books', pathMatch: 'full' },
{ path: 'books', component: HomeComponent},
{ path: 'book/:id', component: BookDetailComponent },
];
The first item in the routes array will match any route that is empty like localhost:4200 and redirect to the HomeComponent, and the other two arrays are routes for the individual component.
And if you dont have a routing-module i suggest you follow angulars tutorial for adding in-app navigation: https://angular.io/tutorial/toh-pt5.
And for making the click on the title actually navigate to the bookcomponent you first need to inject the Router class, so if you go back to the homecomponent you'll see an constructor (if not create one), add the router class like:
constructor(private router: Router) {}
And in the getBookDetail function you can remove the console.log and add:
getBookDetail(book: any) {
// Wrong path this.router.navigateByUrl('/book/' + book.isbn);
this.router.navigateByUrl('/bookdetail/' + book.isbn);
}
All that you need now is to get the isbn from the url and fetch one book with that identifier, but i'll leave those steps to you, everything you'll need is in the angular tutorial i linked previously. Good luck and if anything is confusing or you have any questions feel free to ask.
Added a stackblitz showing my idea:
https://stackblitz.com/edit/angular-ivy-c2znl2?file=src/app/books/books.component.ts

access store outside of component vuejs

I have a file for configuring my OpenID Connect authentication
export const authMgr = new Oidc.UserManager({
userStore: new Oidc.WebStorageStateStore(),
authority: **appsetting.oidc**
})
I want to access my state in order to get the value of appsetting.
I did this:
import store from './store'
const appsetting = () => store.getters.appsetting
but my appsetting is always returning undefined
what I my missing?
Store:
app.js
const state = {
appsetting: appsetting,
}
export {
state
}
getters.js
const appsetting = state => state.appsetting
export {
appsetting
}
index.js
export default new Vuex.Store({
actions,
getters,
modules: {
app
},
strict: debug,
plugins: [createLogger]
})
when I print the value of store.getters, it returns this:
{
return __WEBPACK_IMPORTED_MODULE_2__store__["a" /* default */].getters;
}
No the actual store objects
Try to import 'store' with curly brackets
import {store} from '../store/index'
store.getters.appSettings
Another option is to access from the vue property
import Vue from 'vue'
Vue.store.getters.appSettings
As for 2023 accesing store with
import {store} from '../store/index'
store.getters.appSettings
wasnt working for me but after removing curly brackets like so:
import store from '../store/index'
store.getters.appSettings
It started working as intended

Angular 2 | Typescript | Mapping an string to a component name and return component

I got list of components that I would like to replace on certain conditions:
List of navigation components:
import {navigationDefaultComponent} from '';
import {navigationSmoothComponent} from '';
import {navigationMobileComponent} from '';
navigations: [
{component: navigationDefaultComponent},
{component: navigationSmoothComponent},
{component: navigationMobileComponent},
]
I have an object that comes from API and tel's me what component I should show
const X = {
name: 'John Smith',
navigation: 'navigationDefaultComponent'
}
I have done it this way, as I can't store the component in the api. The API can not return me a component. If there is a way please do let me know.
So my goal is is to have a const that will go through navigation object and based on x.navigation string will map and return me the component.
const nav = ????
Well, this is a typical situation.
You would need to make one of your component to listen to ** route and then use dynamic component loading. https://angular.io/guide/dynamic-component-loader
You can create an array having string and Component
let mapping = [
{'name':'name1', 'component':Component1},
{'name':'name2', 'component':Component2},
{'name':'name3', 'component':Component3},
{'name':'name4', 'component':Component4},
{'name':'name5', 'component':Component5},
];
Please Note that Component1, Component2 are direct reference to the Component and not their string representations.
Create a directive, to be included in your AppComponent
import { Directive, ViewContainerRef } from '#angular/core';
#Directive({
selector: '[app-directive]',
})
export class AppDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
Include the directive in your template
<ng-template app-directive></ng-template>
Get the reference to your directive in ts file
#ViewChild(AppDirective) appDirective: AppDirective;
Now load the desired component after getting the response from the API
// let's assume name1 is what API returned
let component = this.mapping['name1'];
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(mapping[component);
let viewContainerRef = this.appDirective.viewContainerRef;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent(componentFactory);
I hope this solves your problem...

Load Script Tag in Angular 2 App When Src Attribute is from Web API Call

Context:
I have an Angular 2+ application that makes calls to a web API containing URLs for a src attribute on a script tag that is created by a loadScript function in the AfterViewInit lifecycle hook.
The web API returns a JsonResult and is yielding the data I expect. I was able to interpolate some of the data in the component's template.
Additionally, before I added the call to the web API, the loadScript function was working with a hard-coded argument.
Reading a thread on github. A "member" stated that scripts are not supposed to be loaded on demand. So what I implemented with the loadScript function is essentially a work around, but how else would load them? I don't want to have a seemingly endless amount of script tags sitting in the index.html file.
import { Component, OnInit, AfterViewInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { Http } from '#angular/http';
#Component({
selector: 'app-agriculture-roadmap',
templateUrl: './agriculture-roadmap.component.html',
styleUrls: ['./agriculture-roadmap.component.css']
})
export class RoadmapComponent implements OnInit, AfterViewInit {
constructor(private _httpService: Http, private _route: ActivatedRoute)
{
}
apiRoadmaps: { roadmapName: string, pdfRoadmapURL: string, jsRoadmapURL: string };
ngOnInit() {
this._httpService
.get('/api/roadmaps/' + this._route.params)
.subscribe(values => {
this.apiRoadmaps = values.json() as { roadmapName: string, pdfRoadmapURL: string, jsRoadmapURL: string };
});
}
async ngAfterViewInit() {
await this.loadScript(this.apiRoadmaps.jsRoadmapURL);
}
private loadScript(scriptUrl: string) {
return new Promise((resolve, reject) => {
const scriptElement = document.createElement('script')
scriptElement.src = scriptUrl
scriptElement.onload = resolve
document.body.appendChild(scriptElement)
})
}
}
If you are using angular cli .
Then place these scripts in
angular-cli.json file under scripts array
scripts:[
.....
]
Please refer this [link] (https://rahulrsingh09.github.io/AngularConcepts/faq)
It has a question on how to refer third party js or scripts in Angular with or without typings.

Angular - Is it possible to destroy component (not dynamically created)?

I am using Angular 2 google map one of our application. We are loading marker every 5 secs using Sockets. The problem is need to remove previous marker when new marker receive from socket. There is no proper documents in Angular map official site. So thought of destroy components from our app components. And we got all the child components find the following code.
import { Component, OnInit, ViewChild, ViewChildren, QueryList } from '#angular/core';
import { Socket } from 'ng2-socket-io';
import { Marker } from './google-map';
import { SebmGoogleMapMarker } from 'angular2-google-maps/core';
#Component({
selector: 'app-google-map',
templateUrl: './google-map.component.html',
styleUrls: ['./google-map.component.scss'],
providers: [SebmGoogleMapMarker]
})
export class GoogleMapComponent implements OnInit {
public lat: number = 51.678418;
public lng: number = 7.809007;
public markers: Marker[] = [];
#ViewChildren(SebmGoogleMapMarker) SebmGoogleMapMarkers: QueryList<SebmGoogleMapMarker>;
constructor(private socket: Socket) { }
ngOnInit() {
this.socket.on('markers', this.setMarkers);
}
setMarkers = (data: Marker[]) => {
this.removeMarkers();
for (let marker of data) {
var model = new Marker(marker);
this.markers.push(model);
}
}
removeMarkers() {
if (this.SebmGoogleMapMarkers.length > 0) {
this.SebmGoogleMapMarkers.forEach((ele) => {
ele.ngOnDestroy();
});
}
}
}
<div class="col-lg-12">
<sebm-google-map [latitude]="lat" [longitude]="lng">
<sebm-google-map-marker *ngFor="let marker of markers" [latitude]="marker.latitude" [longitude]="marker.longitude">
</sebm-google-map-marker>
</sebm-google-map>
</div>
We got all child components but still reference are there SebmGoogleMapMarkers query list. Is there anyway to destroy component angular way?
Actually here my concern is this.SebmGoogleMapMarkers.length is increasing every 5 sec. what i am feeling is application performance will be reduce.
Solution: I made silly mistake forgot to make marker array empty before pushing.
As far as I know there is no way to destroy a component that was not dynamically added. You can use *ngIf to remove a component though:
<sebm-google-map-markers *ngIf="show">
You can also create your own *ngIf variant that for example includes the logic to remove the component when not needed anymore. Creating such a structural directive is quite simple (https://angular.io/docs/ts/latest/guide/structural-directives.html)