Currently logged in user won’t display on the navbar until I manually refresh the browser - html

The last previous account name is displayed. It's only when I refresh the browser the displayed name changes to the current logged in account.
below is the Auth service.
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { environment } from 'src/environments/environment';
import { map } from 'rxjs/operators';
import { DefaultUrlSerializer } from '#angular/router';
import { JwtHelperService } from '#auth0/angular-jwt';
import { Observable } from 'rxjs';
import { yearsPerPage } from '#angular/material/datepicker';
#Injectable({
providedIn: 'root'
})
export class AuthService {
baseUrl = environment.apiUrl + 'auth/';
decodedToken: any;
jwtHelper = new JwtHelperService();
constructor(private http: HttpClient) { }
login(model: any) {
return this.http.post(this.baseUrl + 'login', model)
.pipe(
map((response: any) => {
const user = response;
if (user) {
localStorage.setItem('token', user.token);
localStorage.setItem('user', JSON.stringify(user.user));
this.decodedToken = this.jwtHelper.decodeToken(user.token);
localStorage.setItem('role', JSON.stringify(this.decodedToken.role));
}
})
);
}
register(model: any) {
return this.http.post(this.baseUrl + 'register', model, { responseType: 'text' });
}
loggedIn() {
const token = localStorage.getItem('token');
return !this.jwtHelper.isTokenExpired(token);
window.location.reload();
}
role() {
return localStorage.getItem('role');
}
}
I’m getting the logged in details from the local storage and storing the details into a variable called userDisplayName in the navbar component. As you can see below the code is in ngONInit method.
“this.userDisplayName = JSON.parse (localStorage.getItem('user'));”
import { AddTaskComponent } from './../addTask/addTask.component';
import { AuthService } from './../_services/auth.service';
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { MatDialog } from '#angular/material/dialog';
import { UpdateTaskComponent } from '../updateTask/updateTask.component';
import { Router } from '#angular/router';
import { UserMemberService } from '../_services/userMember.service';
import { StateStorageService } from '../_services/stateStorage.service';
#Component({
selector: 'app-navigation-bar',
templateUrl: './navigationBar.component.html',
styleUrls: ['./navigationBar.component.css']
})
export class NavigationBarComponent implements OnInit {
model: any = {};
loginReactiveForm: FormGroup;
role;
users: any[];
userAuthorised: boolean;
searchTask: FormControl;
Username: string;
userDisplayName;
constructor(
private authService: AuthService,
public dialog: MatDialog,
private router: Router,
private userMemberService: UserMemberService,
private stateStorageService: StateStorageService) { }
ngOnInit() {
this.initForm();
this.isUserAdmin();
// this.userDisplayName = this.authService.login(this.model);
this.userDisplayName = JSON.parse (localStorage.getItem('user'));
console.log(this.role);
}
login() {
this.model.username = this.loginReactiveForm.value.username;
this.model.password = this.loginReactiveForm.value.password;
this.authService.login(this.model).subscribe(next => {
this.loadUsers();
this.router.navigateByUrl('/CalendarView');
this.isUserAdmin();
}, error => {
console.log('failed to login');
});
}
isUserAdmin() {
// get users role
this.role = JSON.parse(localStorage.getItem('role'));
console.log('this is role = ' + this.role);
// if user is not an Admin
if (this.role !== 'Admin') {
this.userAuthorised = false;
console.log('value of auth is = ' + this.userAuthorised );
} // if user is an Admin
else {
// list of users for the drop down
this.userAuthorised = true;
console.log('value of auth is = ' + this.userAuthorised );
}
}
loadUsers() {
this.userMemberService.getUsers().subscribe((data) => {
this.users = data;
this.stateStorageService.setUserMemberStorage(this.users);
}, error => {
console.log(error);
});
}
initForm() {
this.loginReactiveForm = new FormGroup({
username: new FormControl(),
password: new FormControl()
});
this.searchTask = new FormControl();
}
// has the user logged in
loggedIn() {
return this.authService.loggedIn();
}
loggedOut() {
const token = localStorage.removeItem('token');
const username = localStorage.removeItem('user');
const userId = localStorage.removeItem('role');
localStorage.removeItem('user');
}
}
Below is the html
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<ul *ngIf="!loggedIn()" class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link">
<span class="sr-only"></span></a>
</li>
</ul>
<form *ngIf="!loggedIn()" class="form-inline my-2 my-lg-0" [formGroup]="loginReactiveForm"
(ngSubmit)="login()">
<input formControlName="username" class="form-control mr-sm-2"
type="text" placeholder="Username" aria-label="username">
<input formControlName="password" class="form-control mr-sm-2"
type="password" placeholder="Password" autocomplete="off" aria-label="password">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Login</button>
</form>
<div *ngIf="loggedIn()" class="username" style="position:relative; left:70%; color: white ;" >Username: {{userDisplayName.username}}</div>
<div style="position:relative; left:85%">
<button *ngIf="loggedIn()" class="btn btn-outline-success float-right"
type="submit" (click)="loggedOut()" [routerLink]="['/login']">Log Out</button>
</div>
</nav>
Why is is that the loggedin user is only displayed once the browser has been refreshed?
I'm currently logged in as “Matt Briggs” but it shows “Sallyjones” on the navbar in the image.
Link to the image is here

