Problem in angular when I want recover informations of array - html

I have a problem with my angular code.
This is the code in my animal.component.ts :
import { Component, OnInit } from '#angular/core';
import { AnimalService } from "./animal.service";
import { Animal } from "./animal";
#Component({
selector: 'app-animal',
templateUrl: './animal.component.html',
styleUrls: ['./animal.component.css']
})
export class AnimalComponent implements OnInit {
private animaux:Array<Animal>;
private especeAnimalPresente:Array<string>;
constructor(private animalService: AnimalService) { }
ngOnInit() {
this.recupAllAnimals();
this.recupEspecePresent();
}
recupAllAnimals(){
this.animalService.getAllAnimaux().subscribe(
data => {console.log(this.animaux), this.animaux = data, console.log(this.animaux)}
)
}
recupEspecePresent(){
for (let animal of this.animaux) {
}
}
}
But I have this error in my console :
ERROR TypeError: "this.animaux is undefined"
recupEspecePresent animal.component.ts:28
ngOnInit animal.component.ts:18
Angular 5
View_AnimalComponent_Host_0 (index):1
Angular 26
RxJS 5
Angular 11
I don't understand this problem especially that my array animaux contains many animals. And I display this array in my html code.
This is ma web page :

Data for this.animaux are fetched asynchronously and there is no guarantee that your recupEspecePresent is called after the data are fetched. You should run that function after the fetching is done:
ngOnInit(): void {
this.recupAllAnimals();
}
recupAllAnimals(): void {
this.animalService.getAllAnimaux().subscribe(data => {
this.animaux = data;
this.recupEspecePrsent();
})
}
recupEspecePresent(): void {
for (let animal of this.animaux) {
// do something
}
}

Related

Angular 'Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.'

I'm creating an Angular app which shows list of projects and list of users from postgresql database, but I'm having issues with showing list of users in html.
The problem is that Angular is considering my array as an object no matter what I do.
The same code worked for projects but didn't work for users.
This is my service:
import { environment } from "../../../environments/environment";
import { Observable } from 'rxjs';
import { Projet } from '../modele/projet.model';
import { Test } from '../modele/test.model';
import { HttpParams,HttpClient } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { map } from 'rxjs/operators';
import { User } from '../modele/user.model';
import { Financement } from '../modele/financement.model';
#Injectable()
export class WebService {
constructor(private httpClient: HttpClient) { }
serverUrl: string = "http://localhost:8080/"
get(url: string): Observable<any> {
return this.httpClient.get(this.serverUrl + url);
}
}
The component :
import { Component, OnInit } from '#angular/core';
import { User } from '../../shared/modele/user.model';
import { Router } from '#angular/router';
import { WebService } from '../../shared/sevices/web.service';
import { FormGroup, FormBuilder, FormControl, Validators, Form } from '#angular/forms';
#Component({
selector: 'app-show-users',
templateUrl: './show-users.component.html',
styleUrls: ['./show-users.component.scss']
})
export class ShowUsersComponent implements OnInit {
ngOnInit(): void {
this.getData();
}
usersList: Array<User>
user: User
myForm: FormGroup;
constructor(private webService: WebService, private formBuilder: FormBuilder,private router: Router) { }
getData(): void {
this.webService.get("showUsers").subscribe(res => {
let response = JSON.parse(JSON.stringify(res))
this.usersList = response.data
})
}
}
The html :
<tr *ngFor="let user of usersList">
<td>{{user.name}}</td>
<td>{{user.username}}</td>
<td>{{user.email}}</td>
</tr>
This is the server response :
server response
NB: the EXACT same code worked for the object PROJECT
You need to make sure that the variable you pass into *ngFor is an array. You can make sure of this with Array.from(v) and can also strip any keys of an Object that might be sent from the serverside with Object.values(v):
this.webService.get("showUsers").subscribe(res => {
this.usersList = Array.from(Object.values(res.data.body.data));
})
In my case, I have a simple approach, but I spent a lot of time. You could try this:
datas: any;
this.token = JSON.parse(window.localStorage.getItem('token'));
this.authService.getData(this.token.id).subscribe(data => {
this.datas = data;
})
In the HTML template just use this.datas.id, this.datas.username instead of an *ngFor
You don't need this code:
let response = JSON.parse(JSON.stringify(res))
this.usersList = response.data
simply use:
this.userlist = res
Youe complete method:
this.webService.get("showUsers").subscribe(res => {
this.userlist = res
});

