Angular 6 use passing variables between components in the same file - node.js

I have an Angular 6 app that uses API's to work. In my App I have to show some of the incoming data inside an Angular Material Dialog, so the dialog Component is located alongside with the principal component I'm using to display API's data.
Here's the thing, I want to transfer some of my data to the Dialog component, for example:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-jours-feries',
templateUrl: './show-data.component.html',
styleUrls: ['./show-data.component.scss']
})
export class ShowDataComponent {
public data: any;
// data here will get the incoming data from the API
}
#Component({
selector: 'dialog.component',
templateUrl: 'dialog.component.html',
styleUrls: ['./dialog.component.scss']
})
export class DialogComponent {
// I want to use data property in this component without duplicating functions and variables
}
Here's my original code:
import { Component, OnInit, Inject } from '#angular/core';
import { FormControl, FormGroupDirective, NgForm, Validators } from '#angular/forms';
import { ErrorStateMatcher } from '#angular/material/core';
import { MatDialog, MAT_DIALOG_DATA } from '#angular/material';
import { ConfigurationService } from 'src/app/services/configuration.service';
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
}
#Component({
selector: 'app-jours-feries',
templateUrl: './jours-feries.component.html',
styleUrls: ['./jours-feries.component.scss']
})
export class JoursFeriesComponent implements OnInit {
public displayedColumns: string[] = ['date', 'reserve', 'description', 'actions'];
public jourFeriesObjectHolder: any;
public description: any;
constructor(
private dialog: MatDialog,
private __ConfigurationService: ConfigurationService
) {
this.getJoursFeries();
}
/**
* Getting {{ Congés Annuels }} data from our service
*
*/
public getJoursFeries(){
this.__ConfigurationService.getJoursFeries().subscribe((data) => {
this.jourFeriesObjectHolder = data;
});
}
public getJoursFeriesDescription(){
this.__ConfigurationService.getJoursFeriesDesc().subscribe((data) => {
// this.jourFeries_IDHolder = data[0]._id;
// this.descExplicatifJourFer = data[0].description;
this.description = data[0].description;
});
}
openDialog() {
const dialogRef = this.dialog.open(AddUpdateJourFerieComponent, { data: this.description });
dialogRef.afterClosed().subscribe(confirm => {
if(confirm){
// do something
}
});
}
ngOnInit() {
}
}
#Component({
selector: 'add-update.component',
templateUrl: 'add-update.component.html',
styleUrls: ['./add-update.component.scss']
})
export class AddUpdateJourFerieComponent {
// Validate Jours Fériés
requiredDescriptionJoursFeries = new FormControl('', [
Validators.required
]);
requiredNameJoursFeries = new FormControl('', [
Validators.required
]);
requiredDateJoursFeries = new FormControl('', [
Validators.required
]);
requiredTextJoursFeries = new FormControl('', [
Validators.required
]);
matcher = new MyErrorStateMatcher();
/* Jour ferié */
public jourFerDate: string;
public isReservedHoliday: number = 0;
public descJourFer: string;
public descExplicatifJourFer: string;
public jourFeries_IDHolder: string;
constructor(#Inject(MAT_DIALOG_DATA) public data: any) {
console.log(data);
}
}
Any idea ?

let dialogRef = dialog.open(DialogComponent, {Data: { }})
Reference link for angular material dialog

i think you need to use EventEmitter for that, here is the doc link

I found the issue guys, I forgot to execute the fetching function in the main component constructor, and then create an object to pass it through.
constructor(
private dialog: MatDialog,
private __ConfigurationService: ConfigurationService
) {
this.getJoursFeries();
this.getJoursFeriesDescription(); // this one
}
openDialog() {
const dialogRef = this.dialog.open(AddUpdateJourFerieComponent, {
data: {
description: this.description
}
});
dialogRef.afterClosed().subscribe(confirm => {
//console.log(`Dialog result: ${confirm}`);
if(confirm){
}
});
}

