I am able to get the current logged in user object in the service.ts with this const loggedin = this.request.user
export class PostService {
constructor(
#Inject(REQUEST) private request: Request,
private userService: UserService
) { }
async GetPosts(){
const loggedin = this.request.user
loggedin.firstname;
}
}
But I cant access the properites of the current user
I tried loggedin.firstname but I got Property 'firstname' does not exist on type 'User'
How can I fix this?
I solve the issue,
export class PostService {
constructor(
#Inject(REQUEST) private request: any,
private userService: UserService
) { }
async GetPosts(){
const loggedin = this.request.user
}
}
I changed the request type to any and I destructure it like this
const { _id, firstname } = this.request.user
Related
I have a angular 8 application and a service, like this:
export class ProfileUserService {
user$ = this.authService.loginStatus().pipe(take(1));
constructor(private profileService: ProfileService, private authService: AuthService) {}
getProfile(): Observable<ProfileApi> {
return this.user$.pipe(mergeMap(({ profile }) => this.profileService.get(profile.participant)));
}
}
And I have a component where I use the service where I call the method, like this:
export class SettingsAccountComponent extends FormCanDeactivate implements OnInit, OnDestroy {
constructor(
private profileUserService: ProfileUserService){}
ngOnInit() {
this.innerWidth = window.innerWidth;
this.profileSubscription = this.profileUserService.getProfile().subscribe((profile: ProfileApi) => {
this.profile = profile;
this.deletePicture = false;
this.buildForm();
});
}
}
But I want to call directly in the component SettingsAccountComponent : this service:
private profileService: ProfileService
But the problem is this:
user$ = this.authService.loginStatus().pipe(take(1));
Because I need that for getting the participantId. But so my question is, how to combine the ProfileService, like this
this.profileSubscription = this.profileService.get().subscribe((profile: ProfileApi) => {
this.profile = profile;
this.deletePicture = false;
this.buildForm();
});
witht the:
user$ = this.authService.loginStatus().pipe(take(1));
because now in the get() method it expecs a ParticipantId
So what I have to change?
Thank you
I think a switchMap can help you.
Try:
import { switchMap } from 'rxjs/operators';
...
this.profileSubscription = this.profileService.user$.pipe(
switchMap(({ profile }) => this.profileService.get(profile.participant))
).subscribe((profile: profileAPI) => {
this.profile = profile;
this.deletePicture = false;
this.buildForm();
});
I see you've already done mergeMap in your service, switchMap is very similar.
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.
I'm new to Firebase, and I'm trying to implement authentication from an angular 7 application.
Here is my Authentication service:
#Injectable({
providedIn: 'root'
})
export class AuthService {
private user: Observable<firebase.User>;
private userDetails: firebase.User;
constructor(private angularFireAuth: AngularFireAuth) {
this.user = this.angularFireAuth.user;
this.user.subscribe(
(user) => {
if (user) {
this.userDetails = user;
}
else {
this.userDetails = null;
}
}
);
}
signInGoogleLogin() {
return this.angularFireAuth.auth.setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(() =>
this.angularFireAuth.auth.signInWithPopup(
new firebase.auth.GoogleAuthProvider()
)
);
}
isLoggedIn(): boolean {
return this.userDetails != null;
}
}
And here is my AuthGuard implementation:
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router, private authService: AuthService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
Observable<boolean> | Promise<boolean> | boolean {
if (this.authService.isLoggedIn()) {
return true;
}
this.router.navigate(['login'], { queryParams: { returnUrl: state.url}});
return false;
}
}
My problem is: the persistence does not seem to work. Whenever I refresh the page, I have to log in, whenever I'm navigating to another component that needs authentication, I need to log in again.
Of course, if I use "signInWithRedirect" instead of "signInWithPopup" I fall into a logging loop where I get redirected to my login page which finds that I'm not logged in, then try to log me, redirects me to my login page which finds I'm not logged in, and so on.
I think all these problems are actually related to the same problem: my auth state persistence implementation is somewhat wrong.
So my question is really simple: what am I doing wrong ? :)
I'd like to be able to log in, and then stay logged in when a refresh occurs.
Thank you for your help. :)
If anyone comes here looking for an answer this is how I did it
auth.service.ts
import { auth, firestore } from 'firebase/app';
constructor(
private _fAuth: AngularFireAuth,
) {}
public async login(authInfo: UserAuthInfo) {
if(authInfo.rememberMe) {
await this._fAuth.setPersistence(auth.Auth.Persistence.LOCAL)
console.log("local persistance", true);
}
const credential = await this._fAuth.signInWithEmailAndPassword(authInfo.username, authInfo.pass);
...
}
auth.guard.ts
export class AuthGuard implements CanActivate {
constructor(
private _fAuth: AngularFireAuth,
private _router: Router
) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> {
return this._authService.fAuth.authState.pipe(
first(),
map(user => !!user),
tap(authenticated => {
console.log("auth guard loggedin", authenticated);
authenticated || this._router.parseUrl('/auth/login')
})
)
}
}
I want to isolate http interactions by creating data access objects from a class so that in a component I might simply get data like this:
// dashboard.component
import { AppUser } from './appuser.service'
export class DashboardComponent implements OnInit {
user: AppUser = new AppUser();
constructor() { }
ngOnInit() {
let id = JSON.parse(window.localStorage.getItem('session')).userId;
this.user.find(id) // 'find' is from base class
.subscribe(
// handle user data
);
}
}
I have defined a base class and a sub class like this:
// base-resource.service
import { HttpClient } from '#angular/common/http';
...
export class BaseResource {
private fullpath: string;
protected http: HttpClient;
constructor (path: string) {
this.fullpath = path;
}
find (id): Observable<Object> {
return this.http.get(this.fullpath + '/' + id); // this line throws Error!
}
}
// app-user.service
...
export class AppUser extends BaseResource {
constructor(data?) {
super('api/appusers');
}
}
However this generates an error: ERROR TypeError: Cannot read property 'get' of undefined from within the base class function.
My 'AppUser' instance is clearly inheriting find from 'BaseResource', but find is picking up the 'AppUser' instance as the value of this and http is not available. I have tried declaring http as public and private as well as protected, but that had no effect. I imagine I'm missing some bigger picture of how to extend classes.
As specifically as possible, i think my question is in how to abstract functions to a base class when they need access to the base class's context.
(using Angular 6.0.4)
EDIT
I updated the title as it became clear that this is a problem of instantiating the HttpClient service in a class.
The error is because nothing is instantiating HttpClient, so it is undefined when you come to use it.
You should inject HttpClient into AppUser, and pass it into BaseResource via the constructor
export class AppUser extends BaseResource {
constructor(HttpClient http) {
super(http, 'api/appusers');
}
}
And in base-resource.service
import { HttpClient } from '#angular/common/http';
...
export class BaseResource {
private fullpath: string;
protected http: HttpClient;
constructor (httpClient: HttpClient, path: string) {
this.fullpath = path;
this.http = httpClient;
}
find (id): Observable<Object> {
return this.http.get(this.fullpath + '/' + id); // this line throws Error!
}
}
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