Update on array change - arrays

if I add an object to the objectListDrawArea array outside of the original class, it will be added, but my * ngFor cannot find the object. I have absolutely no idea how to solve it, should I use Observable, if so can you leave an example in the comments? Thank you
ao-bar.component.ts
import { AoBarService } from './ao-bar.service';
import { DrawAreaComponent } from '../../../draw-area/draw-area/draw-area.component';
#Component({
selector: 'app-ao-bar',
templateUrl: './ao-bar.component.html',
styleUrls: ['./ao-bar.component.sass']
})
export class AoBarComponent implements OnInit {
objectsList: object[] = new Array();
showObjectsList: boolean;
drawAreaComponent: DrawAreaComponent = new DrawAreaComponent();
constructor(private service: AoBarService) {
this.service.getObject(this.objectsList);
}
ngOnInit() {
console.log(this.objectsList, ' AoBarComponent');
}
private onShowObjectsList() {
this.showObjectsList = !this.showObjectsList;
}
public onDragEnd(event: DragEvent): void {
console.log('drag end', event);
if (this.drawAreaComponent.onDragEnter) {
for (let object of this.objectsList) {
if (object.name == event.path[0].nextElementSibling.innerText) {
object.settings.x = event.x;
object.settings.y = event.y;
this.drawAreaComponent.createObject(object);
}
}
}
}
}
draw-area.component.ts:
import { Component, OnInit } from '#angular/core';
import { CdkDragEnd } from '#angular/cdk/drag-drop';
#Component({
selector: 'app-draw-area',
templateUrl: './draw-area.component.html',
styleUrls: ['./draw-area.component.sass']
})
export class DrawAreaComponent implements OnInit {
objectsList: object[] = new Array();
constructor() {
}
ngOnInit() {
}
public onDragEnter(event: DragEvent): boolean {
console.log('drag enter', event);
return true;
}
public onDragEnd(event: CdkDragEnd): void {
console.log(event);
}
public createObject(objectToCreate: object): void {
this.objectsList.push(objectToCreate);
console.log(`Aktuelle Liste: ${this.objectsList}`);
}
}
draw-area.component.html :
<div id="DrawAreaComponent">
<div
class="example-boundary"
(dragenter)="onDragEnter($event)"
>
<div
id="ContainerObject"
*ngFor="let object of objectsList | async"
cdkDragBoundary=".example-boundary"
cdkDrag
(cdkDragEnded)="onDragEnd($event)"
>
<img id="ImgObject" [src]="object.imgUrl">
</div>
</div>
</div>

this is a change detection issue.
instead of this.objectsList.push(objectToCreate);
use this.objectsList = [...this.objectsList, objectToCreate]; it will work.
read about change detection.

Related

Angular service for obtain pointguards (position === 1)

Currently i'm developing a web app which shows the Golden State Warriors (Basketball Team) Roster.
My main goal consists in filtering all players by position.
Positions are numbers ordered from 1 to 5.
My question would be: which could be the way to transform my http get request in order to obtain the point-guards (position === 1) ??
roster-data.service.ts
import { Injectable } from '#angular/core';
import { Player } from "../models/player";
import { environment } from "../../environments/environment";
import {HttpClient, HttpErrorResponse} from '#angular/common/http';
import {Observable, throwError} from 'rxjs';
import {catchError, map, filter } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class RosterDataService {
private readonly devURL = environment.url;
constructor(private http: HttpClient) {
}
jSON_Server_ReadPointGuards():Observable<Player[]> {
return this.http.get<Player[]>(`${this.devURL}/roster_GoldenStateWarriors`).pipe(
map(players => players.filter((player:Player) => player.position === 1)
),
catchError(this.handleError)
);
}
And then my interface
player.ts
export interface Player {
fullName: string,
shirtNumber: string,
position: number,
height: string,
weight: number,
points: number,
rebounds: number,
assists: number,
blocks: number,
steals: number,
imageFile: string,
imageDescrip: string
}
players.component.ts
import { Component, OnInit, isDevMode } from '#angular/core';
import { RosterDataService } from "../../services/roster-data.service";
import { Player } from "../../models/player";
import { imgRoute } from "../../services/img-route.service";
#Component({
selector: 'app-players',
templateUrl: './players.component.html',
styleUrls: ['./players.component.scss'],
providers: [RosterDataService]
})
export class PlayersComponent implements OnInit {
public imageLocation:string;
public bases!: Player[];
public escoltas!: Player[];
public aleros!: Player[];
public alaPivots!: Player[];
public pivots!: Player[];
public getPlayers: Player[] = [];
constructor(private _rosterDataService: RosterDataService) {
this.imageLocation = imgRoute.path;
}
ngOnInit(): void {
this.dev_SuscribeAllPointGuards();
// this.dev_SuscribeAllShootingGuards();
// this.dev_SuscribeAllSmallForwards();
// this.dev_SuscribeAllPowerForwards();
// this.dev_SuscribeAllCenters();
}
dev_SuscribeAllPointGuards(){
this._rosterDataService.jSON_Server_ReadPointGuards().subscribe(
pointguards => {
this.bases = pointguards;
}
);
}
}
players.component.html
<section>
<article>
<h4 id="pointGuard">{{ "players.firstTitle" | translate }}</h4>
<div class="gallery">
<div [routerLink]="'/'+(base.fullName | removespaces)+'/'+base.shirtNumber" *ngFor="let base of bases;">
<figure><img src="{{imageLocation + base.imageFile}}" alt="{{base.imageDescrip}}" title="{{base.imageDescrip}}"></figure>
<section>
<h5>{{base.fullName}}</h5>
<h6>{{base.shirtNumber}}</h6>
<h6>{{base.points}}</h6>
<h6>{{base.rebounds}}</h6>
<h6>{{base.assists}}</h6>
<h6>{{base.blocks}}</h6>
<h6>{{base.steals}}</h6>
</section>
</div>
</div>
</article>
</section>

