Angular2 handle click in parent of recursive children - recursion

I created a dynamic recursive (tree)node component which built by a json resonponse from the server. The request and response handled in tree component. I try to handle all child click event in my app. Later I like to use a child-routing which allow to load content page with the clicked node's data.
I just started to play with angular2 so let me know if you thought this is a completly wrong concept at all :)
tree.ts:
#Component({
selector: 'tree',
template: '
<div (click)="onClick($event)" class="tree">
<node *ngIf="data" [key]="key" [data]="data"></node>
</div>
',
...
})
export class TreeComponent {
key: string;
data: any;
error: any;
ngOnInit() {
this.key = 'tree';
let url = 'http://localhost:53494/api/tree';
this.http.get(url)
.map(res => res.json())
.subscribe(
value => this.data = value,
error => this.error = error);
}
...
onClick($event: any) {//This will recieves all click of all node!
$event.preventDefault();
//1. How to get the clicked node's key and data here?
//2. How to (sub/child)route to './tree/' + [node].key?
}
...
}
node.ts:
#Component({
selector: 'node',
directives: [NodeComponent], //<<< use self!
template: '
<a href="" class="node collapsed"
[attr.data-toggle]="data.node ? 'collapse' : null"
[attr.data-target]="'#' + nodePath"
aria-expanded="false" >
<span class="ident-{{level}}">
{{data.name || key}}
</span>
</a>
<div [id]="nodePath" class="tree collapse">
<node *ngFor="#nodeKey of nodeKeys"
[path]="nodePath"
[key]="nodeKey"
[level]="level+1"
[data]="data.node[nodeKey]">
</node>
</div>
'
...
})
export class NodeComponent {
#Input() key: string;
#Input() data: any;
#Input() level: number = 0;
#Input() path: string = 'node';
private nodePath: string;
private nodeKeys: Array<string>;
ngOnInit() {
this.nodePath = this.path + '-' + this.key;
if (this.data.node) {
this.nodeKeys = Object.keys(this.data.node);
}
}
}

Related

unable to render text to DOM from state vue 3

I am trying to render a name to my component, which I get from an axios response. I am able to print the name in the console but {{username}} is never updated.
setup() {
const state = reactive({
username: '',
})
const submit = async () => {
try {
const response = await api.getTest()
if (response != null) {
state.username = response.name
console.log("I am the state " + state.username)
}
} catch (error) {
console.log('Error while getting the response:', error)
}
}
return {
...state,
submit
}
},
template
<template>
<button v-on:click="submit()" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Button
</button>
<div class="text-white">
Name: {{username}}
</div>
</template>
why is the username not updating?
is this the preferred way to do this?
You are using a reactive object, so you have to use that object in the template. username is not defined in the template scope, it would be {{state.username}}.
One other approach would be to define the username as a ref, but then you have to set it's value:
const username = ref('');
And in the async function:
username.value = response.name

how to get and display ngrx store data in angular using ngFor

I am storing form data in the array in state.I am receiving the array but its in nested form .I don't know how to display it.
//view Viewcomponent.ts
customerarray: Customer[];
ngOnInit() {
// this.customerObs = this.store.select('customerList');
this.store.select<Customer[]>('customerList').subscribe(res =>
{
this.customerarray = res;
console.log(res);
console.log(this.customerarray);
});
}
//viewcomponent.html
<li *ngFor="let customer of customerarray; i as index">
<span>{{ i + 1}}.</span> {{customer.customer.name}}
</li>
//reducer.ts
import { Customer } from '../app/models/customer';
import { ADD_CUSTOMER } from '../app/store/action';
import * as CustomerAction from '../app/store/action';
const initialState = {
customer: [
new Customer('Steve', 'Yellow'),
new Customer('RDJ', 'Red')
]
};
export function CustomerReducer(state = initialState, action: CustomerAction.AddCustomer) {
console.log(state.customer);
switch (action.type) {
case CustomerAction.ADD_CUSTOMER:
return {`enter code here`
...state,
customer: [...state.customer, action.payload]
};
default:
return state;
}
}
I think that is a change detection issue.
Your component doesn't render on this subscricption.
try this -
.ts file -
customersObs:Observable<Customer[]>
constructor() {
this.customersObs = this.store.select<Customer[]>('customerList');
}
.html file -
<li *ngFor="let customer of cusomersObs | async; i as index">
<span>{{ i + 1}}.</span> {{customer.name}}
</li>
I am assuming that you Customer class is defined like this -
export class Customer {
name: string;
color: string;
constructor(n: string, c: string) {
this.name = n;
this.color = c;
}
}
I am also assuming that your selector this.store.select<Customer[]>('customerList') returns the customer property from your initialState.
If I am correct then you should update your template like this -
<li *ngFor="let customer of customerarray; i as index">
<span>{{ i + 1}}.</span> {{customer.name}}
</li>