Your code
constructor(
private dialog: MatDialog,
private __ConfigurationService: ConfigurationService
) {
this.getJoursFeries();
this.getJoursFeriesDescription(); // this one
}
openDialog() {
const dialogRef = this.dialog.open(AddUpdateJourFerieComponent, {
data: {
description: this.description
}
});
dialogRef.afterClosed().subscribe(confirm => {
//console.log(`Dialog result: ${confirm}`);
if(confirm){
}
});
}
Steps to receive your data on AddUpdateJourFerieComponent
import { Inject } from '#angular/core';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '#angular/material'
constructor(#Inject(MAT_DIALOG_DATA) public data: any){}
ngOnInit() {
console.log(this.data, 'here is your data');
}

Related

New Entry Not reflacting in table after inserting New record in CRUD angular app

In Angular 13, I created basic CRUD app of employee. When i insert new data and hit submit it run the createEmployee() service and print data on console. Then it redirect to home page that shows all entry in table which call getEmployeeList(). But sometimes it shows newly created entry and sometimes it not shows. In database it perfectly entered. When i goto some other page and come back to home page it shows.
create-employee.components.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Employee } from 'src/app/employee';
import { EmployeeService } from 'src/app/Services/employee.service';
#Component({
selector: 'app-create-employee',
templateUrl: './create-employee.component.html',
styleUrls: ['./create-employee.component.css']
})
export class CreateEmployeeComponent implements OnInit {
employee: Employee = new Employee();
constructor(private employservice: EmployeeService,private router: Router) { }
ngOnInit(): void {
}
saveEmployee() {
this.employservice.createEmployee(this.employee).subscribe(data => {
console.log(data);
})
console.error();
}
gotoemployeelist() {
this.router.navigate(['employees']);
}
onSubmit() {
this.saveEmployee();
this.gotoemployeelist();
}
}
employee-service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { map, Observable } from 'rxjs';
import { Employee } from '../employee';
#Injectable({
providedIn: 'root'
})
export class EmployeeService {
public baseURL="http://localhost:8080/api/v1/employees";
constructor(private httpClient: HttpClient) {}
getEmployeeList(): Observable<Employee[]> {
return this.httpClient.get<Employee[]>(this.baseURL).pipe(
map(employees => {
for(let employee of employees) {
employee.bdate = new Date(employee.bdate);
employee.jdate = new Date(employee.jdate);
}
console.log("Employees Service: GetEmployee() called");
return employees;
}));
}
createEmployee(employee: Employee): Observable<Object> {
console.log("Employees Service: CreateEmployee() called");
return this.httpClient.post(this.baseURL,employee);
}
getEmployeebyId(id: Number): Observable<Employee> {
console.log("Employees Service: GetEmployeeById() called");
return this.httpClient.get<Employee>(this.baseURL+"/"+id);
}
updateEmployee(employee: Employee,id: number): Observable<Object> {
console.log("Employees Service: UpdateEmployee() called");
console.log(employee);
return this.httpClient.put(this.baseURL+"/"+id,employee);
}
deleteEmployee(id: number): Observable<Object> {
console.log("Employees Service: DeleteEmployee() called");
return this.httpClient.delete(this.baseURL+"/"+id);
}
}
Home-component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Employee } from 'src/app/employee';
import { EmployeeService } from 'src/app/Services/employee.service';
#Component({
selector: 'app-employee-list',
templateUrl: './employee-list.component.html',
styleUrls: ['./employee-list.component.css',]
})
export class EmployeeListComponent implements OnInit {
employees: Employee[];
constructor(private employeeservice: EmployeeService,private router: Router) {
}
ngOnInit(): void {
this.getEmployees();
}
private getEmployees() {
this.employeeservice.getEmployeeList().subscribe(data => {
console.log(data);
this.employees=data;
});
}
updateEmployee(id: Number) {
this.router.navigate(['update-employee',id]);
}
deleteEmployee(id: number) {
this.employeeservice.deleteEmployee(id).subscribe(data => {
console.log(id+"employeed Deleted.");
this.getEmployees();
});
}
employeeDetails(id: number) {
this.router.navigate(['emloyee-details',id]);
}
}
In console you can see that createEmployee() called then GetEmployee() called and then it print console.log(newEntry) after navigation.
What is happening program is not waiting to complete createEmployee API before navigating to the home page. You need to call gotoemployeelist() only after the you get response from createEmployee API. You can do this by calling the method inside the subscribe
saveEmployee() {
this.employservice.createEmployee(this.employee).subscribe(data => {
console.log(data);
this.gotoemployeelist();
})
console.error();
}
gotoemployeelist() {
this.router.navigate(['employees']);
}
onSubmit() {
this.saveEmployee();
}

subscribe next parameter types error in angular