Trying to get a unique list of objects from an array in angular

Have an observable being returned from my service.ts as shown here:
import { Injectable, ErrorHandler } from '#angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders } from
'#angular/common/http'
import { Observable } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { PokeResponse } from '../PokeResponse';
#Injectable({
providedIn: 'root'
})
export class PokeApiService {
private url = "https://pokemon-go1.p.rapidapi.com/pokemon_stats.json";
constructor(private http:HttpClient) { }
getPokeData(): Observable<PokeResponse> {
return this.http.get<PokeResponse>(this.url,
{
headers : new HttpHeaders({
'x-rapidapi-key': 'a6cef4cbcamsh05b29346394d4a4p1bafacjsn2a92406ac103'
})
})
.pipe(
tap(data => console.log('Pokedata/Error' + JSON.stringify(data))
),
catchError(this.handleError)
);
}
private handleError(err:HttpErrorResponse) {
console.log('PokemonService: ' + err.message);
return Observable.throw(err.message);
}
}
This is my response:
export interface PokeResponse{
list:results[];
results:{
pokemon_id:number;
pokemon_name:string;
base_attack:number;
base_defense:number;
base_stamina:number;
}[];
}
export interface results{
pokemon_id:number;
pokemon_name:string;
base_attack:number;
base_defense:number;
base_stamina:number;
}
export class Pokemon implements results{
pokemon_id:number;
pokemon_name:string;
base_attack:number;
base_defense:number;
base_stamina:number;
constructor(_id:number, _name:string, _atk:number, _def:number, _stam:number) {
_id = this.pokemon_id;
_name = this.pokemon_name;
_atk = this.base_attack;
_def = this.base_defense;
_stam = this.base_stamina;
}
}
And this is my component.ts:
import { Component, OnInit } from '#angular/core';
import { PokeApiService } from 'src/app/services/poke-api.service';
import { PokeResponse, results, Pokemon } from 'src/app/PokeResponse';
import { Observable } from 'rxjs';
#Component({
selector: 'app-list-pokemon',
templateUrl: './list-pokemon.component.html',
styleUrls: ['./list-pokemon.component.css']
})
export class ListPokemonComponent implements OnInit {
constructor(private pokeService: PokeApiService) { }
ngOnInit(): void {
this.getPokeDetails();
}
pokeData:PokeResponse;
errorMessage:any;
pokeArray:results;
getPokeDetails() : boolean {
this.pokeService.getPokeData().subscribe(
pokeData => {
this.pokeData=pokeData;
console.table(pokeData);
},
error => this.errorMessage = <any>error
);
return false;
}
}
In my console I'm getting back a console.table of my observable like this
I'm trying to filter out the names of Pokemon which are the same as others, which could also be achieved by just filtering out any of the pokemon_ids as all the stats match regardless of the type.
So far I've tried:
console.log(this.pokeArray);,
using [...Set()], forEach(), and Array.from()
Any help or suggestions on how I can make this question any clearer would be greatly appreciated.
Try this, using filter:
// list-pokemon.component.ts
export class ListPokemonComponent implements OnInit {
uniqueListPoke = [];
flags = {};
constructor(private pokeService: PokeApiService) { }
ngOnInit(): void {
this.getPokeDetails();
}
pokeData:PokeResponse;
errorMessage:any;
pokeArray:results;
getPokeDetails() : boolean {
this.pokeService.getPokeData().subscribe(
pokeData => {
this.uniqueListPoke = pokeData.filter((entry) => {
if (this.flags[entry.pokemon_name]) {
// console.log('flags', false);
return false;
}
this.flags[entry.pokemon_name] = true;
return true;
});
console.log(JSON.stringify(this.uniqueListPoke));
},
error => this.errorMessage = <any>error
);
return false;
}
}
The working example:
https://stackblitz.com/edit/angular-distinct-poke?file=src/app/hello.component.ts