Problem
The problem in your code is that you only set userDisplayName once in ngOnInit. NgOnInit is only called once when the component is initialised. So this is why you need to refresh to see the new user from localstorage.
There's no other place where you change or update userDisplayName...
Solution
I think your code could use a little refactoring to make it work like you expect. You're putting to much logic in your component code.
Save your decodedToken in a currentUser subject which is exposed as an observable ==> By doing this, you can subscribe to this observabel in your component's ngOnInit function. This way every change will be shown in your component too.
This is a tutorial which gives a complete overview of how you can implement authentication in Angular. Give it a good read and try this out in your code.
https://jasonwatmore.com/post/2020/07/09/angular-10-jwt-authentication-example-tutorial#authentication-service-ts

this sounds like a change detection problem. Can you use a Subject to store the userDisplayName?
e.g.
export class NavigationBarComponent implements OnInit {
...
userDisplayName = new Subject<{username: string}>;
...
const _u = JSON.parse(localStorage.getItem('user'));
this.userDisplayName.next(_u);
then in your template
<div *ngIf="loggedIn()"
class="username"
style="position:relative; left:70%; color: white ;" >
Username: {{(userDisplayName | aasync)?.username}}
</div>
Using a subject will cause ng to redraw the ui when the value of userDisplayName changes.
I am guessing that ng is drawing the dom on init, when there is an old value in userDisplayName and doesn't know the value has changed. Using a subscribable will fix that.

you can directly call it from your server to html page
get loggedInUser(): any {
const uname = localStorage.getItem('uname');
return uname;
}
In your html page
<li><a *ngIf="auth.isLoggedIncheck"><span class="glyphicon glyphicon-log-in"></span> Welcome{{auth.loggedInUser| uppercase}} </a> </li>

Related

My codes are not doing get,set,post so what is my codes error how can i fix it?

these are my .ts codes i write these becasue i want to get product details and delete
import { Component, OnInit } from '#angular/core';
import {FormGroup,FormBuilder, FormControl, Validators} from "#angular/forms"
import { ToastrService } from 'ngx-toastr';
import { Product } from 'src/app/models/product';
import { ProductService } from 'src/app/services/product.service';
import { LocalStorageService } from 'src/app/services/local-storage.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-product-delete',
templateUrl: './product-delete.component.html',
styleUrls: ['./product-delete.component.css']
})
export class ProductDeleteComponent implements OnInit {
products: Product[] = [];
dataLoaded = false;
deleteProductForm:FormGroup;
product :Product
productId :number;
constructor(private formBuilder:FormBuilder,
private productService:ProductService
, private toastrService:ToastrService
,private router:Router,
private localStorageService:LocalStorageService) { }
ngOnInit(): void {
this.createdeleteProductForm();
}
createdeleteProductForm(){
this.deleteProductForm = this.formBuilder.group({
productId:["", Validators.required],
})
}
getbyid() {
Number(localStorage)
Number(this.productService)
this.productService.getbyid(Number(localStorage.getItem("productId"))).subscribe(
(response) => {
this.products = response.data;
this.dataLoaded = true;
this.deleteProductForm.setValue({
productId: this.product,
categoryId: this.product.categoryId,
productName: this.product.productName,
unitPrice: this.product.unitPrice
});
},
(responseError) => {
this.toastrService.error(responseError.error);
}
)
}
deleteProduct() {
if (this.deleteProductForm.valid) {
let productModel = Object.assign({}, this.deleteProductForm.value);
productModel.productId=parseInt(productModel.productId);
this.productService.delete(productModel).subscribe(
(response) => {
this.toastrService.success('Lütfen tekrar giriş yapınız');
this.router.navigate(['/login']);
},
(responseError) => {
this.toastrService.error(responseError.error);
}
);
} else {
this.toastrService.error('Bir hata oluştu.');
}
}
}
these are my html codes i trying to do when user sign in a productId after that click the button delete the product in that ıd
<div class="card">
<div class="card-header"><h5 class="title">Ürün Sil</h5></div>
<div class="card-body">
<form [formGroup]="deleteProductForm">
<div class="mb-3">
<label for="productId">ÜrünId'si</label>
<div class="form-group">
<input type="number"
id="productId"
formControlName="productId" class="form-control"
placeholder="productId"/>
</div>
<div class="card-footer" style="background-color: rgb(4, 62, 255)">
<button
class="btn btn-lg btn-outline-success float-end"
(click)="deleteProduct()"
>
Sils
</button>
</div>
and these are my service
delete(product:Product):Observable<ResponseModel>{
let newPath = this.apiUrl + 'products/delete';
return this.httpClient.post<ResponseModel>(newPath, product );
}
getbyid(productId:number) : Observable<ListResponseModel<Product>> {
let newPath = this.apiUrl + 'products/getbyid?productId=' + productId;
return this.httpClient.get<ListResponseModel<Product>>(newPath);
}
what i'm going for is that when the user goes on a productId click the button, I want to delete the data including the Id first, but what's the null time on main at the moment?
note:Value cannot be null. says back-end
in html POST https://localhost:44314/api/products/delete
[HTTP/2 500 Internal Server Error 9591ms gives this error
First of all, have you checked the value of product in the call of delete ?
Also, maybe it's the httpClient.delete you need since it's the best way to delete an object to the back end. I suggest this:
https://angular.io/guide/http#making-a-delete-request

#viewChild and #ViewChildern gives undefined

I'm working on Angular 9 and want to access an input field after clicking on a button. right now it gives me undefined. I have tried #ViewChild and #viewChildern because I'm using ngIf.
Template.html file
<div class="search-input" #searchDiv *ngIf="serachActive">
<input
#searched
autofocus
type="text"
class="serach-term"
placeholder="Search"
[(ngModel)]="searchTerms"
(ngModelChange)="applySearch()"
/>
<button (click)="toggleSearch(!serachActive)">
<span class="material-icons"> search </span>
</button>
<ul class="search-list">
<li *ngFor="let result of results">
<a [routerLink]="['/', 'video', 'details', result._id]">{{
result.title ? result.title : ''
}}</a>
</li>
</ul>
</div>
Template.ts file
import { Component, OnInit,AfterViewInit,ElementRef,ViewChild,ViewChildren } from '#angular/core';
import { UserService } from '../../../user.service';
import { VideoService } from '../../../services/video.service';
import { Subject } from 'rxjs';
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';
import { Router } from '#angular/router';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit,AfterViewInit{
serachActive: boolean = false;
#ViewChildren('searched') searchElement: ElementRef;
#ViewChildren("searched") input: ElementRef;
user;
subject = new Subject<string>();
results = [];
searchTerms;
loggedIn: Boolean = false;
constructor(
private userService: UserService,
private videoService: VideoService,
private router: Router
) {
this.user = this.userService.getUser();
this.loggedIn = this.userService.isAuthenticated();
}
ngOnInit() {
console.log('on init', this.input); //undefined
this.subject
.pipe(debounceTime(400), distinctUntilChanged())
.subscribe((value) => {
this.router.navigate(['search'], { queryParams: { term: value } });
});
}
ngAfterViewInit() {
console.log('on after', this.input); //undefined
}
toggleSearch(toggledata) {
this.serachActive = toggledata;
this.results = [];
this.searchTerms = '';
console.log(this.input) //undefined
console.log(this.searchElement.nativeElement) //undefined
}
applySearch() {
const searchText = this.searchTerms;
this.subject.next(searchText);
this.searchElement.nativeElement.focus(); //undefined
}
menuButtonClick(button){
if(button === "history"){
this.router.navigate(['history'])
}
}
}
Use ViewChild since you're only searching for 1 element ID.
If adding { static: true } or { static: false } in your ViewChild options doesn't work as what is stipulated on Angular Static Query Migration Documentation
Use ChangeDetectorRef instead:
#Component({...})
export class AppComponent {
#ViewChild('searchInput') input: ElementRef;
isShow: boolean = false;
constructor(private cdr: ChangeDetectorRef) {}
toggle(): void {
this.isShow = !this.isShow;
this.cdr.detectChanges(); // Detects changes which this.isShow is responsible on showing / hiding
// the element you're referencing to in ViewChild
if (this.isShow) // If element is shown, console the referenced element
console.log(this.input);
}
}
Have created a Stackblitz Demo for your reference

How can I show data in an Angular component in Angular 10?

I'm starting with Angular 10 and I want to put the current user in the profile.component.html and the navbar in app.component.html. Here is the code.
users.ts
export interface User {
username : string
password: string
edad: number
fechaNacimiento: string
createdAt?: string
updatedAt?: string
id?:number
}
login.component.ts
import { Component, OnInit } from '#angular/core';
import { NgForm } from '#angular/forms';
import { ActivatedRoute, Router } from '#angular/router';
import { UsersService } from 'src/app/services/users.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(
public usersServices: UsersService,
private router: Router
) { }
ngOnInit(): void {
}
login(form: NgForm){
this.usersServices.login(form.value).subscribe(
res => {
console.log(res);
localStorage.setItem('token',res['token']);
this.router.navigate(['/profile',form.controls['username'].value],{
state:{username:form.controls['username']}
});
},
err => {
console.log(err)
}
)
}
}
profile.component.ts
import { Component, OnInit } from '#angular/core';
import { UsersService } from '../../services/users.service';
import { NgForm } from '#angular/forms';
import { User } from 'src/app/models/users';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
constructor(public usersService: UsersService,private route: ActivatedRoute) {
this.route.params.subscribe(username => {
console.log(username);
})
}
ngOnInit(): void {
this.getUsers();
}
getUsers(){
this.usersService.getUsers().subscribe(
res => {
this.usersService.user = res
},
err => console.log(err)
)
}
deleteUser(id:number){
if(confirm('Are you sure you want to delete it?')){
this.usersService.deleteUser(id).subscribe(
(res) => {
this.getUsers();
},
(err) => console.log(err)
);
}
}
updateUser(form: NgForm){
this.usersService.editUser(form.value).subscribe(
res => console.log(res),
err => console.log(err)
);
}
}
<div class="col-md-8">
<table class="table table-striped">
<thead>
<tr>
<th>Username</th>
<th>Age</th>
<th>Birthdate</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of usersService.user">
<td>{{user.username}}</td>
<td>{{user.edad}}</td>
<td>{{user.fechaNacimiento}}</td>
<td>
<button class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#staticBackdrop">
<i class="material-icons">edit</i>
</button>
<button class="btn btn-danger btn-sm" (click)="deleteUser(user.id)">
<i class="material-icons">delete</i>
</button>
</td>
</tbody>
</table>
</div>
app.component.html
<nav class="navbar navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="#">MEAN Users</a>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" routerLink="/profile" routerLinkActive = "active">Profile</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
<ng-container *ngIf="!usersService.loggedIn(); else loggedIn">
<li class="nav-item">
<a class="nav-link" routerLink="/register" routerLinkActive = "active">Signup</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/login" routerLinkActive = "active">Signin</a>
</li>
</ng-container>
<ng-template #loggedIn>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" style="cursor: pointer;"></a>
<div class="dropdown-menu">
<a class="dropdown-item" (click)="usersService.logout()">Logout</a>
</div>
</li>
</ng-template>
</ul>
</div>
</nav>
<div class="container p-5">
<router-outlet></router-outlet>
</div>
I want to put a single user in the navbar from app.component.html and profile.component.html but i don't know how to do it.
Beforehand thank you very much.
The problem is not much clear to me, but I think this may help you.
It is better to create an authentication service. The authentication service is used to login & log out, it notifies other components when the user logs in & out, and allows access the currently logged in user.
RxJS Subjects and Observables are used to store the current user object and notify other components when the user logs in and out of the app. Angular components can subscribe() to the public currentUser: Observable property to be notified of changes, and notifications are sent when the this.currentUserSubject.next() method is called in the login() and logout() methods, passing the argument to each subscriber.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { User } from '#app/_models';
#Injectable({ providedIn: 'root' })
export class AuthenticationService {
private currentUserSubject: BehaviorSubject<User>;
public currentUser: Observable<User>;
apiUrl: string;
constructor(private http: HttpClient) {
this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));
this.currentUser = this.currentUserSubject.asObservable();
}
public get currentUserValue(): User {
return this.currentUserSubject.value;
}
login(username: string, password: string) {
return this.http.post<any>(`${this.apiUrl}/users/authenticate`, { username, password })
.pipe(map(user => {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
return user;
}));
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
this.currentUserSubject.next(null);
}
}
you can use the current user like this
currentUser: User;
constructor(
private authenticationService: AuthenticationService
) {
this.authenticationService.currentUser.subscribe(x => this.currentUser = x);
}
if the current user is undefined, you can navigate to again login page. if not you can display the current user.