I shared my error and code below. Somehow I cannot understand why the error is caused. Can you help me?
My code:
import { Component, OnInit } from '#angular/core';
import {ProductService} from '../../services/product.service';
#Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.scss']
})
export class ProductsComponent implements OnInit {
products: any[] = [];
constructor(private productService: ProductService) { }
ngOnInit(): void {
this.productService.getAllProducts().subscribe((prods: {count: Number, products: any[]}) => {
this.products = prods.products;
console.log(this.products);
});
}
}
My Error:
my error img
You should typecast your http.get method
getAllProducts(numberOfResults = 10) {
return this.http.get<{count: Number, products: any[]}>(this.SERVER_URL + '/products', { params: { limit: numberOfResults.toString() } });
}
export class ProductsComponent implements OnInit {
products: any[] = [];
constructor(private productService: ProductService) { }
ngOnInit(): void {
this.productService.getAllProducts().subscribe((prods: IPerson) => {
this.products = prods.products;
});
}
}
interface IPerson{
count:number,
products:any[]
}
service:
getAllProducts(){
return this http.get(`url`);
}
But it is better to use the following method:
export class ProductsComponent implements OnInit {
products: any[] = [];
constructor(private productService: ProductService) { }
ngOnInit(): void {
this.productService.getAllProducts().subscribe(prods=> {
this.products = prods.products;
});
}
}
export interface IPerson{
count:number,
products:any[]
}
service:
getAllProducts():Observble<IPerson>{
return this http.get<IPerson>(`url`);
}

print user name after successful login in angular8 application

i want to display my user name after a successful login. As i am working with the login token and my login logic is separately written and not in my auth file , so i will be including all my required files, for a better understanding
the following is the login component file
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
}
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
mode: ProgressBarMode = 'indeterminate';
value = 50;
bufferValue = 75;
loading:boolean=false;
matcher = new MyErrorStateMatcher();
loginForm = new FormGroup({
email: new FormControl('', [Validators.email, Validators.required ]),
password: new FormControl('', [Validators.required, Validators.min(3) ])
})
get email() { return this.loginForm.get('email'); }
get password() { return this.loginForm.get('password'); }
errorMail = '';
getErrorMessage(emailInput:HTMLInputElement) {
const mail=/^\w+([\.-]?\w+)*#meltwater\.com/;
if(!emailInput.value.match(mail)){
this.errorMail='Email or password are not valid'
}
else{
this.loading=true;
}
}
constructor(
private loginService: LoginService,
private saveUserData:AuthService,
private router: Router,
private cookie:CookieService) { }
userDisplayName = ''
ngOnInit(): void {
}
rememberMe(e){
if(e.target.checked){
this.cookie.set('value',this.loginForm.value);
}
}
onSubmit(event) {
event.preventDefault()
console.log('value',this.loginForm.value)
if(this.errorMail.length === 0) {
this.loginService.login(this.loginForm.value).subscribe((res:any) => {
console.log('login response', res)
if(res.auth.success === true) {
localStorage.setItem('auth', JSON.stringify(res.auth))
this.loginService.loggedIn$.next(res.auth)
this.saveUserData.saveAuthData(res)
sessionStorage.setItem('loggedUser', res.Username);
this.router.navigateByUrl('/search/list')
} else {
this.errorMail='Email or password is not valid'
}
})
}
}
// returnUserName(){
// return this.userDisplayName = sessionStorage.getItem('loggedUser');
// }
}
the following is the login service file
export class LoginService {
constructor(private http: HttpClient) { }
loggedIn$ = new BehaviorSubject(null)
login(creds) {
console.log('creds',creds)
return this.http.post<LoginResponse>('https://backend.url/login', {creds})
}
}
this is my auth service file , probably its not needed i suppose
import { Injectable } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { Router } from "#angular/router";
import { Subject } from "rxjs";
import { BehaviorSubject } from 'rxjs';
#Injectable({ providedIn: "root" })
export class AuthService {
private isAuthenticated = false;
private token: string;
private email: string;
private authStatusListener = new Subject<boolean>();
constructor(private http: HttpClient, private router: Router) {}
getToken() {
return this.token;
}
getIsAuth() {
return this.isAuthenticated;
}
getAuthStatusListener() {
return this.authStatusListener.asObservable();
}
public saveAuthData(token: string) {
localStorage.setItem("token", token);
}
private clearAuthData() {
localStorage.removeItem("token");
}
logout() {
// this.token = null;
this.clearAuthData();
this.router.navigate(["/"]);
}
autoAuthUser() {
const authInformation = this.getAuthData();
this.token = authInformation.token;
this.isAuthenticated = true;
this.authStatusListener.next(true);
}
private getAuthData() {
const token = localStorage.getItem("token");
if (!token ) {
return;
}
return {
token: token
}
}
userDetails(){
sessionStorage.setItem('loggedUser', .email);
}
}
this is where i want to display my user name : the header
following is the header component
import { AuthService } from './../../auth/auth.service';
import { LoginComponent } from './../../login/login.component';
import { Router } from '#angular/router';
import { Component, OnInit } from '#angular/core';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
public userIsAuthenticated;
public userName = '';
constructor(public authService: AuthService,public router:Router, public user:LoginComponent) { }
onLogout(){
this.authService.logout();
this.router.navigateByUrl('/');
}
ngOnInit(): void {
this.userName = this.user.returnUserName() ;
}
}
this is throwing me error , probably bcz login component is been imported , i am not so sure about why the error is occuring
You can not inject Component as service, use #ViewChild(LoginComponent) instead, but this will not solve the problem.
To get username try moving that method in AuthService.
Hope it helps.