Angular 9 data from api call isn't populating dropdown

Having some problems with filling my drop down menu with data from my API. I need help figuring out what I am doing wrong because I am getting no errors in the console.
Service.ts method call:
#Injectable({
providedIn: 'root'
})
export class OrderExceptionReportService extends ApiServiceBase {
private apiRoute: string = 'exception-report';
public sessionData: ExceptionReportSessionData[];
constructor(http: HttpClient, configService: ConfigService) {
super(http, configService);
}
public async GetExceptionReportSessionData(): Promise<ExceptionReportSessionData[]> {
if (!this.appSettings) {
this.appSettings = await this.configService.loadConfig().toPromise();
}
return await this.http.get<ExceptionReportSessionData[]>(this.appSettings.apiSetting.apiAddress + this.apiRoute + '/session-data')
.pipe(
retry(1),
catchError(this.handleError)
)
.toPromise()
}
}
component.ts file:
#Component({
selector: 'app-order-exception-report',
templateUrl: './order-exception-report.component.html',
styleUrls: ['./order-exception-report.component.scss']
})
export class OrderExceptionReportComponent implements OnInit {
public sessionData: ExceptionReportSessionData[];
constructor(private orderExceptionReportService: OrderExceptionReportService) {
}
getExceptionReportSessionData() {
this.orderExceptionReportService.GetExceptionReportSessionData()
.then(
data => {
this.sessionData = data;
});
}
ngOnInit() {
}
}
html where I need the data:
<div class="input-group">
<select class="custom-select" id="inputGroupSelect01">
<option value="" *ngFor="let session of sessionData">{{session.SessionName}}</option>
</select>
</div>
Interface.ts file:
export interface ExceptionReportSessionData {
SessionName: string,
ReportFiles: Array<string>
}
From your comments, it appears the this.configService.loadConfig() returns an HTTP observable as well.
In that case, you could avoid using promises and streamline the process using RxJS method iff to check if the this.appSettings variable is defined and switchMap operator to switch to the target request once appSettings is retrieved.
Try the following
public GetExceptionReportSessionData(): Observable<ExceptionReportSessionData[]> {
return iff(() =>
this.appSettings,
of(this.appSettings),
this.configService.loadConfig().pipe(tap(appSettings => this.appSettings = appSettings))).pipe(
switchMap(appSettings => this.http.get<ExceptionReportSessionData[]>(appSettings.apiSetting.apiAddress + this.apiRoute + '/session-data')),
retry(1),
catchError(this.handleError)
);
}
tap operator is used to tap into the result and store it into this.appSettings variable. of method is used to send an observable of this.appSettings since switchMap operator expects an observable.
You could then subscribe to the function in the component
export class OrderExceptionReportComponent implements OnInit {
public sessionData: ExceptionReportSessionData[];
constructor(private orderExceptionReportService: OrderExceptionReportService) {}
getExceptionReportSessionData() {
this.orderExceptionReportService.GetExceptionReportSessionData().subscribe(
data => { this.sessionData = data; },
error => { }
);
}
ngOnInit() {
this.getExceptionReportSessionData();
}
}

Problem withAngular when I want to add elements in array

I have an animals array. I want to put in another array just the field "espece" of each animal.
I push all the espece of animals in especeAnimalPresenteTmp and then I remove the duplicates and save the next array in especeAnimalPresente.
I have this angular code :
import { Component, OnInit } from '#angular/core';
import { AnimalService } from "./animal.service";
import { Animal } from "./animal";
#Component({
selector: 'app-animal',
templateUrl: './animal.component.html',
styleUrls: ['./animal.component.css']
})
export class AnimalComponent implements OnInit {
private animaux:Array<Animal>;
private especeAnimalPresente:Array<string>;
private especeAnimalPresenteTmp:Array<string>;
constructor(private animalService: AnimalService) { }
ngOnInit() {
this.recupAllAnimals();
}
recupAllAnimals(){
this.animalService.getAllAnimaux().subscribe(data => {
this.animaux = data;
this.recupEspecePresent();
})
}
recupEspecePresent(){
// if (this.animaux){
for (let animal of this.animaux) {
this.especeAnimalPresenteTmp.push(animal.espece);
}
this.especeAnimalPresente = this.removeDuplicates(this.especeAnimalPresenteTmp);
// }
}
removeDuplicates(array) {
let unique = {};
array.forEach(function(i) {
if(!unique[i]) {
unique[i] = true;
}
});
return Object.keys(unique);
}
}
But I have this error in my console :
ERROR TypeError: "this.especeAnimalPresenteTmp is undefined"
recupEspecePresent animal.component.ts:32
recupAllAnimals animal.component.ts:24
RxJS 11
Angular 8
Someone can help me please ?
You have to initialize the array, for example in the constructor:
constructor(private animalService: AnimalService) {
this.especeAnimalPresenteTmp = [];
}

