I am trying to extend some components with another class but I got
[Angular] Can't resolve all parameters for MyProjectsComponent in 'pathtomyproject'/src/app/my-projects/my-projects.component.ts: ([object Object], ?).
security.ts
import { Router} from '#angular/router';
export abstract class Security {
constructor(
protected router: Router
) { }
isLogged() {
if (!sessionStorage.getItem('user')) {
this.router.navigate(['/login']);
}
}
}
my-projects.component
import { Component, OnInit } from '#angular/core';
import { RouterModule, Router, ActivatedRoute } from '#angular/router';
import { ProjectService } from './project.service';
import { Security } from '../security';
#Component({
selector: 'app-my-projects',
templateUrl: './my-projects.component.html',
styleUrls: ['./my-projects.component.scss'],
providers: [ProjectService],
})
export class MyProjectsComponent extends Security implements OnInit {
projects: Array<any>;
constructor(
private projectService: ProjectService,
protected router
) {
super(router);
}
ngOnInit() {
this.getProjects();
}
async getProjects() {
const data: any = await this.projectService.getAll();
this.projects = data._embedded.projects;
}
delete(id) {
this.projectService.delete(id);
this.getProjects();
}
edit(id) {
const path = `/edit/${id}`;
this.router.navigate([path]);
}
}
There might be some issue in the constructor of the MyProjectsComponent. You misconfigured the dependency injection of the router. Change it to:
constructor(
private projectService: ProjectService,
protected router: Router // <-- DI for Router
) {
super(router);
}
and then it should work.
I tried to reproduce your issue in this stackblitz:
https://stackblitz.com/edit/angular-aifdew
Related
I have a problem where when I type manually localhost:4200/create it goes on the page where i want it to go, but when I click on a link to lead me there, I get an error saying:
TypeError: Cannot read property 'unsubscribe' of undefined
at PostListComponent.ngOnDestroy
Here's my code:
header.component.html
<mat-toolbar color="primary">
<span><a routerLink="/">My Messages</a></span>
<ul>
<li><a routerLink="/create">New Post</a></li>
</ul>
</mat-toolbar>
app-routing.module.ts:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { PostCreateComponent } from './posts/post-create/post-create.component';
import { PostListComponent } from './posts/post-list/post-list.component';
const routes: Routes = [
{path: '', component: PostListComponent},
{path: 'create', component: PostCreateComponent},
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
postlistcomponent.ts
import { Component, OnDestroy, OnInit } from '#angular/core';
import { Subscription } from 'rxjs';
import { Post } from '../posts';
import { PostsService } from '../posts.service';
#Component({
selector: 'app-post-list',
templateUrl: './post-list.component.html',
styleUrls: ['./post-list.component.css'],
})
export class PostListComponent implements OnInit, OnDestroy {
posts: Post[] = [];
private postsSub: Subscription;
constructor(public postsService: PostsService) {}
ngOnInit(): void {
this.postsService.getPosts();
this.postsService.getPostUpdateListener().subscribe((posts: Post[]) => {
this.posts = posts;
});
}
onDelete(postId: string) {
this.postsService.deletePost(postId);
}
ngOnDestroy() {
this.postsSub.unsubscribe();
}
}
Like the error says, you're calling unsubscribe on an object that doesn't exist in PostListComponent (postlist.component.ts?)
In that file, find the ngOnDestroy function and for any this.object$.unsubscribe() functions, test for the object first -
if (this.object$ && !this.object$.closed) {
this.object$.unsubscribe()
}
I'm using this.object$ as an example - your variable will be called something different
When you navigate from / to /create your ngOnDestroy in the PostListComponent is throwing an error.
This is why it is happening on the link and not when you put in the url.
As you can see in your ngInit you are not passing any value to your variable (postsSub). That is why you cannot destroy it.
Change this :
ngOnInit(): void {
this.postsService.getPosts();
this.postsService.getPostUpdateListener().subscribe((posts: Post[]) => {
this.posts = posts;
});
}
For this:
ngOnInit(): void {
this.postsService.getPosts();
this.postsSub = this.postsService.getPostUpdateListener().subscribe((posts: Post[]) => {
this.posts = posts;
});
}
That should work.
Regards
How to re-fetch data after parameter change from:
oglas/1 to oglas/2 by click, so when put URL and than click ENTER everything works, but when click on oglas/2 button when oglas/1 is rendered URL changes to oglas/2 but data is from oglas/1?
TS
import { Component, OnInit } from "#angular/core";
import { ActivatedRoute } from "#angular/router";
import { Post } from "../post.model";
import { ServerService } from "../server.service";
#Component({
selector: "post",
templateUrl: "./post.component.html",
styleUrls: ["./post.component.css"]
})
export class PostComponent implements OnInit {
post: Post[];
constructor(
private route: ActivatedRoute,
private serverService: ServerService
) {}
ngOnInit(): void {
this.getPost();
}
getPost(): void {
const id = +this.route.snapshot.paramMap.get("id");
this.serverService.getPosts(id).subscribe(post => (this.post = post));
}
}
Service
import { HttpClient } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { Post } from "./post.model";
import { User } from "./user.model";
import { Observable } from "rxjs";
#Injectable({ providedIn: "root" })
export class ServerService {
usersUrl = "http://localhost:3000/users";
postsUrl = "http://localhost:3000/posts";
constructor(private http: HttpClient) {}
getPosts(id: number | string): Observable<Post[]> {
const url = `${this.postsUrl}/${id}`;
return this.http.get<Post[]>(url);
}
getUser(id: number | string): Observable<User[]> {
const url = `${this.usersUrl}/${id}`;
return this.http.get<User[]>(url);
}
}
Since your are making an API call for data in ngOnInit(), requested data may not be available by the time your component loads. And Angular might be reusing the same instance of the component, making ngOnInit() to be called only once.
You can use Angular Resolvers to ensure that you have the required data before loading the component.
1) Create a route resolver to fetch the required data before loading the route.
PostDataResolver.ts:
// ... imports
#Injectable()
export class PostDataResolver implements Resolve<any> {
constructor(private serverService: ServerService) {}
resolve(route: ActivatedRouteSnapshot) {
const id = route.paramMap.get('id');
return this.serverService.getPosts(id);
}
}
2) Add this resolver to your routing module:
{ path: "oglas/:id", component: PostComponent, resolve: { postData: PostDataResolver }}
3) Then access the resolved data in your component.
PostComponent.ts:
export class PostComponent implements OnInit {
post: Post[];
constructor(
private route: ActivatedRoute,
private serverService: ServerService
) {}
ngOnInit(): void {
this.post = this.route.snapshot.data.postData;
}
}
This ensures that you have the latest and appropriate data before the component loads.
Got it...
import { Component, OnInit, OnChanges } from "#angular/core";
import { ActivatedRoute, Router } from "#angular/router";
import { Post } from "../post.model";
import { ServerService } from "../server.service";
#Component({
selector: "post",
templateUrl: "./post.component.html",
styleUrls: ["./post.component.css"]
})
export class PostComponent implements OnInit {
post: Post[];
id: number;
constructor(
private route: ActivatedRoute,
private serverService: ServerService
) {}
ngOnInit(): void {
this.route.paramMap.subscribe(params => {
this.id = parseInt(params.get("id"));
this.getPost(this.id);
});
}
getPost(id: number): void {
this.serverService.getPosts(id).subscribe(post => (this.post = post));
}
}
This code re-fetch data to a component
ngOnInit(): void {
this.route.paramMap.subscribe(params => {
this.id = parseInt(params.get("id"));
this.getPost(this.id);
});
}
Thank you all for your effort!
Hi i'm new in Angular 4 and I want to use it to build a WordPress theme using the wp-api. I start with the ng-wp-theme but I and all its working fine, but I need that hen a new post is publish the post list page updates itself without reload the page. I saw some tutorials about the http services in angular but I dont find any solution to this, maybe its a Wordpress api issue and not the Angular part.
here is the service:
import { Injectable } from '#angular/core';
import { HttpClient } from "#angular/common/http";
import { Observable } from 'rxjs/Observable';
import { Post } from './post';
import { environment } from '../../environments/environment';
#Injectable()
export class PostsService {
private _wpBase = environment.wpBase;
constructor(private http: HttpClient) { }
getPosts(): Observable<Post[]> {
return this.http.get<Post[]>(this._wpBase + 'posts');
}
getPost(slug: string): Observable<Post[]> {
return this.http.get<Post[]>(this._wpBase + `posts?slug=${slug}`);
}
}
and the controller:
import { Component, OnInit } from '#angular/core';
import { Post } from '../post';
import { PostsService } from '../posts.service';
import { Router } from '#angular/router';
import { HttpErrorResponse } from '#angular/common/http';
#Component({
selector: 'app-post-list',
templateUrl: './post-list.component.html',
styleUrls: ['./post-list.component.css'],
providers: [PostsService]
})
export class PostListComponent implements OnInit {
public posts: Post[];
constructor( private postsService: PostsService, private router: Router ) {}
ngOnInit() {
this.postsService.getPosts().subscribe(
(posts: Post[]) => this.posts = posts,
(err: HttpErrorResponse) => err.error instanceof Error ? console.log('An error occurred:', err.error.message) : console.log(`Backend returned code ${err.status}, body was: ${err.error}`));
}
selectPost(slug) {
this.router.navigate([slug]);
}
}
I want to show a snackbar when my login fails that says 'error connecting'. That much is simple. But then I would like it to try again either after 10 seconds when it is dismissed or after the action dismisses the snackbar. But my observable runs immediately and I am stuck in an infinite observable loop trying to login immediately after it has failed.
login.page.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { UserService, HelpersService, AuthService } from '../../services/';
#Component({
selector: 'login-page',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss']
})
export class LoginPage {
loginError: any;
constructor(
private router: Router,
private auth: AuthService,
public helpers: HelpersService,
) { }
login() {
this.auth.login().then((response) => {
this.router.navigate(['/']);
}).catch(error => {
this.loginError = this.helpers.notify('error connecting', 'try again', 10000);
this.helpers.notifyAction(this.loginError, this.login());
});
};
}
helpers.service.ts
import { Injectable } from '#angular/core';
import { MdSnackBar, MdSnackBarRef } from '#angular/material';
#Injectable()
export class HelpersService {
constructor(public snackBar: MdSnackBar) {}
notify(message: string, action: string, duration: number) {
return this.snackBar.open(message, action, {duration});
}
notifyAction(notification: MdSnackBarRef<any>, next) {
return notification.onAction().subscribe(() => next);
}
}
You were almost there. Please pay attention to my comments in your sources.
login.page.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { UserService, HelpersService, AuthService } from '../../services/';
#Component({
selector: 'login-page',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss']
})
export class LoginPage {
loginError: any;
constructor(
private router: Router,
private auth: AuthService,
public helpers: HelpersService,
) { }
login() {
this.auth.login().then((response) => {
this.router.navigate(['/']);
}).catch(error => {
this.loginError = this.helpers.notify('error connecting', 'try again', 10000);
this.helpers.notifyAction(this.loginError, this.login); // no parenthesis here!
});
};
}
helpers.service.ts
import { Injectable } from '#angular/core';
import { MdSnackBar, MdSnackBarRef } from '#angular/material';
#Injectable()
export class HelpersService {
constructor(public snackBar: MdSnackBar) {}
notify(message: string, action: string, duration: number) {
return this.snackBar.open(message, action, {duration});
}
notifyAction(notification: MdSnackBarRef<any>, next) {
return notification.onAction().subscribe(() => next()); // they are here!
}
}
Live Example Infinity Login
You need to pass function instead of calling it. And also take care about context by using arrow function or bind.
login.page.ts
this.helpers.notifyAction(this.loginError, () => this.login());
helpers.service.ts
notifyAction(notification: MdSnackBarRef<any>, next) {
notification.afterDismissed().subscribe(next);
return notification.onAction().subscribe(notification.dismiss);
}
I have a simple method that at the end of it I want to redirect to another component:
export class AddDisplay{
display: any;
addPairTo(name: string, pairTo: string){
this.display = {};
this.display.name = name;
this.display.pairTo = pairTo;
}
}
What I wanna do is at the end of the method redirect to another component:
export class AddDisplay{
display: any;
addPairTo(name: string, pairTo: string){
this.display = {};
this.display.name = name;
this.display.pairTo = pairTo;
this.redirectTo('foo');
}
}
How do I achieve this in Angular 2?
first configure routing
import {RouteConfig, Router, ROUTER_DIRECTIVES} from 'angular2/router';
and
#RouteConfig([
{ path: '/addDisplay', component: AddDisplay, as: 'addDisplay' },
{ path: '/<secondComponent>', component: '<secondComponentName>', as: 'secondComponentAs' },
])
then in your component import and then inject Router
import {Router} from 'angular2/router'
export class AddDisplay {
constructor(private router: Router)
}
the last thing you have to do is to call
this.router.navigateByUrl('<pathDefinedInRouteConfig>');
or
this.router.navigate(['<aliasInRouteConfig>']);
#kit's answer is okay, but remember to add ROUTER_PROVIDERS to providers in the component. Then you can redirect to another page within ngOnInit method:
import {Component, OnInit} from 'angular2/core';
import {Router, ROUTER_PROVIDERS} from 'angular2/router'
#Component({
selector: 'loginForm',
templateUrl: 'login.html',
providers: [ROUTER_PROVIDERS]
})
export class LoginComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit() {
this.router.navigate(['./SomewhereElse']);
}
}
This worked for me Angular cli 6.x:
import {Router} from '#angular/router';
constructor(private artistService: ArtistService, private router: Router) { }
selectRow(id: number): void{
this.router.navigate([`./artist-detail/${id}`]);
}
callLog(){
this.http.get('http://localhost:3000/getstudent/'+this.login.email+'/'+this.login.password)
.subscribe(data => {
this.getstud=data as string[];
if(this.getstud.length!==0) {
console.log(data)
this.route.navigate(['home']);// used for routing after importing Router
}
});
}