Trying to implement a checkbox complete into To Do List

Trying to implement a checkbox complete to my To Do List but unsure why it is not working.
Whenever my code compiles down to Javascript I get this error:
" ERROR in src/app/ToDo/todo.component.ts(89,32): error TS2339: Property 'item' does not exist on type 'ToDoComponent'. "
Also i'm unsure why my IDE is saying the task is considered an any statement.
UPDATE:
My console in my browser is displaying this error:
Unexpected closing tag "li". It may happen when the tag has already been closed by another tag.
TypeScript:
import { Component, OnInit, EventEmitter, Output } from '#angular/core';
import { ToDo, IToDo } from './todo.model';
import { HttpClient } from '#angular/common/http';
import { LocalStorageService } from '../localStorageService';
import { ActivatedRoute, Router } from '#angular/router';
import { IUser } from '../login/login.component';
import { ToastService } from '../toast/toast.service';
#Component({
// tslint:disable-next-line: component-selector
selector: 'todolist',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class ToDoComponent implements OnInit {
[x: string]: any;
todos: Array<IToDo> = [];
inputtask = "";
toDoParams = '';
localStorageService: LocalStorageService<IToDo>;
currentUser: IUser;
#Output() update: EventEmitter<any> = new EventEmitter();
constructor(
private http: HttpClient,
private activatedRoute: ActivatedRoute,
private router: Router) {
this.localStorageService = new LocalStorageService('todos');
}
private toastService: ToastService;
async ngOnInit() {
const currentUser = this.localStorageService.getItemsFromLocalStorage('user');
console.log('from todos component', currentUser);
if (currentUser == null) {
await this.router.navigate(['login']);
} else {
// if user is logged in go and find any items from local storage and bind
// to the view
const toDoItems = this.localStorageService.getItemsFromLocalStorage('todos');
if (toDoItems && Array.isArray(toDoItems)) {
this.todos = toDoItems;
}
}
}
addToDo(todo: string, cm?: boolean) {
const td = {
id: null,
task: todo,
completed: cm,
}
if (todo === '') {
alert('You must enter in a task TO DO!')
} else {
this.todos.push(td);
}
this.saveItemsToLocalStorage(this.todos);
}
delete(index: number) {
this.todos.splice(index, 1);
console.log("index", index);
this.saveItemsToLocalStorage(this.todos);
}
clear() {
this.todos = [];
console.log('index', this.todos)
this.saveItemsToLocalStorage(this.todos);
}
getItemsFromLocalStorage(key: string) {
const savedToDo = JSON.parse(localStorage.getItem(key));
console.log('from getItemsFromLocalStorage savedItems', savedToDo);
return this.localStorageService.getItemsFromLocalStorage(key);
return savedToDo;
}
completeItem() {
this.update.emit({
task: this.todos,
changes: {completed: this.task.completed}
});
}
saveItemsToLocalStorage(todos: Array<IToDo>) {
todos = this.sortByID(todos);
return this.localStorageService.saveItemsToLocalStorage(todos);
const savedToDo = localStorage.setItem('todos', JSON.stringify(todos));
console.log('from saveItemsToLocalStorage savedToDos: ', savedToDo);
return savedToDo;
}
sortByID(todos: Array<IToDo>) {
todos.sort((prevToDo: IToDo, presToDo: IToDo) => {
return prevToDo.id > presToDo.id ? 1 : -1;
});
console.log('the sorted ToDos', this.todos);
return this.todos;
}
logout() {
// clear localStorage
this.localStorageService.clearItemFromLocalStorage('user');
// navigate to login page
this.router.navigate(['']);
}
}
HTML Code:
<ul class="list-group">
<li *ngFor="let todo of todos; let i = index"
class="list-group-item shadow p-3 mb-5 bg-white rounded border border-dark rounded" id="myTask">
<div class="todo-item">
{{todo.task}} <button type="button" class="btn btn-danger" (click)="delete()">X</button>
<input type="checkbox" class="todo-checkbox" (click)="completeItem()">
<span class="todo-title" [ngClass]="{'todo-complete': item.completed}">
</li>
</ul>
<span class="todo-title" [ngClass]="{'todo-complete': item.completed}">
Here you are using item which doesn't exist in your typescript file. Did you mean to use todo from your *ngFor ?

