Problem withAngular when I want to add elements in array - html

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 = [];
}

Related

Type 'null' is not assignable to type 'string'

Getting error
Type 'null' is not assignable to type 'string'
in
this.localItem = localStorage.getItem("todos");
When trying to resolve by using
this.localItem = JSON.parse(localStorage.getItem("todos") || '{}');
the entire component of webpage is getting blank. This is for preparing a to do list and auto adding to do items and removing todo items by adding to local storage.
import { Component, OnInit } from '#angular/core';
import { Todo } from 'src/app/Todo';
#Component({
selector: 'app-todos',
templateUrl: './todos.component.html',
styleUrls: ['./todos.component.css']
})
export class TodosComponent implements OnInit {
localItem: string;
todos:Todo[];
constructor() {
this.localItem = localStorage.getItem("todos");
if(this.localItem == null){
this.todos = [];
}
else{
this.todos = JSON.parse(this.localItem);
}
this.todos =[]
}
ngOnInit(): void {
}
deleteTodo(todo:Todo){
console.log(todo)
const index = this.todos.indexOf(todo);
this.todos.splice(index,1)
localStorage.setItem("todos", JSON.stringify(this.todos));
}
addTodo(todo:Todo){
console.log(todo);
this.todos.push(todo);
localStorage.setItem("todos", JSON.stringify(this.todos));
}
}
```
Since your assigning a local storage value to the object in todos[] it might return object of arrays so try [] while parsing object of arrays.
export class TodosComponent implements OnInit {
localItem: string ;
todos:Todo[];
constructor() {
this.localItem = localStorage.getItem("todos"||"[]");
if(this.localItem == null){
this.todos = [];
}
else{
this.todos = JSON.parse(this.localItem );
}
this.todos =[]
}
}
import { Component, Input, OnInit } from '#angular/core';
import { Todo } from '../../Todo';
#Component({
selector: 'app-todos',
templateUrl: './todos.component.html',
styleUrls: ['./todos.component.css']
})
export class TodosComponent implements OnInit {
localItem: any;
#Input() todo:Todo;
todos:Todo[];
dataSource: any;
constructor() {
this.localItem = localStorage.getItem("todos");
if(this.localItem == null){
this.todos= [];
}
else{
this.todos = JSON.parse(this.localItem)
}
}
ngOnInit(): void {
}
deleteTodo(todo:Todo) {
console.log(todo);
const index = this.todos.indexOf(todo);
this.todos.splice(index, 1);
localStorage.setItem("todos", JSON.stringify(this.todos));
}
addTodo(todo:Todo) {
console.log(todo);
this.todos.push(todo);
localStorage.setItem("todos", JSON.stringify(this.todos));
}
}

Problem in angular when I want recover informations of array

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
}
}

Nativescript/angular listpicker does not show array list

I am trying to get JSON data from server and then output the data in Nativescript Listpicker.I am also using Angular Here is the code.The problem is I cannot see the items displayed in the Listpicker.A service is being used to make an http request to the server. A subscription is used to get the data from the service. I have a play example below.I would like to know what I am doing wrong. Is it the event binding ?
JSON from server
[{'name':potato},{'name':berries}]
.ts file
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from "#angular/core";
import { EventData} from 'tns-core-modules/data/observable';
import { RouterExtensions } from "nativescript-angular/router";
import { BehaviorSubject, Subscription } from "rxjs";
import { request, getFile, getImage, getJSON, getString } from "tns-core-modules/http";
import { Page } from 'ui/page';
import { Output_restaurants_service } from "../services/output_restaurants.service";
#Component({
selector: "item_option",
moduleId: module.id,
templateUrl: "./item_option.component.html",
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ["./item_option.component.css"]
})
export class ItemOption implements OnInit,OnDestroy {
page:Page;
args:EventData;
isLoading: boolean;
value:any;
picked:any;
cool:any;
list =[];
arr = [];
public pokemons: Array<string>;
private curChallengeSub: Subscription;
constructor(private service_men:Output_restaurants_service,page:Page, private router: RouterExtensions){
this.pokemons = [];
}
ngOnInit(){
this.service_men.output_included_sides().subscribe(
(r)=>{
for(let x =0;x<r.length;x++){
this.arr.push(r[x]['name']);
}
this.pokemons = this.arr;
console.log("observer"+ this.pokemons);
}
);
}
public selectedIndexChanged(picker) {
console.log('picker selection: ' + picker.selectedIndex);
this.picked = this.pokemons[picker.selectedIndex];
}
public onSelectedIndexChanged(picker) {
}
ngOnDestroy(){
}
}
Service
import { Injectable } from '#angular/core';
import { Http,Response} from '#angular/http';
import { HttpClient } from '#angular/common/http';
import { BehaviorSubject } from 'rxjs';
import { map,tap,take } from "rxjs/operators";
import { Menu_i} from '~/restaurant_menu/restaurant.model';
import { Observable } from 'tns-core-modules/ui/page/page';
//import { Observable } from "rxjs";
#Injectable({providedIn:'root' })
export class Output_restaurants_service{
shopping_cart=[];
included_side_output:any;
menu_part:any;
menu_rest_items:any;
values:any
servers=[];
men:any;
menu_int= [];
outpuut_restaurants: any;
//response:string[]=[];
Restaurants:string[]=[];
countries: any[];
//http: any;
response = [];
pokemonsarray= [];
//private menuChanged = new Subject(null);
//public products: Observable<Menu[]>
private _currentChallenge = new BehaviorSubject(null);
constructor(private http:HttpClient) {
}
// sides(){
// return this._currentChallenge.asObservable();
// }
output_included_sides(){
this.included_side_output = this.http.get(`https://www.pidequehaypos.com/customer_chooses_food_type/output_specific_sides`);
return this.included_side_output;
}
add_variable_to_session(main_dish_id:string){
return this.http.post(`https://www.pidequehaypos.com/customer_chooses_food_type/store_main_dish_to_session`,{"main_dish_id":main_dish_id});
}
choose_restaurant() {
return this.http.get(`https://www.pidequehaypos.com/customer_chooses_business/output_businesses_button`);
}
post_menu_part_selected(restaurant_number:string){
this.menu_part= this.http.post(`https://www.pidequehaypos.com/customer_chooses_food_type/output_food_type`,{"business_id":restaurant_number});
return this.menu_part;
}
output_restaurant_items(menu_part_name:string){
this.menu_rest_items = this.http.post(`https://www.pidequehaypos.com/customer_chooses_food_type/output_food_and_drink_items`,{"menu_part_name":menu_part_name});
return this.menu_rest_items;
}
public set_restaurants (Rest){
//console.log("rest res"+Rest);
if(Rest["business"]){
// for(let t=0;t<Rest["business"].length;t++){
// this.restaurants.push(Rest["business"][t]["name"]);
// }
}
}
pes(){
//return this.menu.slice();
}
output_menu_items_test(){
return this.http.get<Menu_i>('https://www.pidequehaypos.com/customer_chooses_food_type/output_food_and_drink_items').pipe(take(1),
tap(resData => {
// tslint:disable-next-line:no-unused-expression
resData;
// tslint:disable-next-line: max-line-length
console.log('response from logout server ' + JSON.stringify(resData));
})
);
}
}
html file
<ListPicker #picker
id="pickerid"
class="p-15"
[items]="pokemons"
(selectedIndexChange)="onSelectedIndexChanged($event)">
</ListPicker>
Need to use async with the service.
ngOnInit() {
let items = [];
let subscr;
this.myItems = RxObservable.create(subscriber => {
subscr = subscriber;
subscriber.next(items);
return function () {
console.log("Unsubscribe called!");
};
});
this.service_men.output_included_sides().subscribe(
(r) => {
console.log("result: ", r)
for (let x = 0; x < r.length; x++) {
items.push(r[x]['name']);
subscr.next([...items]);
}
}
);
}
<ListPicker #picker id="pickerid" class="p-15" [items]="myItems | async"
(selectedIndexChange)="onSelectedIndexChanged($event)">
</ListPicker>
working example below
https://play.nativescript.org/?template=play-ng&id=zthg0B&v=54

