Reputation: 475
TypeError: Cannot read property 'ip' of null
provider.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { DeviceInterface } from '../interfaces/Device';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class DeviceService {
private _devices = new BehaviorSubject<DeviceInterface[]>([]);
private baseUrl = 'api/monitoring';
private dataStore: { devices: DeviceInterface[] } = { devices: [] };
readonly devices = this._devices.asObservable();
constructor(private http: HttpClient) { }
loadAll() {
this.http.get<DeviceInterface[]>(`${this.baseUrl}/devices`).subscribe(
data => {
this.dataStore.devices = data;
this._devices.next((<any>Object).assign({}, this.dataStore).devices);
},
error => console.log('Could not load todos.')
);
}
create(device: DeviceInterface) {
this.http
.post<DeviceInterface>(`${this.baseUrl}/add`, device)
.subscribe(
data => {
this.dataStore.devices.push(data);
this._devices.next((<any>Object).assign({}, this.dataStore).devices);
},
error => console.log('Could not create todo.')
);
}
}
component.ts
import { Component, OnInit } from '@angular/core';
import { DialogService, Dialog } from '../providers/dialog.provider';
import { fadeInOut } from '../app.component.animation';
import { AppComponent } from '../app.component'
import {
LanguageService,
} from '../providers/language.provider';
import { DeviceService } from '../providers/device.provider';
import { DeviceInterface } from '../interfaces/Device';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Component({
selector: 'app-monitoring',
templateUrl: './monitoring.component.html',
styleUrls: ['./monitoring.component.scss'],
animations: [fadeInOut],
})
export class AppMonitoring implements OnInit {
dialog: Dialog;
ShowDevices: boolean;
devices: Observable<DeviceInterface[]>;
constructor(
public language_service: LanguageService,
public device_service: DeviceService,
private dialog_service: DialogService,
app: AppComponent
) {
app.done$.pipe().subscribe(result => {
this.ShowDevices = true;
});
}
ngOnInit() {
this.devices = this.device_service.devices;
this.device_service.loadAll();
this.ShowDevices = false;
this.dialog_service.DialogState.subscribe(dialog => this.dialog = dialog);
}
AddDevice() {
this.dialog = Dialog.DIALOG_ADD;
this.dialog_service.ChangeDialog(this.dialog);
}
Scan() {
this.dialog = Dialog.DIALOG_SCAN;
this.dialog_service.ChangeDialog(this.dialog);
}
}
The html template
<div [@fadeInOut] *ngIf="ShowDevices">
<div class="box-header" style="margin-bottom:15px;">
<div class="div-right" style="line-height: 35px;">
<a href="#" onclick="return false;" (click)="AddDevice()" class="pull-right"><i matTooltipPosition="below" class="fa fa-plus"></i> </a>
<a href="#" onclick="return false;" (click)="Scan()" class="pull-right"><i matTooltipPosition="below" class="fa fa-search"></i> </a>
</div>
</div>
<app-device class="flexItemSensor" *ngFor="let device of devices | async; index as i;" [ip]="device?.ip" [name]="device?.name"> </app-device>
</div>
When i add you using
this.device_service.create(post);
The new item has been added without the input values receiving the following error and the application freezes.
The create function itself is called in a 3rd component with the following code
AddDevice() {
let post: DeviceInterface = {
ip: this.AddDeviceForm.value.ip,
name: this.AddDeviceForm.value.name,
}
this.device_service.create(post);
}
Cannot read property 'ip' of null
I know the item is being stored in the database successfully, when i restart the program i can see the new item with his values, what is the proper way an item to be added with his value shown ?
Best regards!
Edit: I have tried adding the following code in ngOnInit() and on devices being added the new values of devices are indeed null
ngOnInit() {
this.device_service.devices.subscribe(devices => {
console.log(devices);
} );
}
Edit 2 : Issue is resolved, turn out that in the back end controller should return the following :
return Ok(device);
Upvotes: 1
Views: 1486
Reputation: 31115
The BehaviorSubject
would immediately emit the current value it holds on subscription. By the time the async
triggers the subscription the value of the observable is still the default (an empty array []
). So there is no ip
property.
Use safe navigation operator ?.
to check if the value is defined before trying to access it's properties
<app-device *ngFor="let device of devices | async; index as i;" [ip]="device?.ip" [name]="device?.name"> </app-device>
Try to check beforehand if the array is non-empty using *ngIf
directive.
<ng-container *ngIf="(devices | async) as devicesData">
<ng-container *ngIf="devicesData.length > 0">
<app-device *ngFor="let device of devicesData; index as i;" [ip]="device.ip" [name]="device.name"> </app-device>
<ng-container>
<ng-container>
Upvotes: 2
Reputation: 10979
Try this
<app-device *ngFor="let device of devices | async; index as i;" [ip]="device?.ip" [name]="device?.name"> </app-device>
Upvotes: 2