So i am currently working on a web application that i can add user which has name last name age born date and a picture .And after i create a user i can delete and edit it . My problem is when i create a user and then after i try to edit it and replace the picture of the user and then save it it creates a new user with the same info but with the picture i tried to change on the first place.
here is the stackblitz link to it : https://stackblitz.com/~/github.com/simeonskiq/Angular-project
edit-user.component.ts :
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { UserService } from '../user.service';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
declare var bootstrap: any;
@Component({
selector: 'app-edit-user',
templateUrl: './edit-user.component.html',
styleUrls: ['./edit-user.component.css']
})
export class EditUserComponent implements OnInit {
userForm: FormGroup;
userId!: string;
notificationMessage: string = '';
private confirmModalInstance: any;
photoUrl?: string | ArrayBuffer | null = '';
constructor(
private fb: FormBuilder,
private userService: UserService,
private route: ActivatedRoute,
private router: Router
) {
this.userForm = this.fb.group({
id: [''],
firstName: ['', [Validators.required, this.noNumbers]],
lastName: ['', [Validators.required, this.noNumbers]],
occupation: ['', [Validators.required, this.noNumbers]],
gender: ['', Validators.required],
dateOfBirth: ['', Validators.required],
photo: ['']
});
}
noNumbers = (control: any): { [key: string]: boolean } | null => {
if (control.value && /\d/.test(control.value)) {
return { 'containsNumber': true };
}
return null;
}
ngOnInit(): void {
this.userId = this.route.snapshot.params['id'];
this.userService.getUser(Number(this.userId)).subscribe(user => {
if (user) {
this.userForm.patchValue(user);
this.photoUrl = user.photo;
}
});
const modalElement = document.getElementById('confirmSaveUserModal');
if (modalElement) {
this.confirmModalInstance = new bootstrap.Modal(modalElement);
}
}
showNotification(message: string): void {
this.notificationMessage = '';
setTimeout(() => {
this.notificationMessage = message;
}, 0);
}
handleSave(event: Event): void {
event.preventDefault();
if (this.userForm.invalid || this.hasErrors()) {
this.showNotification('Please ensure all fields are correctly filled and do not contain numbers.');
} else {
this.showConfirmationModal();
}
}
hasErrors(): boolean {
const controls = this.userForm.controls;
return Object.keys(controls).some(key => controls[key].hasError('containsNumber'));
}
showConfirmationModal(): void {
if (this.confirmModalInstance) {
this.confirmModalInstance.show();
}
}
confirmSaveUser(): void {
if (this.userForm.valid) {
const updatedUser = { ...this.userForm.value };
updatedUser.id = this.userId; // Explicitly assign the ID to avoid duplications
this.userService.updateUser(updatedUser).subscribe(() => {
this.confirmModalInstance.hide();
this.router.navigate(['/home']);
}, (error) => {
console.error('Error updating user:', error);
});
}
}
cancel(): void {
this.router.navigate(['/home']);
}
onFileChange(event: any): void {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
this.photoUrl = reader.result as string; // Ensure it's a string
this.userForm.patchValue({ photo: this.photoUrl });
};
reader.readAsDataURL(file);
}
}
}
user.service.ts :
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { User } from './user.model';
@Injectable({
providedIn: 'root'
})
export class UserService {
private users: User[] = [];
constructor() { }
getUsers(): Observable<User[]> {
return of(this.users);
}
getUser(id: number): Observable<User | undefined> {
const user = this.users.find(user => user.id === id.toString());
return of(user);
}
addUser(user: User): Observable<void> {
if (!user.id) {
user.id = (this.users.length + 1).toString();
}
user.createdDate = new Date();
if (user.dateOfBirth) {
user.age = this.calculateAge(user.dateOfBirth);
}
this.users.push({ ...user });
return of();
}
updateUser(updatedUser: User): Observable<void> {
const index = this.users.findIndex(user => user.id === updatedUser.id);
if (index !== -1) {
updatedUser.age = this.calculateAge(updatedUser.dateOfBirth);
this.users[index] = updatedUser;
}
return of();
}
updateUserPhoto(id: string, photoUrl: string | ArrayBuffer | null): Observable<void> {
const index = this.users.findIndex(user => user.id === id);
if (index !== -1 && photoUrl) {
if (typeof photoUrl !== 'string') {
// Convert ArrayBuffer to base64 string
photoUrl = this.arrayBufferToBase64(photoUrl);
}
this.users[index].photo = photoUrl;
}
return of();
}
deleteUser(id: number): Observable<void> {
this.users = this.users.filter(user => user.id !== id.toString());
return of();
}
private calculateAge(dateOfBirth: string): number {
const dob = new Date(dateOfBirth);
const ageDifMs = Date.now() - dob.getTime();
const ageDate = new Date(ageDifMs);
return Math.abs(ageDate.getUTCFullYear() - 1970);
}
private arrayBufferToBase64(buffer: ArrayBuffer): string {
let binary = '';
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
}
I tried everything and it isnt working. I want when i edit it and place a new picture and save it the picture to change and not a new user to add.
Inside your add-user component you have some code that is binding an event listener to the confirmation modal button to fire off this.confirmAddUserAndNavigate()
:
ngAfterViewInit(): void {
const confirmModalElement = document.getElementById('confirmModal');
if (confirmModalElement) {
const saveButton = confirmModalElement.querySelector('.btn-primary');
if (saveButton) {
saveButton.addEventListener('click', () => {
this.confirmAddUserAndNavigate();
});
}
}
}
but there is already a function binded to the click
event inside the HTML template. So it's firing off two calls to addUser()
whenever the button is pressed.
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="cancel()">Cancel</button>
<button type="button" class="btn btn-primary" (click)="confirmAddUserAndNavigate()">Save</button>
</div>