Loading JSON data gives undefined object in Angular 2 - asynchronous?

...component.ts:
import { Component } from '#angular/core';
import { ValgteSkolerService } from '../valgteSkoler.service';
import { DatoService } from './datoer.service';
#Component({
selector: 'kalender',
providers: [DatoService],
templateUrl: 'app/kalendervisning/html/kalender.html'
})
export class KalenderComponent {
private valgteSkoleRuter: Array<any> = [];
public datoer: any[] = [];
constructor(private valgteSkolerService: ValgteSkolerService, private DatoService: DatoService) {
this.DatoService
.getDato()
.subscribe(datoer => { this.datoer = datoer; });
}
ngOnInit() {
this.valgteSkolerService.hentLagretData();
this.valgteSkoleRuter = this.valgteSkolerService.delteValgteSkoleRuter;
}
antallRuter: number = 0;
j: number = 0;
ukeEn(mnd: number, aar: number) :Cell[] {
var cells: Array<Cell> = [];
this.antallRuter = 0;
for (this.j = 1; this.j <= this.antallDager(mnd, aar); this.j++) {
var cell = new Cell;
console.log(this.datoer[this.j].dato);
cell.id = this.datoer[this.j].dato;
cell.text = this.j;
cells.push(cell);
this.antallRuter++;
this.j = this.j;
if (this.antallRuter % 7 == 0 && this.antallRuter != 0) {
break;
}
}
return cells;
}
class Cell {
id: string;
text: number;
}
...service.ts:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class DatoService {
dato: Array<any>;
constructor(private http: Http) {}
getDato() {
return this.http.request('app/kalendervisning/datoer.json')
.map(res => res.json());
}
}
...json:
{
"dato": "2016-08-01"
},
etc.
I am struggling with the cell.id = this.datoer[this.j].dato statement in the component.
I have checked the browser inspector, and it seems like the datoer array is undefined until the whole code has been run through several times. After a while, the array gets filled up. When I tested this with console.log, it prints 9 undefined objects, and then the actual data, but for some reason repeated 2 times also.
I think there might be a problem that the data is not loaded asynchronously, but I'm not sure.
Are there any ideas why it acts like this, and do you have a solution?
add constrctor code of calling API inside ngOnInit :
ngOnInit() {
this.DatoService
.getDato()
.subscribe(datoer => { this.datoer = datoer; });
this.valgteSkolerService.hentLagretData();
this.valgteSkoleRuter = this.valgteSkolerService.delteValgteSkoleRuter;
}

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)"))}
});
}