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'))
Related
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();
}
I use two pages with login and crud operations in my project. I need some help. I want to check user login first and redirect to login page if not logged. There are crud operations after the user logs in. Whichever user logs in, only the products added by them will appear. How can I do that? I used node js on backend.
this is login.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormControl } from '#angular/forms';
import { ActivatedRoute, Router } from '#angular/router';
import { HttpClient } from '#angular/common/http';
import { LoginService } from '../shared/login.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
loginForm: FormGroup;
username = new FormControl('');
password = new FormControl('');
constructor(
private http: HttpClient,
private authService: LoginService,
private formBuilder: FormBuilder,
private _router: Router) { }
ngOnInit() {
this.loginForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
}
get f() { return this.loginForm.controls; }
loginSubmit() {
this.http.post("http://localhost:3000/login", { username: this.username.value, password: this.password.value })
.subscribe(result => {
debugger;
if(result.result){
this._router.navigate(["/payment"]);
// sessionstorage
}else{
alert("Bilgiler yanlış");
}
}, error => {
alert('hata oluştur');
});
}
}
and this is login.service.ts
import { loginDetail } from './login.model';
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from "#angular/common/http";
import { Router } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class LoginService {
//private readonly mockedUser = new SignInData()
isAuthenticated = false;
loginFormData: loginDetail= {
username: null,
password: null,
user_id: null
};
list : loginDetail[];
readonly rootURL = 'http://localhost:5000/api';
readonly rootURLnode = 'http://localhost:3000/';
constructor(private http: HttpClient, private router: Router) { }
login() {
//debugger;
//console.log(this.loginFormData)
this.isAuthenticated = true;
this.router.navigate(['payment-details']);
return this.http.post(this.rootURLnode + 'payment-details', this.loginFormData);
}
}
Use a route guard to check if the user is authenticated or not. Below you can find an example:
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private _authService: AuthService, private _router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
const url: string = state.url;
return this.checkLogin(url);
}
checkLogin(url: string): boolean {
if (this._authService. isAuthenticated) {
return true;
}
// Store the attempted URL for redirecting
this._authService.redirectUrl = url;
// Navigate to the login page
this.router.navigate(['/login']);
return false;
}
}
You can use it in the routing module like so:
const routes: Routes = [
{
path: '',
loadChildren: () => import('.home/home.module').then((m) => m.HomeModule),
canActivate: [AuthGuard]
}
];
Your login method should be like this:
login() {
return this.http.post(this.rootURLnode + 'payment-details',
this.loginFormData).pipe(
tap(() => {
// you need to do this only for the success case
this.isAuthenticated = true;
this.router.navigate(['payment-details']);
})
}
}
I recommend you to go through the tutorial from the Angular docs https://angular.io/guide/router-tutorial
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++;
I Have get some error while login which is not expected but i try to solve it from 2 days but i cannot. I am using Nodejs for the api and angular 7 for the frontend
i have posted some of the code with the error
please help me to solve this
THANK YOU SO MUCH IN ADVANCE
auth.service.ts
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import "rxjs/Rx";
import { JwtHelperService } from "#auth0/angular-jwt";
import "core-js/es7/reflect";
import { HttpClient } from "#angular/common/http";
const jwt = new JwtHelperService();
#Injectable()
export class AuthService {
private decodedToken;
constructor(private http: HttpClient) {}
public register(userData: any): Observable<any> {
return this.http.post("/api/v1/users/register", userData);
}
public login(userData: any): Observable<any> {
return this.http.post("/api/v1/users/auth", userData).map(token => {
//debugger;
return this.saveToken(token);
});
}
private saveToken(token): string {
//debugger;
this.decodedToken = jwt.decodeToken(token);
localStorage.setItem("bwm_auth", token.token);
localStorage.setItem("bwm_meta", JSON.stringify(this.decodedToken));
return token;
}
}
login.component.ts
import { Component, OnInit } from "#angular/core";
import { Router, ActivatedRoute } from "#angular/router";
import { AuthService } from "../shared/auth.service";
import { FormBuilder, FormGroup, Validators } from "#angular/forms";
#Component({
selector: "bwm-login",
templateUrl: "./login.component.html",
styleUrls: ["./login.component.scss"]
})
export class LoginComponent implements OnInit {
loginForm: FormGroup;
mistake: any[] = [];
notifyMessage: string = "";
constructor(
private fb: FormBuilder,
private auth: AuthService,
private router: Router,
private route: ActivatedRoute
) {}
ngOnInit() {
this.initForm();
this.route.params.subscribe(params => {
if (params["registered"] == "success") {
//debugger;
this.notifyMessage =
"You have been successfully registered you can login now";
}
});
}
initForm() {
this.loginForm = this.fb.group({
email: [
"",
[
Validators.required,
Validators.pattern(
"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$"
)
]
],
password: ["", Validators.required]
});
}
isInvalidForm(fieldName): boolean {
return (
this.loginForm.controls[fieldName].invalid &&
(this.loginForm.controls[fieldName].dirty ||
this.loginForm.controls[fieldName].touched)
);
}
isRequiredForm(fieldName): boolean {
return this.loginForm.controls[fieldName].errors.required;
}
login() {
// debugger;
//console.log(this.loginForm.value);
this.auth.login(this.loginForm.value).subscribe(
token => {
//debugger;
this.router.navigate(["/rentals"]);
},
errorResponse => {
// debugger;
console.log(errorResponse);
// this.mistake = errorResponse.error.errors;
//this.mistake = errorResponse.error;
}
);
}
}
error in browser
TypeError: token.split is not a function
at JwtHelperService.push../node_modules/#auth0/angular-jwt/src/jwthelper.service.js.JwtHelperService.decodeToken (jwthelper.service.js:70)
at AuthService.push../src/app/auth/shared/auth.service.ts.AuthService.saveToken (auth.service.ts:26)
at MapSubscriber.project (auth.service.ts:20)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:35)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:41)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next (filter.js:38)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber.notifyNext (mergeMap.js:84)
error in browser
As it seems the token that is returned from server is not string type
public login(userData: any): Observable<any> {
return this.http.post("/api/v1/users/auth", userData).map(token => {
//debugger;
return this.saveToken(token);
});
}
try to check it what is returned from server
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');
}