My android app shows [object Promise] using Nativescript

I cannot show my data from my firebase on my app. I am really new to this and I don't know what to do. I can't find any solution for this on the internet.
This is my typescript code:
import { Component, OnInit } from "#angular/core";
import { ActivatedRoute, ActivatedRouteSnapshot } from "#angular/router";
import { Item } from "./item";
import { ItemService } from "./item.service";
import { EventData } from "tns-core-modules/data/observable";
import { Label } from "tns-core-modules/ui/label";
import { listener } from "#angular/core/src/render3";
const firebase = require("nativescript-plugin-firebase");
const firebaseWebApi = require("nativescript-plugin-firebase/app");
#Component({
selector: "ns-details",
moduleId: module.id,
templateUrl: "./item-detail.component.html",
})
export class ItemDetailComponent implements OnInit {
item: Item;
public oneway;
public stuff = firebaseWebApi.database().ref("/WaterStatus")
.once("value")
.then(result => console.log(JSON.stringify(result)))
.catch(error => console.log("Error: " + error));
constructor(
private itemService: ItemService,
private route: ActivatedRoute
) { }
ngOnInit(): void {
const id = +this.route.snapshot.params["id"];
this.item = this.itemService.getItem(id);
var onChildEvent = function(oneway) {
console.log("Water Status: " + JSON.stringify(oneway.value));
};
// listen to changes in the /users path
firebase.addChildEventListener(onChildEvent, "/WaterStatus").then(
function(listenerWrapper) {
var path = listenerWrapper.path;
var listeners = listenerWrapper.listeners;
}
);
firebase.getValue('/WaterStatus')
.then(result => console.log(JSON.stringify(result)))
.catch(error => console.log("Error: " + error));
}
}
and this is my html:
<ActionBar title="Details" class="action-bar"></ActionBar>
<FlexboxLayout flexDirection="column" class="page">
<FlexboxLayout class="m-15">
<Label class="h2" [text]="item.id + '. '"></Label>
<Label class="h2" [text]="item.name"></Label>
</FlexboxLayout>
<Label class="h3" [text]="item.role"></Label>
<!-- <Button text="Tap Me!" tap="onTap" class="btn btn-primary btn-active"></Button> -->
<br>
<br>
<Label class="h3 p-15" text='{{oneway}}' textWrap="true">{{oneway}}</Label>
<Label class="h3 p-15" text='{{stuff}}' textWrap="true"></Label>
<Label class="h3 p-15" text='{{last}}' textWrap="true">{{last}}</Label>
</FlexboxLayout>
How can I show my data on my app?
Some say that I should do Promise resolve but I don't really know how to integrate it with that.
screenshot:
screenchot
Looking at your code, the [object Promise] comes from <Label class="h3 p-15" text='{{stuff}}' textWrap="true"></Label> (please confirm by removing the other tables or adding a different color to this label).
In fact, stuff is initialized as a promise. Instead, you have to remove that initialization, and inside ngOnInit(), do:
firebaseWebApi.database().ref("/WaterStatus")
.once("value")
.then(result => {
console.log(JSON.stringify(result)));
this.stuff = result; // or result.something?
})
.catch(error => console.log("Error: " + error));
I am not a firebase expert, but I hope it helps.

Passing data correctly with angularfire2 / ionic2

