In my Angular-12 project I am trying to edit data that has image. The code is shown below:
interface:
export class VehicleResponse {
results!: { vehicle: IVehicle };
}
export interface IVehicle {
id?: number;
registration_number: string;
vehicle_image?: any;
}
service:
getVehicleById(id: number): Observable<VehicleResponse> {
return this.http.get<VehicleResponse>(this.api.baseURL 'vehicles/fetchbyid/' id, this.httpOptions);
}
public updateVehicle(id: number, data: any) {
return this.http.post(this.api.baseURL 'vehicles/update/' id, data, this.httpOptions1);
}
component
import {
IVehicle,
VehicleResponse
} from 'src/app/models/vehicle.model';
import {
VehicleService
} from 'src/app/services/vehicle.service';
editForm!: FormGroup;
vehicle!: IVehicle;
vehicledata!: IVehicle;
isLoading = false;
data: any;
isSubmitted = false;
_id!: number;
vehicleImageDirectoryPath: any = this.api.imageURL 'vehicle_images/';
url = '';
files ? : any;
constructor(
private fb: FormBuilder,
private router: Router,
private api: ApiService,
private route: ActivatedRoute,
private store: Store < AppState > ,
private vehicleService: VehicleService
) {}
onSelectFile(event: any) {
if (event.target.files && event.target.files[0]) {
var reader = new FileReader();
reader.readAsDataURL(event.target.files[0]); // read file as data url
this.files = event.target.files[0]; // associates the file to the a different property
reader.onload = (event: any) => { // called once readAsDataURL is completed
// console.log(event);
this.url = event.target.result;
}
}
}
editVehicle() {
this.editForm = this.fb.group({
registration_number: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(50)]],
vehicle_image: ['', [
RxwebValidators.extension({
extensions: ["jpg", "jpeg", "bmp", "png", "gif", "svg"]
})
]]
});
}
loadVehicleById() {
this.vehicleService.getVehicleById(this._id)
.subscribe(
(data: VehicleResponse) => {
this.vehicledata = data.results.vehicle;
this.editForm.patchValue({
registration_number: this.vehicledata.registration_number,
vehicle_image: this.vehicledata.vehicle_image,
});
this.isLoading = false;
}
);
}
ngOnInit(): void {
this._id = this.route.snapshot.params['id'];
bsCustomFileInput.init();
this.editVehicle();
this.loadVehicleById();
this.isLoading = false;
}
submitForm() {
this.isSubmitted = true;
// stop here if form is invalid
if (this.editForm.invalid) {
return;
}
this.isLoading = true;
const formVehicleData = this.editForm.getRawValue();
const formData = new FormData();
formData.append('registration_number', formVehicleData.registration_number);
if (this.files) {
formData.append("vehicle_image", this.files, this.files.name);
}
this.vehicleService.updateVehicle(this._id, formData).subscribe(res => {
this.data = res;
});
}
<div class="card-body">
<form [formGroup]="editForm" (ngSubmit)="submitForm()">
<div class="col-lg-4">
<div class="form-group">
<label for="registration_number">Registration No.:<span style="color:red;">*</span></label>
<input type="text" formControlName="registration_number" placeholder="XB-547-AG" class="form-control" required/>
</div>
<div *ngIf="isSubmitted || (fc.registration_number.touched && fc.registration_number.invalid)">
<div *ngIf="fc.registration_number.hasError('required')">
<div class="text-danger">
Registration Number is required!
</div>
</div>
<div *ngIf="fc.registration_number.hasError('minlength')">
<div class="text-danger">
Registration Number cannot be less than 2 characters!
</div>
</div>
<div *ngIf="fc.registration_number.hasError('maxlength')">
<div class="text-danger">
Registration Number cannot be more than 50 characters!
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="vehicle_image">Vehicle Image:</label>
<div class="card-body box-profile">
<div class="text-center">
<img class="profile-user-img img-fluid img-circle" [src]="vehicledata.vehicle_image ? vehicleImageDirectoryPath vehicledata.vehicle_image : url || 'assets/img/no-image.png'" alt="No Vehicle Image" onerror="this.src='assets/img/no-image.png'" style="height:150px; width:150px">
</div>
<div class="form-group">
<input formControlName="vehicle_image" id="vehicle_image" type="file" class="form-control" accept=".jpg,.jpeg,.bmp,.png,.gif,.svg" (change)="onSelectFile($event)">
<div *ngIf="fc.vehicle_image.touched && fc.vehicle_image.invalid">
<div *ngIf="fc.vehicle_image.hasError('extension')">
<div class="text-danger">
Enter valid File Type!
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-success" [disabled]="isLoading" class="btn btn-success" (click)="editValidate()">
<span *ngIf="isLoading" class="spinner-border spinner-border-sm mr-1"></span>
<i class="fa fa-save" aria-hidden="true"></i> Save</button>
</div>
</form>
</div>
While trying to retrieve and view the data before I eventually update, I got this error:
ERROR TypeError: Cannot read properties of undefined (reading 'vehicle_image') at VehicleEditComponent_Template (vehicle-edit.component.html:245)
It highlights this page:
[src]="vehicledata.vehicle_image ? vehicleImageDirectoryPath vehicledata.vehicle_image : urlVehicle || 'assets/img/no-image.png'"
But the registration_number was displayed. vehicle_image exists. Could it be because the image is null?
How do I resolve this?
Thanks
CodePudding user response:
I think the issue here is with vehicledata
, it is undefined
and you are unable to read any property on it.
You can use optional chaining operator
in the html which I have added in the below code:
<div class="text-center">
<img class="profile-user-img img-fluid img-circle" [src]="vehicledata?.vehicle_image ? vehicleImageDirectoryPath vehicledata.vehicle_image : url || 'assets/img/no-image.png'" alt="No Vehicle Image" one rror="this.src='assets/img/no-image.png'" style="height:150px; width:150px">
</div>
Another way could be to add the *ngIf
directive to only show the image tag if vehicledata
is available. I'm not sure this will work for you as I can see you have already added no-image
url.
CodePudding user response:
Your vehicledata
is initialized only inside loadVehicleById
method, but template is used without any *ngif
annotation to prevent variable use before it initialized.
You can at least extend your SRC interpolation expression to include null check:
[src]="(vehicledata && vehicledata.vehicle_image) ? vehicleImageDirectoryPath vehicledata.vehicle_image : url || 'assets/img/no-image.png'" alt="No Vehicle Image" one rror="this.src='assets/img/no-image.png'"