I have a anuglar 8 application. And I have a parent child route relationship for creating a new item. But when the page is loaded where you can create a new item. the id of the parent component is first set, but the second time when it comes in ngOninit it is null.
So this is the route relationship:
{
path: ':dossierId',
component: ViewComponent, children: [
{ path: 'item/new/:dossierItemType', component: ItemComponent}
],
resolve: {
dossier: DossierResolver,
dossierItems: DossierItemsResolver
}
},
and this is the ite.component.ts:
export class ItemComponent implements OnInit {
itemTypes = DossierItemTypeDto;
formBuilder = new FormBuilder();
isNew = false;
editItemForm: FormGroup;
dossierItemId: string;
item: DossierItemDto;
dossierItems: DossierItemDto[];
dossier: DossierDto;
globalErrors: ValidationErrors;
constructor(
private dossierService: DossierService,
private route: ActivatedRoute,
private router: Router,
private errorProcessor: ErrorProcessor
) {
//this.dossier.id = this.route.snapshot.params.dossierId;
this.dossier = this.route.snapshot.data.dossier;
this.dossierItemId = this.route.snapshot.params.dossierItemId;
this.isNew = this.dossierItemId === undefined;
this.dossierItems = this.route.snapshot.data.dossierItems;
if (this.isNew) {
this.item = {
title: '',
itemType: this.route.snapshot.params.dossierItemType,
date: moment().format('Y-MM-DD'),
createdAt: moment().format('Y-MM-DD'),
body: ''
};
} else {
this.item = this.dossierItems.find(i => i.id === this.dossierItemId);
}
}
ngOnInit(): void {
this.route.params.subscribe((params: Params) => {
this.dossier.id = params.dossierId;
});
}
So when I first look at this line:
I see the id:
06637e72-8915-4735-9400-4ef7705194ea
but when I debug in google chrome, it goes again in the ngOninit and then the id is null.
this is the url:
http://localhost:4200/en/dossier/06637e72-8915-4735-9400-4ef7705194ea/item/new/Interview
And I get this error:
core.js:6406 ERROR TypeError: Cannot set property 'id' of undefined
at SafeSubscriber._next (item.component.ts:58)
at SafeSubscriber.__tryOrUnsub (Subscriber.js:183)
at SafeSubscriber.next (Subscriber.js:122)
at Subscriber._next (Subscriber.js:72)
at Subscriber.next (Subscriber.js:49)
then I get even more errors:
Interview:9 GET https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap net::ERR_NAME_NOT_RESOLVED
Interview:10 GET https://fonts.googleapis.com/icon?family=Material+Icons net::ERR_NAME_NOT_RESOLVED
core.js:6406 ERROR TypeError: Cannot set property 'id' of undefined
at SafeSubscriber._next (item.component.ts:58)
at SafeSubscriber.__tryOrUnsub (Subscriber.js:183)
at SafeSubscriber.next (Subscriber.js:122)
at Subscriber._next (Subscriber.js:72)
at Subscriber.next (Subscriber.js:49)
at BehaviorSubject._subscribe (BehaviorSubject.js:14)
at BehaviorSubject._trySubscribe (Observable.js:42)
at BehaviorSubject._trySubscribe (Subject.js:81)
at BehaviorSubject.subscribe (Observable.js:28)
at ItemComponent.ngOnInit (item.component.ts:57)
So the second time params is like this:
this.dossier.id = params.dossierId;
dossierItemType: "Interview"
this is the save method:
save(): void {
const form = this.editItemForm;
const dossierItemDto: DossierItemPostDto = {
title: form.controls.title.value,
itemType: form.controls.itemType.value,
date: (form.controls.date.value as moment.Moment).format('Y-MM-DD'),
body: form.controls.body.value
};
form.disable();
if (!this.isNew) {
this.dossierService.updateDossierItemById(this.dossier.id, this.item.id, dossierItemDto).subscribe(
item => {
this.item = item;
this.sortDossierItems();
form.enable();
form.markAsPristine();
this.errorProcessor.openSuccessSnackBar($localize`Item is saved`);
},
error => this.handleError(error)
);
} else {
this.dossierService.newDossierItem(this.dossier.id, dossierItemDto).subscribe(
item => {
this.item = item;
this.dossierItems.unshift(item);
this.sortDossierItems();
this.isNew = false;
form.enable();
form.markAsPristine();
this.errorProcessor.openSuccessSnackBar($localize`Item is saved`);
},
error => this.handleError(error)
);
}
}
this.dossierService.newDossierItem(this.dossier.id,
this is now also undefined
this error:
core.js:6406 ERROR Error: Required parameter dossierId was null or undefined when calling newDossierItem.
at DossierService.newDossierItem (dossier.service.ts:359)
at ItemComponent.save (item.component.ts:97)
Because A item is connected with a dossierId
So this is the solution:
#NgModule({
imports: [RouterModule.forRoot(routes, {
paramsInheritanceStrategy: 'always'
})],
exports: [RouterModule]
})
export class AppRoutingModule { }
Related
I'm trying to create a route to a page on Angular when URL address is not correct.
Error in console
In my IDE there is no error message.
The only error message I get on console is this:
ERROR TypeError: Cannot read property 'name' of undefined
at SingleAppareilComponent.ngOnInit (single-appareil.component.ts:19)
at callHook (core.js:2526)
at callHooks (core.js:2495)
at executeInitAndCheckHooks (core.js:2446)
at refreshView (core.js:9480)
at refreshEmbeddedViews (core.js:10590)
at refreshView (core.js:9489)
at refreshComponent (core.js:10636)
at refreshChildComponents (core.js:9261)
at refreshView (core.js:9515)
Below are my files:
SingleAppareilComponent
AppModule
HTML template for 404 page
HTML template for SingleAppareilComponent
AppareilService
single.appareil.component.ts
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { AppareilService } from 'services/appareil.service';
#Component({
selector: 'app-single-appareil',
templateUrl: './single-appareil.component.html',
styleUrls: ['./single-appareil.component.scss']
})
export class SingleAppareilComponent implements OnInit {
name: string = 'Appareil';
status: string = 'Statut';
constructor(private appareilService: AppareilService,
private route: ActivatedRoute) { }
ngOnInit(): void {
const id = this.route.snapshot.params['id'];
this.name = this.appareilService.getApparreilById(+id).name;
this.status = this.appareilService.getApparreilById(+id).status;
}
}
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AppareilComponent } from './appareil/appareil.component';
import { FormsModule } from '#angular/forms';
import { AppareilService } from 'services/appareil.service';
import { AuthComponent } from './auth/auth.component';
import { AppareilViewComponent } from './appareil-view/appareil-view.component';
import { RouterModule, Routes } from '#angular/router';
import { AuthService } from 'services/auth.service';
import { SingleAppareilComponent } from './single-appareil/single-
appareil.component';
import { FourOhFourComponent } from './four-oh-four/four-oh-four.component';
import { HashLocationStrategy, LocationStrategy } from '#angular/common';
const appRoutes: Routes = [
{ path: 'appareils', component: AppareilViewComponent },
{ path: 'appareils/:id', component: SingleAppareilComponent },
{ path: 'auth', component: AuthComponent },
{ path: '', component: AppareilViewComponent },
{ path: 'not-found', component: FourOhFourComponent },
{ path:'**', redirectTo: '/notfound' }
]
#NgModule({
declarations: [
AppComponent,
AppareilComponent,
AuthComponent,
AppareilViewComponent,
SingleAppareilComponent,
FourOhFourComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
RouterModule.forRoot(appRoutes)
],
providers: [
AppareilService,
AuthService,
{provide: LocationStrategy, useClass: HashLocationStrategy}
],
bootstrap: [AppComponent]
})
export class AppModule { }
and it is supposed to display this template:
four-oh-four.component.html
<h2>Erreur 404</h2>
<p>La page que vous cherchez n'existe pas.</p>
but instead it displays this one
single-appareil.component.hmtl
<h2>{{ name }}</h2>
<p>Statut : {{ status }}</p>
<a routerLink="/appareils">Retourner à la liste</a>
appareil-service.ts
export class AppareilService {
appareils = [
{
id: 1,
name: 'Machine à laver',
status: 'éteint'
},
{
id:2,
name: 'Frigo',
status: 'allumé'
},
{
id:3,
name: 'Ordinateur',
status: 'éteint'
}
];
getApparreilById(id: number) {
const appareil = this.appareils.find(
(appareilObject) =>{
return appareilObject.id === id;
}
);
return appareil
}
switchOnAll() {
for (let appareil of this.appareils) {
appareil.status = 'allumé'
}
}
switchOffAll() {
for (let appareil of this.appareils) {
appareil.status = 'éteint'
}
}
switchOnOne(index: number) {
this.appareils[index].status = 'allumé';
}
switchOffOne(index: number) {
this.appareils[index].status = 'éteint';
}
Why does console show this error?
ERROR TypeError: Cannot read property 'name' of undefined
at SingleAppareilComponent.ngOnInit (single-appareil.component.ts:19)
As commented by jabaa, your a function inside your component returned undefined. Then an assignment tried to access a property on this non-existing object in the same erroneous line 19:
this.name = this.appareilService.getApparreilById(+id).name
How to debug this?
open your browser's dev tools, go to the debugger, set a breakpoint on the erroneous line
or add debug logging in your source code to show more details
In your SingleAppareilComponent try logging the id parameter extracted from current route-path as well as the return value of getApparreilById(+id):
const id = this.route.snapshot.params['id'];
console.log('Routed to SingleAppareilComponent to display appareil with id: ', id)
let appareil = this.appareilService.getApparreilById(+id);
console.log('AppareilService returned appareil: ', appareil):
this.name = appareil.name; // if appareil is undefined then you will get an error here
What possibly happened?
To analyze your issue further, we must see your AppareilService component, especially the method getApparreilById.
Test your service
appareils = [{
id: 1,
name: 'Machine à laver',
status: 'éteint'
},
{
id: 2,
name: 'Frigo',
status: 'allumé'
},
{
id: 3,
name: 'Ordinateur',
status: 'éteint'
}
];
function getApparreilById(id) {
const appareil = this.appareils.find(
(appareilObject) => {
return appareilObject.id === id;
}
);
return appareil
}
/* Tested with vairous inputs: if not found, then undefined! */
console.log("getApparreilById(1) returns: ", getApparreilById(1));
console.log("getApparreilById(2) returns: ", getApparreilById(2));
console.log("getApparreilById(3) returns: ", getApparreilById(3));
console.log("getApparreilById(4) returns: ", getApparreilById(4));
console.log("getApparreilById('') returns: ", getApparreilById(''));
console.log("getApparreilById('1') returns: ", getApparreilById('1'));
So the find method always returns undefined if appareil with specified id was not found.
And undefined is just an identifier (or you could say a place-holder which signals "Uups, sorry: nothing, nada, null"). It has no properties (like name) to access.
so the error-message is:
Cannot read property 'name' of undefined
There is an object undefined, but it has no properties, so you can not read or write any property.
Alternative way of returning
You could also return a default value-object which is defined, but with empty values, like:
getApparreilById(id: number) {
const appareil = this.appareils.find(a => a.id === id);
if (appareil === undefined) {
return {id: 0, name: '', status: ''}; // defined but empty object
}
return appareil;
}
Assumption on a backend HTTP GET call
Assume the service tries to fetch the appareil resource with specified id from your backend, like: GET /appareils/:id
and expects either a response with HTTP status 200 and the appareil inside body.
Or like apparently here (in the unhappy case), a response with HTTP status 404 if appareil with specified id was not found on backend.
Then the body could be empty, so that getApparreilById returns an undefined appareil object. If no object, then no property name.
Redirect to 404 page programmatically
If undefined is returned (signaling "appareil not found"), you could (as you probably intended) redirect to another component, e.g. your 404 page.
The path to your 404 page was defined inside the routes-definition of your app:
{ path: 'not-found', component: FourOhFourComponent },
You can then use Angular's Router inside your component SingleAppareilComponent:
import { Router } from '#angular/router'; // import the router module here
export class SingleAppareilComponent implements OnInit {
name: string = 'Appareil';
status: string = 'Statut';
// inject router in constructor as parameter
constructor(private appareilService: AppareilService,
private route: ActivatedRoute,
private _router: Router) {
}
ngOnInit(): void {
const id = this.route.snapshot.params['id'];
let appareil = this.appareilService.getApparreilById(+id);
if (typeof appareil === 'undefined') {
// use router to redirect to 404 page as defined in your routes
this._router.navigateByUrl('/not-found');
}
// else continue
this.name = appareil.name;
this.status = appareil.status;
}
}
Note: the get method is only called once (better performance).
The undefined test can also be simplified to something like myVar === undefined (which should have same effect in most cases).
Alternative error handling
Another way would be to return a Promise from your service-method.
This would let you define callbacks for both cases (the happy 200, and all unhappy like 404).
See:
Angular: Http vs fetch api
Further reading
How can I check for "undefined" in JavaScript?
How to redirect to another component after checking conditions in angular 8?
It actually mentions the exact line issue is on this line in ngOnInit:
this.name = this.appareilService.getApparreilById(+id).name;
I suspect you are supposed to return an observable instead of a value there and subscribe to it since how do you know your data is loaded when ngOnInit is called anw .
So I am using jasmine testing and istanbul. I Try to test a component.
And I have a testcase for creating just the component(instantiate), like this:
describe('DossierPersonalDataComponent', () => {
let component: DossierPersonalDataComponent;
let fixture: ComponentFixture<DossierPersonalDataComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, HttpClientTestingModule, DossierModule, BrowserModule],
declarations: [DossierPersonalDataComponent],
providers: [
{
DossierFileService,
ErrorProcessor,
provide: DomSanitizer,
useValue: {
sanitize: () => 'safeString',
bypassSecurityTrustHtml: () => 'safeString'
}
}
]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(DossierPersonalDataComponent);
component = fixture.componentInstance;
});
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
And my component looks like this:
constructor(
private dossierService: DossierService,
private route: ActivatedRoute,
private sanitizer: DomSanitizer,
private dossierFileService: DossierFileService,
private errorProcessor: ErrorProcessor,
private dialog: MatDialog
) {
this.dossierItems = this.route.snapshot.data.dossierItems;
this.editDossierForm = this.formBuilder.group({});
this.editDossierForm.disable();
this.dossier = this.route.snapshot.data.dossier;
this.dossierItems = route.snapshot.data.dossierItems;
this.profileImagefile = this.route.snapshot.data.profileImage;
this.editDossierForm = this.formBuilder.group({
firstName: this.formBuilder.control(this.dossier.firstName, [Validators.required, Validators.maxLength(255)]),
lastName: this.formBuilder.control(this.dossier.lastName, [Validators.required, Validators.maxLength(255)]),
mobile: this.formBuilder.control(this.dossier.mobile, [Validators.maxLength(255)]),
company: this.formBuilder.control(this.dossier.company, [Validators.maxLength(255)]),
buddy: this.formBuilder.control(this.dossier.buddy, [Validators.maxLength(255)]),
supervisor: this.formBuilder.control(this.dossier.supervisor, [Validators.maxLength(255)]),
dateOfBirth: this.formBuilder.control(this.dossier.dateOfBirth)
});
}
ngOnInit(): void {
this.editDossierForm.disable();
}
But I still get this error on the should create unit test:
DossierPersonalDataComponent > should create
Failed: Uncaught (in promise): TypeError: Cannot read property 'firstName' of undefined
TypeError: Cannot read property 'firstName' of undefined
at new DossierPersonalDataComponent (http://localhost:9876/_karma_webpack_/src/app/dossier/components/dossier-profile-data/dossier-personal-data/dossier-personal-data.component.ts:69:4)
at NodeInjectorFactory.DossierPersonalDataComponent_Factory [as factory] (ng:///DossierPersonalDataComponent/ɵfac.js:5:10)
at getNodeInjectable (http://localhost:9876/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:5641:1)
at instantiateRootComponent (http://localhost:9876/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:12566:1)
at createRootComponent (http://localhost:9876/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:26366:1)
at ComponentFactory$1.create (http://localhost:9876/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:33908:1)
at initComponent (http://localhost:9876/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/testing.js:3225:1)
at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:365:1)
at AsyncTestZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:763:1)
at ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:302:1)
So what I have to change? I mean what I have to correct in the test suite? Or unit test?
Thank you.
Remove RouterTestingModule from imports because you don't need it.
You also have to mock activated route to what you want.
describe('DossierPersonalDataComponent', () => {
let component: DossierPersonalDataComponent;
let fixture: ComponentFixture<DossierPersonalDataComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, DossierModule, BrowserModule],
declarations: [DossierPersonalDataComponent],
providers: [
DossierFileService,
ErrorProcessor,
{
provide: ActivatedRoute,
useValue: {
snapshot: {
data: {
dossier: {
firstName: 'hello',
lastName: 'world',
mobile: '111-111-1111',
company: 'acme',
buddy: 'bud',
supervisor: 'super',
dateOfBirth: '1900-01-01',
},
dossierItems: [], // mock these to your liking
profileImage: '',
}
}
}
},
{
// DossierFileService, These have to be outside of the braces
// ErrorProcessor,
provide: DomSanitizer,
useValue: {
sanitize: () => 'safeString',
bypassSecurityTrustHtml: () => 'safeString'
}
}
]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(DossierPersonalDataComponent);
component = fixture.componentInstance;
});
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
I try to select boxes for participants. So that a user will been able to sent some data to one or more participant. And after the user selected some participants the user will be redirected to a Model dialog from anuglar material.
So I have this:
export class EcheqSelectorComponent implements OnInit, OnDestroy {
private subscriptions = new Subscription();
echeqs: EcheqFamilyInfo[] = [];
allEcheqs: EcheqFamilyInfo[] = [];
echeqFamily: EcheqFamilyInfo;
searchInput = '';
filtering = false;
participantInfo: ParticipantInfoDTO;
echeqsToSend: EcheqFamilyInfo[] = [];
echeqSubmissionBatchDTO: EcheqSubmissionBatchDTO;
participantIds$: Observable<string[]>;
patientId: string;
public participantIds: string[] = [];
public participantIdsFromRoute: string[] = [];
constructor(
private apiService: EcheqDefinitionService,
private dialog: MatDialogRef<EcheqSelectorComponent>,
public selectedParticipantService: SelectedParticipantsService,
private submissionService: EcheqSubmissionMedicalService,
private snackBar: MatSnackBar,
#Inject(MAT_DIALOG_DATA) public data: any,
public dialogRef: MatDialogRef<EcheqSelectorComponent>
) {
this.participantInfo = data.participant;
this.participantIdsFromRoute = this.data.participant.participantId ? [this.data.participant.participantId] : undefined;
}
ngOnInit() {
this.subscriptions.add(
this.apiService.listEcheqFamilies().subscribe(families => {
this.echeqs = families;
this.allEcheqs = families;
})
);
}
And the matdialog service looks like this:
export class DialogModelService {
participant: ParticipantInfoDTO;
constructor(private dialog: MatDialog, route: ActivatedRoute) {
this.participant = route.snapshot.data['participant'];
console.log('Route:', this.participant);
}
openEcheqSelectorDialog(participant: ParticipantInfoDTO): Observable<any> {
const dialogRef = this.dialog.open(EcheqSelectorComponent, {
width: '600px',
maxHeight: 'calc(100vh - 2em)',
data: {
participant: participant
}
});
return dialogRef.afterClosed();
}
openSchemaSelectorDialog(participantId: string): Observable<any> {
const dialogRef = this.dialog.open(SchemaSendDialogComponent, {
width: '600px',
maxHeight: 'calc(100vh - 2em)',
data: {
participant: participantId
}
});
return dialogRef.afterClosed();
}
}
But after I select some participants and trigger the event sent, then I get an error on this line:
this.participantIdsFromRoute = this.data.participant.participantId ? [this.data.participant.participantId] : undefined;
}
saying:
EcheqSelectorComponent_Host.ngfactory.js? [sm]:1 ERROR TypeError: Cannot read property 'participantId' of undefined
at new EcheqSelectorComponent (echeq-selector.component.ts:50)
at createClass (core.js:18681)
at createDirectiveInstance (core.js:18550)
at createViewNodes (core.js:19776)
at createRootView (core.js:19690)
at callWithDebugContext (core.js:20722)
at Object.debugCreateRootView [as createRootView] (core.js:20208)
at ComponentFactory_.push../node_modules/#angular/core/fesm5/core.js.ComponentFactory_.create (core.js:18029)
at ComponentFactoryBoundToModule.push../node_modules/#angular/core/fesm5/core.js.ComponentFactoryBoundToModule.create (core.js:7812)
at ViewContainerRef_.push../node_modules/#angular/core/fesm5/core.js.ViewContainerRef_.createComponent (core.js:18140)
So what I have to do to fix this?
Thank you
can any one please tell me why I can not loop through this array?
In ngOnInit, everything works fine. I got an array that I successfully display in the template.
But in ngAfterViewInit, console.log show the array but when looping through with "for of" or "forEach", nothing works.
import { JobsService } from '../jobs.service';
import {Job} from '../models/Job';
#Component({
selector: 'app-job',
templateUrl: 'job.component.html'
})
export class JobComponent implements OnInit, AfterViewInit {
title = 'Job';
jobs: Job[] = [];
InProcess = '';
CurrentPartner = '';
ShowProcess = false;
sended = '';
constructor(private jobsService: JobsService) {
}
ngOnInit() {
this.jobs = this.jobsService.getJobs();
}
ngAfterViewInit() {
console.log(this.jobs); // Show the array
// Nothing happened when looping through the array
this.jobs.forEach((oneJob) => {
console.log(oneJob);
});
}
}
Screenshot of the console in Google Chrome
The content of the service:
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import {Job} from './models/Job';
interface IJob {
message: string;
jobs: any[];
}
#Injectable({
providedIn: 'root'
})
export class JobsService {
constructor(private httpClient: HttpClient) { }
private REST_API_SERVER = 'http://localhost:8080/myband/api/getjobs.php';
private REST_API_SERVER_SEND = 'http://localhost:8080/myband/api/sendjob.php';
jobList: Job[] = [];
errorMessage: any;
message: string;
static handleError(err: HttpErrorResponse) {
let errorMessage = '';
if (err.error instanceof ErrorEvent) {
errorMessage = `An error occurred: ${err.error.message}`;
} else {
errorMessage = `Server returned code: ${err.status}, error message is: ${err.message}`;
}
console.error(errorMessage);
return throwError(errorMessage);
}
public getJobs() {
this.requestJobs().subscribe(
iJob => {
this.message = iJob.message;
for (const job of iJob.jobs) {
const oneJob: Job = new Job(job);
this.jobList.push(oneJob);
}
},
error => this.errorMessage = error as any
);
return this.jobList;
}
public requestJobs(): Observable<IJob> {
return this.httpClient.get<IJob>(this.REST_API_SERVER).pipe(
catchError(JobsService.handleError)
);
}
}
The first thing I want to say to you is about isolation of responsibilities.
Your service must have just one job: provider one way to access your data; It means your logic inside getJobs() method could be done in your component.
export class JobsService {
constructor(
private httpClient: HttpClient,
) {}
private REST_API_SERVER = 'http://localhost:8080/myband/api/getjobs.php';
public requestJobs(): Observable<IJob> {
return this.httpClient.get<IJob>(this.REST_API_SERVER);
}
}
Now, you can handler your data in your component.
import { JobsService } from '../jobs.service';
#Component({
selector: 'app-job',
templateUrl: 'job.component.html'
})
export class JobComponent implements OnInit, AfterViewInit {
title = 'Job';
jobs$;
InProcess = '';
CurrentPartner = '';
ShowProcess = false;
sended = '';
constructor(private jobsService: JobsService) {
}
ngOnInit() {
this.jobs$ = this.jobsService.requestJobs();
}
ngAfterViewInit() {
this.jobs$
.pipe(
map(() => {}), // change your data here
catchError(() => {}) // handler your error here;
)
.subscribe(
() => {} // have access to your final data here.
);
}
}
Things to know:
You can remove the subscribe() execution and use the async pipe in your template;
The use of the operator map in pipe() is optional, you can handler your final data directly from your first callback subscribe().
You can convert your Observable to Promise using toPromise() method in one observable. Don't forgot async / await in your ngAfterViewInit.
Let me know if there is something I can help.
Try:
Object.keys(this.jobs).forEach(job => {
console.log(this.jobs[job]);
});
Try to assign an iterator function with below part replacement by this code:
// Nothing happened when looping through the array
this.jobs.forEach(oneJob, function(value, key) {
console.log(key + ': ' + value);
});
Usage of forEach in AngularJS:
For documentation try to check AngularJS forEach Docs
Syntax:
someIterable.forEach(object, iterator, [context])
Please check below example
class Job {
id: any;
status: any;
constructor(obj: any) {
this.id = obj.id;
this.status = obj.status;
}
}
let arr = [
{
id: 1,
status: "job"
}, {
id: 2,
status: "job2"
}
];
let newArr: any = [];
arr.forEach(a => {
let obj: Job = new Job(a);
newArr.push(obj);
})
console.log(newArr);
newArr.forEach((a: any) => {
console.log(a);
})
Hii all I am trying to post data to json server using post method , but unfortunately I have erros, my app have buttons follow, likes etc , I want when user clicks follow numbers increase and saved to the json file , so now when user clicks button I get the following error :
Note: am using fakes json server : Fake Json server
Error: Insert failed, duplicate id
at Function.insert (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash-id\src\index.js:49:18)
at C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:4374:28
at arrayReduce (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:683:21)
at baseWrapperValue (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:4373:14)
at LodashWrapper.wrapperValue (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:9052:14)
at create (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\lib\server\router\plural.js:221:52)
at Layer.handle [as handle_request] (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\route.js:137:13)
at next (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\route.js:131:14)
at Route.dispatch (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\route.js:112:3)
POST /statuses 500 13.873 ms - -
Here is service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import {Status } from '../model/statuses.model';
import { Comment } from '../model/comments.model';
#Injectable({
providedIn: 'root'
})
export class UserService {
status: Status[];
constructor(private http: HttpClient) { }
statusUrl = 'http://localhost:3000/statuses';
commentsUrl = 'http://localhost:3000/comments';
getStatuses() {
return this.http.get<Status[]>(this.statusUrl);
}
addStatus(status: Status) {
return this.http.post(this.statusUrl, status);
}
addComments(comment: Comment) {
return this.http.post(this.commentsUrl, comment);
}
}
here is ts file :
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { UserService } from '../service/user.service';
import { Status } from '../model/statuses.model';
import { Comment } from '../model/comments.model';
import {FormBuilder, FormGroup, Validators} from '#angular/forms';
#Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
styleUrls: ['./user-profile.component.scss']
})
export class UserProfileComponent implements OnInit {
status: Status[];
comment: Comment[];
constructor(private formBuilder: FormBuilder, private http: HttpClient, private userService: UserService) { }
addForm: FormGroup;
ngOnInit() {
this.addForm = this.formBuilder.group({
id: [],
name: ['', Validators.required],
city: ['', Validators.required],
description: ['', Validators.required],
});
this.userService.getStatuses()
.subscribe( data => {
this.status = data;
console.log(data);
console.log(this.status);
});
}
addComments() {
this.userService.addComments(this.addForm.value)
.subscribe(data => {
this.comment.push(this.addForm.value);
});
}
followButtonClick(statusId) {
const statusToUpdate = this.status.filter(status => status.id === statusId)[0];
statusToUpdate.followers++;
statusToUpdate.following++;
this.persistStatus(statusToUpdate);
}
likesButtonClick(statusId) {
const statusToUpdate = this.status.filter(status => status.id === statusId)[0];
statusToUpdate.like++;
this.persistStatus(statusToUpdate);
}
persistStatus(status) {
this.userService.addStatus(status)
.subscribe(data => {
this.status = status;
});
}
}
Here is json file :
{
"statuses": [
{
"id": 1,
"statusId": 20,
"likes": 121,
"following": 723,
"followers": 4433
}
]
}
Here is model
export class Status {
id: number;
statusId: number;
like: number;
following: number;
followers: number;
}
what am I doing wrong in my code ????
From documentation of the fake json-server you are using,:
Id values are not mutable. Any id value in the body of your PUT or
PATCH request will be ignored. Only a value set in a POST request will
be respected, but only if not already taken.
You are trying to update an existing status, so you need a put call not post. Something like this:
updateStatus(status: Status) {
return this.http.put(this.statusUrl + '/' + status.id, status);
}
And use it in the persistStatus function.
persistStatus(status) {
his.userService.updateStatus(status)
.subscribe(data => {
this.status = [status];
});
}