Angular2 Array objects

I would like to add in an array of objects, but it does not work: Can not set property '0' of undefined
I try to put in this.positions [0] = the PositionMap object
I have decreased the size of the code for better readability, but the rest works
Here is my code:
import { Component, ViewChild, ElementRef } from '#angular/core';
import { NavController } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { Geolocation } from 'ionic-native';
declare var google;
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
positions: PositionMap[] = [];
#ViewChild('map') mapElement: ElementRef;
constructor(public navCtrl: NavController) {
this.positions = [];
}
ionViewDidLoad(){
this.loadMap();
this.autocomplete();
}
autocomplete() {
autocompleteDepart.addListener('place_changed', function() {
var place = autocompleteDepart.getPlace();
let tmpPosition = new PositionMap(place.geometry.location.lat(), place.geometry.location.lng());
this.positions[0] = (tmpPosition);
return;
});
}
}
export class PositionMap {
latitude: number;
longitude: number;
constructor(_latitude: number, _longitude: number) {
this.latitude = _latitude;
this.longitude = _longitude;
}
}
My table is well declared in the class and in the constructor, but yet is not known in the function.
You're using this from a callback function. This callback function must first be bound to this. The easiest way is to use an arrow function:
autocompleteDepart.addListener('place_changed', () => {
...
});

Angular 2 make a second emit, when first completes

We've started migrating from ng1 to ng2, but I don't understand how to upgrade my button component. For example:
In angular 1, I can pass a promise inside of a component and wait response, like:
class ButtonController {
click: () => Promise<any>;
form: SomeForm;
onClick(): void {
this.click().then(() => {
this.form.doSomething();
});
}
}
export const ButtonComponent = {
templateUrl: 'button-component.template.html',
controller: ButtonController,
controllerAs: 'vm',
require: '^form',
bindings: {
click: '&'
}
});
But, how can I achive this in angular 2 with #Output and EventEmitter? I've achived this with #Input, callback from component and a service between ButtonComponent and FormComponent, but I'm sure it's totally wrong. Will be glad of any help. Thanks.
angular 2 code:
sign-up.template.html
// content
<ab-form [uFormGroup]="signUpForm">
//content
<ab-button [uClick]="onClick"></ab-button>
</ab-form>
sign-up.component.ts
export class SignUpComponent {
onClick = () => {
//do something async
}
}
form.component.ts
#Component({
selector: "ab-form",
template: require("./form.template.html"),
providers: [
FormService
]
})
export class FormComponent {
#Input() uFormGroup: FormGroup;
constructor(
private formService: FormService
) {
this.formService.buttonClicked$.subscribe((fn) => {
this.uFormGroup['submitted'] = true;
if (this.uFormGroup.invlaid) {
return this.formService.endSubmittingForm();
}
this.formService.startSubmittingForm();
// resolve if function is not a promise
Promise.resolve(fn()).then(() => {
this.formService.endSubmittingForm();
});
});
}
}
button.component.ts
export class ButtonComponent {
submitting = false;
constructor(
private formService: FormService
) {
this.formService.formSubmitting$.subscribe(() => {
this.submitting = true;
});
this.formService.formSubmitted$.subscribe(() => {
this.submitting = false;
});
}
onClick(): void {
this.formService.buttonClick(this.uClick);
}
}
form.service.ts
export class FormService {
private buttonClickedSource = new Subject<Function>();
private formSubmittingSource = new Subject<void>();
private formSubmitedSource = new Subject<void>();
buttonClicked$ = this.buttonClickedSource.asObservable();
formSubmitting$ = this.formSubmittingSource.asObservable();
formSubmited$ = this.formSubmitedSource.asObservable();
buttonClick(fn: Function): void {
this.buttonClickedSource.next(fn);
}
startSubmittingForm(): void {
this.formSubmittingSource.next();
}
endSubmittingForm(): void {
this.formSubmitedSource.next();
}
}
You can create simple Component Inputs and Outputs like this:
#Component({
selector: 'myButton',
template: '<button (click)="buttonAction()">{{label}}</button>',
inputs: ['label']
})
export class MyButton {
#Input()
label:string;
#Output()
myButtonClick = new EventEmitter<any>();
...
buttonAction() {
this.tableButtonClick.emit("some value")
}
}
and then use it in your templates like this:
<myButton [label]="sample"
(myButtonClick)="handleMyButtonClick($event)">
</myButton>
$event will be string "some value", but you can use any object you like
You can do the same as you done with Angular 1, using Observer :
onClick(): void {
this.formService.buttonClick().subscribe(() => {
// You reach this when buttonClick is async terminated
// like your then() in your Angular 1 code
this.uClick()
...
});
}
And in your FormService you return the Observable :
buttonClick(): Observable<any> {
return this.buttonClicked$;
}