I have a simple structure in my Database:
The app logic here: I create a list with some data with the function to delete each list item separately.
I´m using the angularefire2 plugin for database communication. The code to get data looks like this in component:
// Set variables
currentUserID: any;
visits: any[] = [];
selectedVisit: any;
constructor(public navCtrl: NavController, public navParams: NavParams, private dbAction: DbActionsProvider, private afDatabase: AngularFireDatabase) {
// Build Current User ID
this.currentUserID = this.dbAction.currentUserID().subscribe(data => {
this.currentUserID = data.uid;
});
}
ngOnInit() {
// Get data
this.afDatabase.object('data/users/' + this.currentUserID + '/visits')
.snapshotChanges().map(action => {
const data = action.payload.toJSON();
return data;
})
.subscribe(result => {
Object.keys(result).map(key => {
this.visits.push({ 'key': key, 'data':result[key]
});
}); console.log(this.visits)
})
}
The code in my view:
<ion-item-sliding *ngFor="let visit of visits | orderBy:'date' : false" (ionDrag)="onSelectedVisit(visit)">
<ion-item>
<ion-icon ios="ios-man" md="md-man" item-start></ion-icon>
<strong>{{ !visit.data.name == '' ? visit.data.name : 'Unbekannt' }}</strong>
<p>Musterstraße 8, 66130 Saarbrücken</p>
</ion-item>
<ion-item-options side="right">
<button ion-button>Bearbeiten</button>
<button ion-button color="danger" (click)="deleteVisit()">Löschen</button>
</ion-item-options>
<ion-input [(ngModel)]="visit.id"></ion-input>
</ion-item-sliding>
Ok..now I want that the user can delete items. For this I need access to the key reference ($key in firebase, but not works.....)...so I had to build my own object with this key field in the top. Not a pretty solution...do you have another idea?
The problem:
If the user swipe an item to see the Delete-Option, I pass data with (ionDrag)="onSelectedVisit(visit). My code in component for this function:
onSelectedVisit(visit) {
this.selectedVisit = visit.key;
console.log(this.selectedVisit);
}
deleteVisit() {
this.afDatabase.list('data/users/' + this.currentUserID + '/visits').remove(this.selectedVisit);
this.navCtrl.setRoot(VisitsPage);
}
If I not navigate back to VisitsPage (same page) I´ll see duplicates in my list because of the own builded object before.....so I need a more elegant solution..
Found a pretty solution:
export class AppComponent {
itemsRef: AngularFireList<any>;
items: Observable<any[]>;
constructor(db: AngularFireDatabase) {
this.itemsRef = db.list('messages');
// Use snapshotChanges().map() to store the key
this.items = this.itemsRef.snapshotChanges().map(changes => {
return changes.map(c => ({ key: c.payload.key, ...c.payload.val() }));
});
}
addItem(newName: string) {
this.itemsRef.push({ text: newName });
}
updateItem(key: string, newText: string) {
this.itemsRef.update(key, { text: newText });
}
deleteItem(key: string) {
this.itemsRef.remove(key);
}
deleteEverything() {
this.itemsRef.remove();
}
}
Reference: Github - Angularfire2 Docs

Angular 2 Http Service Injectable

I'm pulling a big object from my server using Angular 2 service when the website starts. The data I need to pull looks like this:
{
Edu: [...],
Exp: [...],
Links: [...],
Portfolio: [...],
Skills: [...]
}
And I set up the service this way:
AllDataService:
import { Injectable, OnInit } from "#angular/core";
import { Http, Response } from "#angular/http";
import { Observable } from "rxjs/Rx";
#Injectable()
export class AllDataService {
private allDataUrl = ".../allData";
private loading: boolean;
private Edu: Array<any>;
private Exp: Array<any>;
private Links: Array<any>;
private Portfolio: Array<any>;
private Skills: Array<any>;
constructor(private http: Http) {
this.loading = true;
this.Edu = [];
this.Exp = [];
this.Links = [];
this.Portfolio = [];
this.Skills = [];
}
ngOnInit() {
this.getAllData();
}
// Get data from api, aka "Set" methods
getAllData() {
return this.http.get(this.allDataUrl)
.subscribe(
data => {
this.Edu = data.Edu;
this.Exp = data.Exp;
this.Links = data.Links;
this.Portfolio = data.Portfolio;
this.Skills = data.Skills;
this.loading = false;
},
err => console.error(err)
);
}
// “Get” methods
getLoading() { return this.loading; }
getEdu() { return this.Edu; }
getExp() { return this.Exp; }
getLinks() { return this.Links; }
getPortfolio() { return this.Portfolio; }
getSkills() { return this.Skills; }
}
And in my component, I inject the service so that I can get data:
HomeIcons:
import { Component } from "#angular/core";
import { AllDataService } from "../allDataService";
#Component({
selector: "home-icons",
template: `
<div class="home-icons-wrapper">
<ul class="home-icons-ul no-select">
<li class="home-icons-li"
*ngFor="let link of links" >
<a href={{link.url}} target="_blank">
<span class="home-icons-icon {{link.icon}}"></span>
</a>
</li>
</ul>
</div>
`,
providers: [AllDataService]
})
export class HomeIcons {
public links;
constructor(private http: Http, private allDataService: AllDataService) {
this.links = allDataService.getLinks();
}
}
However, in the AllDataService, the error message tells me that properties (Exp, Edu, Skills...) don't exist in Response. How should I setup my http service correctly so that I can pull the data I want at start and make sure all the components get the data? Thanks
All you need to do, is to convert your response to a JavaScript object:
// Get data from api, aka "Set" methods
getAllData() {
return this.http.get(this.allDataUrl)
.map(res => res.json()) // <-- this line here
.subscribe(
data => {
this.Edu = data.Edu;
this.Exp = data.Exp;
this.Links = data.Links;
this.Portfolio = data.Portfolio;
this.Skills = data.Skills;
this.loading = false;
},
err => console.error(err)
);
}
Bind to the method directly in your template:
template: `
<div class="home-icons-wrapper">
<ul class="home-icons-ul no-select">
<li class="home-icons-li"
*ngFor="let link of allDataService.getLinks()" >
<a href={{link.url}} target="_blank">
<span class="home-icons-icon {{link.icon}}"></span>
</a>
</li>
</ul>
</div>
`,

Resources