My PUT method isn't working in angular even though it works in spring

I have a webpage that displays a logged in user information which is called from database using a spring REST API. Next to each user property there's an edit button when clicked displays an input field which the user can use to edit that property (I've only added it the password field so far).
For some reason after I click on the button and edit the property nothing happens even though it's supposed to display 'works' in the console.
Here's the spring controller method that handles the update:
#PutMapping("myProfile/edit")
public ResponseEntity<Object> updateProfile(#CurrentUser User currentUser, #RequestBody EditUserProfileRequest user){
User updatedUser = userService.updateProfile(currentUser, user);
return ResponseEntity.ok().body("Update Success!");
}
Here's the service method:
#Override
public User updateProfile(User currentUser, EditUserProfileRequest input) {
User user = this.getUserByUsername(currentUser.getUsername());
user.setEditedProfile(input);
if(input.getPassword()!=null){
user.setPassword(passwordEncoder.encode(input.getPassword()));
}
User saveMe = userRepository.save(user);
return saveMe;
}
The EditUserProfileRequest class:
package com.example.demo.contract;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#AllArgsConstructor
#NoArgsConstructor
#Data
public class EditUserProfileRequest {
private String firstName;
private String lastName;
private String password;
private String email;
private String location;
private String bio;
private Long phoneNumber;
private Long zipCode;
}
Here's the html code for the password field which would display the normal password first then change to input fields after clicking on the edit button:
<div style="margin-top: 3px; margin-bottom: 3px;">
<h5 style="float: left; margin-left: 160px; margin-top: 18px;">
<b>Password: </b>
</h5>
<div id="hashPassword" style="display: block">
<div style="width: 100px; margin-left: 233px; float: left;">
<span style="font-weight: 600">*********</span>
</div>
<mat-icon id="hashPassword" aria-label="EDIT" aria-hidden="false" (click)="editPassword()" style="cursor: pointer; margin-left: 446px">edit</mat-icon>
</div>
<div id="editPassword" style="display: none">
<div style="width: 800px; margin-left: 233px; float: left;">
<form [formGroup]="passwordEditForm" (ngSubmit)="onPasswordSubmit()">
<div class="form-group">
<label>Password</label>
<input type="password" formControlName="password" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.password.errors }" />
<div *ngIf="submitted && f.password.errors" class="invalid-feedback">
<div *ngIf="f.password.errors.required">Password is required</div>
<div *ngIf="f.password.errors.minlength">Password must be at least 4 characters</div>
</div>
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" formControlName="confirmPassword" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.confirmPassword.errors }" />
<div *ngIf="submitted && f.confirmPassword.errors" class="invalid-feedback">
<div *ngIf="f.confirmPassword.errors.required">Confirm Password is required</div>
<div *ngIf="f.confirmPassword.errors.mustMatch">Passwords must match</div>
</div>
</div>
<div class="form-group">
<button type="button" class="btn btn-primary">Confirm Edit</button>
</div>
</form>
</div>
</div>
</div>
Here's my my component that handles the calls the edit function:
import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '#angular/core';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
import { MediaMatcher } from '#angular/cdk/layout';
import { Router } from '#angular/router';
import { DomSanitizer } from '#angular/platform-browser';
import { Observable } from 'rxjs';
import { HttpHeaders, HttpClient } from '#angular/common/http';
import { MustMatch } from '../must-match.validators';
import { UserService } from '../user.service';
#Component({
selector: 'app-myacc',
templateUrl: './myacc.component.html',
styleUrls: ['./myacc.component.scss']
})
export class MyaccComponent implements OnInit {
loginUser: any = {};
imgSrc: any;
submitted = false;
passwordEditForm: FormGroup;
constructor(private router: Router,
private sanitizer: DomSanitizer,
private http: HttpClient,
private fb: FormBuilder,
private service: UserService) {
}
ngOnInit() {
console.log(window.URL);
this.loginUser = JSON.parse(localStorage.getItem('currentUser'));
console.log(this.loginUser);
this.passwordEditForm = this.fb.group({
password: ['', [Validators.required, Validators.minLength(4)]],
confirmPassword: ['', Validators.required]
}, {
validator: MustMatch('password', 'confirmPassword')
});
}
editPassword() {
document.getElementById('hashPassword').style.display = 'none';
document.getElementById('editPassword').style.display = 'block';
}
get f() {
return this.passwordEditForm.controls;
}
onPasswordSubmit() {
this.submitted = true;
if (this.passwordEditForm.invalid) {
return;
} else {
this.service.editUser(this.passwordEditForm.value, this.loginUser.token).subscribe(res => {
console.log('works');
}, err => {
console.log(err);
});
}
}
}
And finally the User service that has the edit method:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private http: HttpClient) {
this.http = http;
}
getAllUsers(token: any): Observable<any> {
// tslint:disable-next-line: object-literal-key-quotes
const headers = new HttpHeaders({'Authorization': 'Bearer ' + token});
return this.http.get('http://localhost:8082/users', {headers: headers});
}
getUser(token: any): Observable<any> {
// tslint:disable-next-line: object-literal-key-quotes
const headers = new HttpHeaders({'Authorization': 'Bearer ' + token});
return this.http.get('http://localhost:8082/getuser', {headers: headers});
}
getAllOffer(): Observable<any> {
return this.http.get('http://localhost:8082/getAllOffer');
}
getServices(): Observable<any> {
return this.http.get('http://localhost:8082/services');
}
editUser(user, token): Observable<any> {
const headers = new HttpHeaders({'Authorization': 'Bearer ' + token});
return this.http.put('http://localhost:8082/myProfile/edit', user, token);
}
}
The third argument of HttpClient.put() should be an options object. Update your editUser method so that you are passing an object containing your headers as the third argument instead of token:
editUser(user, token): Observable<any> {
const headers = new HttpHeaders({'Authorization': 'Bearer ' + token});
return this.http.put('http://localhost:8082/myProfile/edit', user, { headers });
}
Hopefully that helps!