I am getting multiple calls from angular to the Post API in Node

I am trying to write a file from the data from the database but I'm getting multiple calls from the angular causing multiple entries of the same data.How can I stop that? And also it is causing to override write file after some time.
I am not getting what exactly should I do. I have tried subscribing thing in service in angular but it was of no help.
component.ts
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
import { NgbModalRef, NgbModal } from '#ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
import { CountryService } from './country.service';
import { ConfigService } from '../config.service';
#Component({
selector: 'app-country',
templateUrl: './country.component.html',
styleUrls: ['./country.component.scss'],
encapsulation: ViewEncapsulation.None,
providers: []
})
export class CountryComponent implements OnInit {
public modalRef: NgbModalRef;
public form: FormGroup;
public selectedCountry;
public countries;
constructor(public fb: FormBuilder, public toastrService: ToastrService,
public modalService: NgbModal, public configService: ConfigService,
public countryService: CountryService) {
}
ngOnInit() {
this.form = this.fb.group({
country: [null, Validators.compose([Validators.required])],
});
this.getCountries();
}
public getCountries() {
this.countryService.getCountries((data) => {
this.countries = data.countries;
}, (err) => { });
}
public selectCountry(country) {
this.countryService.selectCountry(country, (resp) => {
}, (err) => { });
}
}
service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { ConfigService } from '../config.service';
import { ToastrService } from 'ngx-toastr';
#Injectable({
providedIn: 'root'
})
export class CountryService {
private setHeaders() {
const headers = new HttpHeaders({
'content-type': 'application/json',
});
return headers;
}
constructor(private configService: ConfigService, public http: HttpClient, public toastrService: ToastrService) { }
selectCountry(country: any, callback, errCallback) {
const options = {
headers: this.setHeaders(),
};
this.http.post(this.configService.url + '/selectedCountry', country, options).subscribe((resp: any) => {
callback(resp);
}, err => {
errCallback(err);
});
}
getCountries(callback, errCallback) {
const options = {
headers: this.setHeaders(),
};
this.http.get(this.configService.url + '/countries', options).subscribe((resp: any) => {
callback(resp.msg);
}, err => {
errCallback(err);
});
}
}
I want the call to be sent only once, not twice
Btw. - Please consider adding the NGRX lib in your app.
An angular-service is considered as a data holder. So make there an instance variable.
It could look like:
export class Service{
private countries;
...
public getCountries(){
return this.countries;
}
public loadCountries(){
this.http.get("url").subscribe(countries => this.countries = countries);
}
}
Then in your component class, you just get the countries.
export class Component{
public coutries;
...
public ngOnInit(){
this.countryService.getCountries(countries => this.countries=coutries);
}
}
And last but not least - load the countries in your AppComponent.
export class AppComponent{
...
public ngOnInit(){
this.countryService.loadCountries();
}
}
Need all your code if you can do a stackblitz, and like Mateusz said its better to handle state with ngrx if you dont want to call twice to backend or a simple approach its something like this https://stackblitz.com/edit/angular-biv6cw.
Change your service method like:
add interface:
export interface Country{
id: number;
name: string;
}
Change your method:
getCountries(): Observable<Country> {
return this.httpClient
.get('pass api url here')
.pipe(
map((body: any) => body),
catchError(error => of(error))
);
}
In your component:
ngOnInit() {
this.countryService.getCountries().subscribe(
(result: Countries) => {
this.countries = result;
},
err => {
log.debug('get countries error', err);
}
);
}
}
Try this:
// Somewhere on init
let postRequestCount = 0;
// More stuff …
// Just before doing the POST request inside the `selectCountry` method
if(postRequestCount < 1) {
http.post(); // TODO : Replace with the actual `post` method
}
postRequestCount++;