while retrieving passed array got from json in the second component,i am getting [object Object]

This is the first component where i am pushing those things into array named items and i am trying to get it in the second component through service
import { Component } from '#angular/core';
import { FormBuilder, FormControl } from '#angular/forms';
import {AppService} from '../second/app.service';
import { Router } from '#angular/router';
import { Http,Response } from '#angular/http';
import { routing, appRoutingProviders } from '../app.route';
import { Validators } from '#angular/forms';
import {BrowserModule} from '#angular/platform-browser';
#Component({
selector: 'first-app',
templateUrl:"../app/src/component/first/app.firstpage.html"
})
export class FirstComponent
{
data:any;
public items=[];
public edited=false;
public city=false;
public dateCon=false;
inputForm: FormGroup;
Select: FormControl;
Selectt: FormControl;
dat:FormControl;
constructor(private appservice:AppService,builder: FormBuilder, router:Router)
{
this.appservice.getData().subscribe(res=>{this.data=res.json()});
console.log(this.data);
this.Select = new FormControl('', [
Validators.required
]);
this.Selectt = new FormControl('', [
Validators.required
]);
this.dat = new FormControl('', [
Validators.required
]);
this.inputForm = builder.group({
Select: this.Select,
Selectt: this.Selectt,
dat: this.dat
});
this.router=router;
this.appservice=appservice;
}
ngOnInit(){
this.appservice.getData()
}
onclick(a,b) {
console.log(this.data);
let sel1=this.inputForm.value.Select;
let sel2=this.inputForm.value.Selectt;
let sel3=this.inputForm.value.dat;
console.log(sel3);
console.log(sel1);
console.log(sel2);
console.log(this.data.bus.length);
for(let i=0;i<this.data.bus.length;i++){
if((this.data.bus[i].from==sel1)&&(this.data.bus[i].to==sel2))
{
this.items.push(this.data.bus[i]);
}
}
this.appservice.setData(this.items);
}
if((sel1!="")&&(sel2!="")&&(sel3!="")&&(sel1!=sel2))
{
this.router.navigate(['/sec-component']);
}
else if((sel1=="")&&(sel2=="")&&(sel3==""))
{
this.edited=true;
}
if((sel1==sel2)&&((sel1!="")&&(sel2!="")))
{
this.edited=false;
this.city=true;
}
else
{
this.city=false;
}
if(sel1!=sel2)
{
this.edited=false;
}
if(sel3=="")
{
this.dateCon=true;
}
else
{
this.dateCon=false;
}
}
}
This is the second component to which i am passing this array and i need to get that printed over there and each properties to be accessed rather than the entire stuff.
import { Component } from '#angular/core';
import {AppService} from '../first/first.service';
#Component({
template:
`
<h1>second component</h1>
<h1>second component</h1>
<p >{{myName}}</p>
`
})
export class SecondComponent {
constructor(private appservice: AppService)
{
this.appservice=appservice;
this.myName=appservice.getVal();
}
}
This is the service page where i am returning the values
import {Component, Injectable,Input,Output,EventEmitter} from '#angular/core'
import { Http, Response } from '#angular/http';
export interface myData
{
name:any;
}
#Injectable()
export class AppService
{
sharingData: myData={name:""};
constructor(private http:Http){ }
getData()
{
return this.http.get('./app/src/component/busDet.json')
}
setData(i)
{
console.log('save data function called' + i + this.sharingData.name);
this.sharingData.name=i;
console.log(this.sharingData.name);
}
getVal()
{
console.log(this.sharingData.name);
return this.sharingData.name;
}
}
I am getting the output as object.object
I am not able to get the values with in the JSON in the next component.

Resources