Angular 2/4 - Can't resolve all parameters for GameEditComponent: ([object Object], [object Object], ?)

I am developing the services of my application, but when I try to load the page it shows the following error:
Can't resolve all parameters for GameEditComponent: ([object Object],
[object Object], ?).
I tried in the service to put as an array or just leave any, but even then the error continued
game-edit.service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs';
#Injectable()
export class GameEditService {
constructor(private http: Http) { }
getGame(id): Observable<any> {
return this.http.get('http://localhost:8080/lightning/api/game' + id).map(res => res.json()).catch(error => {
throw new Error(error.message);
});
}
getManufactures(): Observable<any> {
return this.http.get('http://localhost:8080/lightning/api/manufacture').map(res => res.json()).catch(error => {
throw new Error(error.message);
});
}
getPlatforms(): Observable<any> {
return this.http.get('http://localhost:8080/lightning/api/platform').map(res => res.json()).catch(error => {
throw new Error(error.message);
});
}
}
game-edit.component.ts
import { ActivatedRoute, Params } from '#angular/router';
import { Component, OnInit } from '#angular/core';
import { GameEditService } from './game-edit.service';
#Component({
moduleId: module.id,
selector: 'app-game-edit',
templateUrl: './game-edit.component.html',
styleUrls: ['./game-edit.component.css', '../styles.css' ]
})
export class GameEditComponent implements OnInit {
constructor(private activatedRoute: ActivatedRoute, private gameEditService: GameEditService, private id) {
this.gameEditService.getPlatforms().subscribe(platforms => {
console.log(platforms);
}), erro => console.log(erro);
this.gameEditService.getManufactures().subscribe(manufactures => {
console.log(manufactures);
}), erro => console.log(erro);
}
ngOnInit() {
this.activatedRoute.params.subscribe((params: Params) => {
this.id = params['id'];
console.log(this.id);
});
this.gameEditService.getGame(this.id).subscribe(game => {
console.log(game);
}), erro => console.log(erro);
}
onSubmit(form){
console.log(form);
}
verificaValidTouched(campo){
return !campo.valid && campo.touched;
}
aplicaCssErro(campo){
return {
'subError': this.verificaValidTouched(campo)
}
}
}
This is the json that is coming, the first is for a selected game, the second is for the platforms and the third is for the manufacturers
json game selected
{
"id":1,
"name":"Street Fighter",
"category":"luta",
"price":20.5,
"quantity":1000,
"production":true,
"description":"descricao",
"image":"ps4.jpg",
"manufacture":
{
"id":1,
"name":"Sony",
"image":"ps4.jpg",
"imageFullPath":"http://localhost:8080/lightning/images/ps4.jpg"
}
}
json platforms
{
"id":1,
"name":"PC",
"image":"ps4.jpg",
"imageFullPath":"http://localhost:8080/lightning/images/ps4.jpg"
}
json manufactures
{
"id":1,
"name":"Sony",
"image":"ps4.jpg",
"imageFullPath":"http://localhost:8080/lightning/images/ps4.jpg"
}
Console
I'm using angular cli with with all packages in the most current versions.
I do not know if maybe this error is because of the platforms you have inside the game, or some other code problem, if you know something that could do to repair, I tried several solutions that I found through the internet, but none worked.
Thanks in advance.
The problem is the last argument in the component's constructor, private id. Angular will try to resolve this dependency, but can't find an injectable class for id. When looking at the code, I think there is no need to inject id into the constructor. Just define it as a property on your component:
// ... import statements
#Component({
moduleId: module.id,
selector: 'app-game-edit',
templateUrl: './game-edit.component.html',
styleUrls: ['./game-edit.component.css', '../styles.css' ]
})
export class GameEditComponent implements OnInit {
private id; // put the declaration of id here
// remove id declaration from the constructor, no need to inject it
constructor(private activatedRoute: ActivatedRoute,
private gameEditService: GameEditService) { // ...constructor code}
// other code
}
I solved it otherwise: My problem was that the HttpClient has a rare condition, it's not the same "import" line on the component that on the app.module...
On the Component is this:
import { HttpClient } from '#angular/common/http';
in app module is this:
import { HttpClientModule } from '#angular/common/http';

How can I sanitize css properties to use in template given from a data service

I need to generate sanitized css property to use with my component template to set the background image of the div:
<div *ngFor="let Item of Items"
[style.background-image]="Item.imageStyle
(click)="gotoDetail(Item.iditems)">
</div>
using data obtained through a data service. The component is:
import { Component } from '#angular/core';
import { Router } from '#angular/router';
import { DomSanitizer } from '#angular/platform-browser';
import { OnInit } from '#angular/core';
import { Item } from '../models/Item';
import { CollectionDataService } from '../services/CollectionData.service';
#Component({
selector: 'mainpage',
templateUrl: 'app/mainpage/mainpage.component.html',
styleUrls: ['app/mainpage/mainpage.component.css']
})
export class MainpageComponent implements OnInit {
Items: Item[];
ngOnInit() {
this.collectionDataService.getItems().subscribe(
Items => this.Items = Items
);
// Generates and sanitizes image links
this.Items.map(
(LItem) => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)")
)
}
constructor(
private router: Router,
private sanitizer: DomSanitizer,
private collectionDataService: CollectionDataService
) {
}
gotoDetail($iditems: number): void {
this.router.navigate(['/viewer', $iditems]);
}
}
But it doesn't work because the statement that generates the sanitized property
this.Items.map(
(LItem) => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)")
)
doesn't find the loaded data. The error that I'm seeing in the browser console is:
core.umd.js:3070 EXCEPTION: Uncaught (in promise): Error: Error in ./MainpageComponent class MainpageComponent_Host - inline template:0:0 caused by: Cannot read property 'map' of undefined
TypeError: Cannot read property 'map' of undefined
The data service is:
import { Injectable } from '#angular/core'
import { Http } from '#angular/http'
import { Item } from '../models/Item';
import { DomSanitizer } from '#angular/platform-browser';
#Injectable()
export class CollectionDataService {
constructor(
private http: Http,
private sanitizer: DomSanitizer
) { }
getItems() {
return this.http.get('app/mocksdata/items.json').map(
response => <Item[]>response.json().items
)
}
}
And the provided items.json:
{
"items": [{
"iditems": 1,
"imageStyle": ""
}, {
"iditems": 2,
"imageStyle": ""
}]
}
If I set static data in the component, instead of using the data service, everything works:
export class MainpageComponent implements OnInit {
Items: Item[];
ngOnInit() {
this.Items = [{
"iditems": 1,
"imageStyle": ""
}, {
"iditems": 2,
"imageStyle": ""
}]
// Generates and sanitizes image links
this.Items.map(
(LItem) => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)")
)
}
How can I force the sanitizer statement to wait that the async data are fully loaded? Alternatively how can I generate sanitized properties directly in the service?
EDIT
The best answer comes from PatrickJane below:
Items: Item[] = [];
ngOnInit() {
this.collectionDataService.getItems().subscribe(Items => {
this.Items = Items;
this.Items.map(LItem => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)"))}
});
}
I also solved this problem working directly in the service method (credits), but it is more verbose:
return this.http.get('app/mocksdata/items.json')
.map( (responseData) => {
return responseData.json().items;
})
.map(
(iitems: Array<any>) => {
let result:Array<Item> = [];
if (iitems) {
iitems.forEach((iitem) => {
iitem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+iitem.iditems+".jpg)");
result.push(<Item>iitem);
});
}
return result;
}
)
The subscribe function is async so your map function called before the subscribe function run. So in this phase the array is undefined because you doesn't set any initial value.
The solution is to do this inside the subscribe function and to initialize the Items with empty array.
Items: Item[] = [];
ngOnInit() {
this.collectionDataService.getItems().subscribe(Items => {
this.Items = Items;
this.Items.map(LItem => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)"))}
});
}