Displaying images on angular app from node server

I have a nodejs app running on localhost:3000, I uploaded images using multer, so they are in ./uploads/ folder.
In the Angular app running on locahost:4200 I want to retrieve those images.
in my for loop: ( projectImages is the array of images for every Project Object)
<div *ngFor="let i of project.projectImages">
<img [src]=i.path alt="" >
</div>
the problem is that the path is being displayed as : localhost:4200/uploads/image.png instead of localhost:3000/uploads/image.png
UPDATE:
With that fixed by adding a variable to the component, I'm now getting :
WARNING: sanitizing unsafe URL value
any help would be appreciated!
UPDATE2:
this is my component:
import { Component, OnInit } from '#angular/core';
import { ProjectService } from '../services/project.service';
import { Router, ActivatedRoute } from '#angular/router';
import {Location} from '#angular/common';
import { DomSanitizer } from '#angular/platform-browser';
#Component({
selector: 'app-project-details',
templateUrl: './project-details.component.html',
styleUrls: ['./project-details.component.css']
})
export class ProjectDetailsComponent implements OnInit {
project:any;
apiUrl :string = "localhost:3000";
project_id:string;
constructor(
private router:Router,
private activatedRoute: ActivatedRoute,
private projectService:ProjectService,
private _location: Location,
private sanitization: DomSanitizer
) {
this.activatedRoute.params
.subscribe( params => {
console.log(params.project_id)
this.project_id = params.project_id;
this.getProjectByID(params.project_id);
})
}
ngOnInit() {
}
getProjectByID(project_id:string){
this.projectService.getProjectById(project_id).subscribe((data:any) => {
this.project = data.project;
this.project.projectImages.map(image => {
image.path = this.sanitization.bypassSecurityTrustUrl(`${this.apiUrl}/${image.path}`.replace(/\\/g,"/"));
console.log(image);
return image;
});
console.log(this.project.projectImages);
} , err => {
console.log(err);
});
}
}
NOTE: project.projectImages is an array containing the images, this is what it looks like: https://ibb.co/jEgszo
use full path and sanitize the url before use
import { DomSanitizer } from '#angular/platform-browser';
import { environment } from '../../../../environments/environment';
export class YourClass{
project;
apiUrl;
constructor(private sanitization: DomSanitizer) {
this.apiUrl = environment.apiUrl;
project.projectImages.map(image => {
image.path = this.sanitization.bypassSecurityTrustUrl(`${this.apiUrl}/${image.path}`);
return image;
});
}
}
then in your html you can do this
<div *ngFor="let i of project.projectImages">
<img [src]=i.path alt="" >
</div>
your complete code will look something like this
import { Component, OnInit } from '#angular/core';
import { ProjectService } from '../services/project.service';
import { Router, ActivatedRoute } from '#angular/router';
import { Location } from '#angular/common';
import { DomSanitizer } from '#angular/platform-browser';
import { environment } from '../../../../environments/environment';
#Component({
selector: 'app-project-details',
templateUrl: './project-details.component.html',
styleUrls: ['./project-details.component.css']
})
export class ProjectDetailsComponent implements OnInit {
project: any;
apiUrl: string;
project_id: string;
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private projectService: ProjectService,
private _location: Location,
private sanitization: DomSanitizer
) {
this.apiUrl = environment.apiUrl;
this.activatedRoute.params
.subscribe(params => {
console.log(params.project_id)
this.project_id = params.project_id;
this.getProjectByID(params.project_id);
})
}
ngOnInit() {
}
getProjectByID(project_id: string) {
this.projectService.getProjectById(project_id).subscribe((data: any) => {
data.project.projectImages.map(image => {
image.path = this.sanitization.bypassSecurityTrustUrl(`${this.apiUrl}/${image.path}`);
return image;
});
this.project = data.project;
}, err => {
console.log(err);
});
}
}
check out the docs here
I guess you are using express in your node app, you need to include a static route to the resources/uploads directory (express static routes) like the following:
app.use(express.static('resources/uploads'))

Resources