Component take user from service with params
#Component({
selector: 'users',
providers: [UserService],
template: `
<p>{{user.id}}</p>
`
})
export class UserPageComponent implements OnInit {
constructor(
private userService: UserService,
private route: ActivatedRoute
) {};
ngOnInit(): void {
this.route.params.forEach((params: Params) => {
let id = +params['id'];
this.userService.getUser(id)
.then(user => {console.log(user.id);this.user = user})
});
}
Service :
#Injectable()
export class UserService {
private postUrl = 'http://127.0.0.1:8000/user-detail/'; // URL to web api
constructor(private http: Http) {
}
getUser(id: number): Promise<User> {
return this.http.get(this.postUrl+id)
.toPromise()
.then(response => response.json() as User)
.catch(this.handleError);
};
And I get Error Uncaught (in promise): Error: Error in ./UserPageComponent class UserPageComponent - inline template:1:7 caused by: Cannot read property 'id' of undefined
It looks as if the service does not send the promise, although it should.
How to solve this proble?
It looks like your component doesn't have default value for user, so it is undefined when component rendered try adding default value
#Component({
selector: 'users',
providers: [UserService],
template: `
<p>{{user.id}}</p>
`
})
export class UserPageComponent implements OnInit {
user = {} // default value for user
constructor(
private userService: UserService,
private route: ActivatedRoute
) {};
ngOnInit(): void {
this.route.params.forEach((params: Params) => {
let id = +params['id'];
this.userService.getUser(id)
.then(user => {console.log(user.id);this.user = user})
});
}
actually it will be better to add some conditional logic here then
<p *ngIf="user">{{user.id}}</p>
it should work
Related
I have an Angular Frontend and I want to have access to the image in my backend. So I created webservices,
with security authenticated;
//AppParam{int id, AppFileInfo logo}
#GetMapping(value = "/allParam")
public List<AppParam> getAllParams (){
return paramsSiteService.findAllParam();
}
// model
export class ParamSite {
public id: string;
public file;
constructor(file) {
this.file = file;
}
}
//service
#Injectable({
providedIn: 'root'
})
export class ParamSiteService {
host: string;
headers;
constructor(private http: HttpClient, private authService: AuthentificationService, private appConfigService: AppConfigService) {
this.headers = new HttpHeaders({'authorization': this.authService.jwt});
this.host = this.appConfigService.getMyUrl();
}
...
getAllParam(): Observable<any> {
console.log(this.host);
console.log(this.headers);
console.log(this.authService.jwt);
return this.http.get(this.host + "/allParam", {headers: this.headers})
.pipe(catchError((error: any) => {
console.log(error);
return Observable.throw(error);}
));;
}
//html
<img src={{logo.file}} alt="" width="50">
// ts
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
showFiller: boolean;
logo ;
constructor(private authService: AuthentificationService, private router: Router,
private frontDynamic: FrontDynamicService,private cdRef:ChangeDetectorRef
,private paramSiteService: ParamSiteService) {
}
ngOnInit(): void {
this.authService.loadToken();
this.getLogo();
}
ngAfterViewChecked(){
this.cdRef.detectChanges();
}
ngOnDestroy(): void {
this.onLogOut()
};
onLogOut() {
return this.authService.logout()
}
public getLogo(){
this.paramSiteService.getAllParam().pipe(take(1)).subscribe(param => {
this.logo = param;
console.log(param);
},
error => console.log(error)
);
}
...
}
Console browser
core.js:4081 ERROR TypeError: Cannot read property 'file' of undefined
Console.log "getAllParam()
param-site.service.ts:35 http://localhost:8082
param-site.service.ts:36 HttpHeaders {normalizedNames: Map(0),
lazyUpdate: null, lazyInit: Ć’} param-site.service.ts:37
Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJCZXJuYXJkIiwicm9sZSI6WyJBRE1JTiJdLCJpc3MiOiIvbG9naW4iLCJleHAiOjE2MTI4ODI2NDV9.GO-mvwvU0tMYdgoeNvBEPfggnZjI1kO7GMJoAfRL_S8
I have solved the problem by allowing the webservice for All.
It's not the best solution but main component, I should have put login as the main component.
I Need to implement 'search' by passing queryParams through route from the search component to the userList component (example. /search-result?user="Alfred"). Before loading the userList component, i need to make an API call using the queryParams in the userList resolver but the query params keeps showing undefined.
Search Component
search(searchTerm: string) {
if (searchTerm) {
this.router.navigate(['search-result'], { queryParams: { user: searchTerm } });
}
}
UserList Resolver
export class UserResolver implements Resolve<User[]> {
constructor(private userService: UserService, private route: ActivatedRoute) { }
resolve(): Observable<User[]> {
const searchTerm: string = this.route.snapshot.queryParams['user'];
console.log(searchTerm); //Logs Undefined
return this.userService.getUsers(searchTerm);
}
}
On latest versions of Angular you can get the ActivatedRouteSnapshot on the resolver function.
export class UserResolver implements Resolve<User[]> {
constructor(private userService: UserService, private route: ActivatedRoute) { }
resolve(**route: ActivatedRouteSnapshot**): Observable<User[]> {
**console.log(route.queryParams)**
return this.userService.getUsers(searchTerm);
}
}
Maybe the resolve function is running before the queryParams are populated in the url. Try doing it in an Rxjs way.
import { filter, map, switchMap, tap } from 'rxjs/operators';
...
export class UserResolver implements Resolve<User[]> {
constructor(private userService: UserService, private route: ActivatedRoute) { }
resolve(): Observable<User[]> {
return this.route.queryParams.pipe(
tap(params => console.log(`Params: ${params}`)),
// wait until params has user in it
filter(params => !!params['user']),
tap(params => console.log('after filter')),
// extract the value of the user param
map(params => params['user']),
// switch to a new observable stream once we know the searchTerm
switchMap(searchTerm => this.userService.getUsers(searchTerm)),
);
}
}
Edit
Use the tap operator to debug the stream. See what the log is and make sure console.log(Params: ${params}) has the user params.
Edit2
Try
this.router.navigateByUrl(`/search-result?user=${searchTerm}`);
, I am thinking there is something wrong with how you navigate.
Edit 3
I am thinking queryParams can only be read when the component itself loads and not at the run time of the route resolvers because it is saying, I need to go to the route of search-result, give me the data before I go to search-result and it is independent of the queryParams. To fix this, I followed this guide (https://blog.thoughtram.io/angular/2016/10/10/resolving-route-data-in-angular-2.html).
1.) In app-routing-module.ts, change the registration of the path to:
{ path: 'search-result/:user', component: UserListComponent, resolve: { users: UserResolver } },
Now the user will be the parameter we are after in the URL.
2.) In search.component.ts, change search to:
search(searchTerm: string) {
if (searchTerm) {
this.router.navigate([`search-result/${searchTerm}`]);
}
}
3.) In user-resolver.service.ts, change it to this:
#Injectable({
providedIn: 'root'
})
export class UserResolver implements Resolve<User[]> {
constructor(private userService: UserService) { }
resolve(route: ActivatedRouteSnapshot): Observable<User[]> {
const searchTerm: string = route.paramMap.get('user');
return this.userService.getUsers(searchTerm);
}
}
I when console logging searchTerm, it is the accurate value. Thanks for providing the StackBlitz, it helped you and me.
<app-example [id]="requestId"></app-example>
We have add the selector in another component with passing the id.
export class exampleComponent implements OnInit {
#Input() id:number;
Id:string;
}
constructor(private fb: FormBuilder, private _AppService: AppService, private router: Router, private route: ActivatedRoute) {
this.router.getCurrentNavigation().extras.state != undefined ? this.Id = this.router.getCurrentNavigation().extras.state.key : '';
this.route.data.subscribe(data => {
this.current_path = data.urlname;
})
}
we've using the getCurrentNavigation() method,
but its return null value
Try something like this
constructor(private router: Router) {
router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
this.current_path = event.url;
}
})
I have an angular page which has a list of properties. Each property has a link to view the details of the property. I have a function which maps the property by id, however as a return I am always getting undefined (printed in console).
service.ts
getProperties(): Observable<IProperty[]>{
return this.http.get<IProperty>('http://localhost:3000/')
.do(data => this.properties.push(JSON.stringify(data)))
.catch(this.handleError);
}
getProperty(id:number): Observable<IProperty>{
return this.getProperties()
.map((properties: IProperty[])=> properties.find(p=>p.propertyId===id));
}
propertyDetail.component.ts
import { Component, OnInit } from '#angular/core';
import { IProperty } from './property';
import { ActivatedRoute, Router } from '#angular/router';
import { ApiService} from '../api/api.service';
import { PropertyGuardService } from './property-guard.service'
#Component
({
selector: 'propertyDetail',
templateUrl: './propertyDetail.component.html',
providers: [PropertyGuardService]
})
export class PropertyDetailComponent implements OnInit
{
pageTitle:string = "Property Details";
property: IProperty;
errorMessage: string ="";
constructor(private _route : ActivatedRoute,
private _router: Router,
private apiService: ApiService){
console.log(this._route.snapshot.paramMap.get('id'));
}
ngOnInit(){
const param = this._route.snapshot.paramMap.get('id');
if(param){
const id = +param;
this.getProperty(id);
console.log(this.getProperty(id));
}
}
getProperty(id:number)
{
this.apiService.getProperty(id).subscribe(
property => this.property = property,
error => this.errorMessage = <any>error);
}
onBack(): void
{
this._router.navigate(['/properties']);
}
}
You set one property using property => this.property = property by subscribe in the suitable time and now you can use this.property in the view like {{property?.id}}.
If you want to check Property whether being fetched properly or not on the console, you can use as follows:
getProperty(id:number){
this.apiService.getProperty(id).subscribe(
property => {
this.property = property,
console.log(property) // check property returned here
});
}
I plan to do such architecture:
component store
-- nested-component book
in store - i have an service call, which get data from service, and i do a subscription on result. Like it was described in angular2 docs (http).
And i want to use this data in nested components: in forms (formBuilder), in material-design elements etc.
Which way is the best, to do this? I'm new to angular2.
Store:
book: IBook;
constructor(private bookService: BookService) { }
ngOnInit() {
this.bookService.getBook('1')
.subscribe((book) => {
this.book = book;
});
}
BookService:
...
getBook (id): Observable<IBook> {
return this.http.get(this.url + '/' + id)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body || { };
}
...
Book:
#Input() book:IBook;
constructor() {}
ngOnInit() {
/*How here can i subscribe on book http data get?, so that i can use async value in forms etc?*/
});
Because, if i use async book everywhere (not formBuilder) - all is ok, but formBuilder is in need to update values, after data is loaded in parent component. How can i do this?
What about passing the bookID to the BookComponent and letting the BookComponent handle the async http get in ngInit?
export class Book implements OnInit {
#Input() bookID: number;
private book: IBook;
constructor(private bookService: BookService) {}
ngOnInit() {
this.bookService.getBook(this.bookID)
.subscribe((book) => {
this.book = book;
});
}
}
Otherwise you have a few options which are explained in https://angular.io/docs/ts/latest/cookbook/component-communication.html
I'll briefly highlight two ways which I think you could use.
Intercept input property changes with ngOnChanges
export class Book implements OnChanges {
#Input() book: IBook;
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
for (let propName in changes) {
// handle updates to book
}
}
}
more info https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html
Parent and children communicate via a service
#Injectable()
export class BookService {
books = new Subject<IBook>();
getBook(id): Observable<IBook> {
return this.http.get(this.url + '/' + id)
.map(d => {
let book = this.extractData(d);
this.books.next(book);
return book;
})
.catch(this.handleError);
}
...
}
#Component({
selector: 'book',
providers: []
})
export class Book implements OnDestroy {
book: IBook
subscription: Subscription;
constructor(private bookService: BookService) {
this.subscription = bookService.books.subscribe(
book => {
this.book = book;
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
#Component({
selector: 'store',
providers: [BookService]
})
export class Store {
book: IBook;
constructor(private bookService: BookService) { }
ngOnInit() {
this.bookService.getBook('1')
.subscribe((book) => {
this.book = book;
});
}
}