How I get $key when I using ngFor using angularfire2? - json

I have some question, example I have a json file:
{
"items" : {
"khanh" : {
"name":"2017 shirt",
"size":["S","M","L"],
"image":"http://placehold.it/650x450",
"likes":0,
"price":123
},
"-KdleehAQm0HgVFYdkUo" : {
"name":"2017 shirt",
"size":["S","M","L"],
"image":"http://placehold.it/650x450",
"likes":0,
"price":123
},
"-Kdlg3AqKNTnbhjAVT8h" : {
"name":"2017 shirt",
"size":["S","M","L"],
"image":"http://placehold.it/650x450",
"likes":0,
"price":123
}
}
}
I have a button that update how many likes. But I have a problem. I don't know how to get the "key". Example:"khanh","-KdleehAQm0HgVFYdkUo"

This worked for me.
Component:
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
dbcomplextest: FirebaseListObservable<any[]>;
constructor(afDB: AngularFireDatabase) {
this.dbcomplextest = afDB.list('/complex/');
}
View:
<span *ngFor="let value of dbcomplextest | async">
{{ value.$key }} - {{ value.$value }}
</span>

In the latest version >=4.6.0, you have to use snapshotChanges().map() to store the key.
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() }));
});
Then now you can be able to get it from your view list using .key

Related

Mat-Option selected option based on patch value from api subscription

In my case i have several controls with mat-autocomplete with mat-options. in which the same form is handled for new entry creation and edit an existing entry data. So i have tried the following methods to implement the mat-option selected by default or mat-option is active based on the data fetched from the server side api, but the approach is not working. Please refer my code below provide a solution to make this case working.
HTML
<mat-form-field floatLabel="never" class="dropdown-arrow-icon">
<span class="material-icons">arrow_drop_down</span>
<input type="text" matInput formControlName="UOM" [matAutocomplete]="uomSelect" (keyup)="onUomKeyUp($event.target.value)">
<mat-autocomplete #uomSelect="matAutocomplete" [displayWith]="selectedDropdownForUom">
<mat-option *ngFor="let uom of uomOption" [value]="uom.value">
{{ uom.value }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
TYPESCRIPT
uomData = [
{ id: 1, value: "Parts", key: "PARTS" },
{ id: 2, value: "G/KG", key: "KG" },
{ id: 3, value: "L/Gal", key: "L" },
{ id: 4, value: "oz/lb", key: "OZ" },
{ id: 5, value: "%", key: "PERC" },
]
machineDetails;
ngOnInit(): void {
this.patchValue();
}
public selectedDropdownForUom = (uomData?: string): string => {
return uomData;
};
public onUomKeyUp(value: string): void {
if (value === "") {
// eslint-disable-next-line no-self-assign
this.uomOption = this.uomData;
} else {
this.uomOption = this.uomData.filter((item) => new RegExp(value, "gi").test(item.value));
}
}
private selectDefaultAutocompleteData(selectedUOM) {
find(this.uomSelect.options.toArray(), (uomOption) => uomOption.value === selectedUOM? .value)?.select();
}
public patchValue(){
this.httpClient.get("https://conversion.intil.io/units/45").subscribe(data =>
{this.machineDetails = data;
const selectedUOM = this.uomData.find(uom => uom.id === this.machineDetails.UoMID
this.experimentForm.patchValue({ UOM: selectedUOM.value});
this.selectDefaultAutocompleteData(selectedUOM);
})
}
RECIEVING OUTPUT
actual output recieving
EXPECTED OUTPUT
expected output

Formgroup binding in select boxes with Angular

I have a nested JSON array which i have to iterate to HTML using formgroup or formarray. This response is to be iterated into dynamically created select boxes depending on the length of array.
The JSON response coming in is:
var result = [{
id: 1,
options: [
{ option: 'Ram', toBeSelected: false },
{ option: 'Ravi', toBeSelected: true }
]
},
{
id: 2,
options: [
{ option: 'Pooja', toBeSelected: false },
{ option: 'Prakash', toBeSelected: false }
]
}
]
I have to iterate this into HTML in such a way that if any of these options have toBeSelected as true, that option should be preselected in HTML and if not, placeholder text can be shown.
According to the JSON in question, you can make it like:
ngOnInit() {
this.form = this._FormBuilder.group({
selections: this._FormBuilder.array([])
});
// the api call should be made here
this.jsonResponse.map(item => {
const opts = item.options.filter(o => {
return o.toBeSelected
});
if (opts.length) {
this.addSelections(opts[0].option);
} else {
this.addSelections();
}
});
}
get selections() {
return this.form.get('selections') as FormArray
}
addSelections(value?: string) {
this.selections.push(
this._FormBuilder.control((value ? value : ''))
);
}
Live view here.
Stackblitz link: https://stackblitz.com/edit/dynamic-form-binding-kx7nqf
Something along the lines of this?
<div *ngFor="let result of results">
<p>ID - {{ result.id }}</p>
<div *ngFor="let option of result.options">
<input
type="checkbox"
[checked]="option.toBeSelected">
{{ option.option }}
</div>
</div>
This isn't an example of FormGroup though but should help you understand how it can be done.
Sample StackBlitz

How to v-model 2 values?

I was using buefy <b-autocomplete> component and there is one property called v-model which is binding values to the input field
now I wanna bind Full Name into the field but the data consist with list[index].first_name and list[index].last_name, and the index is from a v-for loop.
Since v-model cannot bind a function (it has specific index so I cannot just concat it on computed then pass it on) so it's either v-model="list[index].first_name" or v-model="list[index].last_name"
How do I make it bind's these two?
You need a settable computed for full name, and you can v-model that. You just have to decide on a rule for where extra spaces go and what to do if there is no space.
new Vue({
el: '#app',
data: {
firstName: 'Joe',
lastName: 'Smith'
},
computed: {
fullName: {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(newValue) {
const m = newValue.match(/(\S*)\s+(.*)/);
this.firstName = m[1];
this.lastName = m[2];
}
}
}
});
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
First: {{firstName}}<br>
Last: {{lastName}}<br>
Full Name: <input v-model="fullName">
</div>
I am not sure if i get the question,but i am assuming that you have a list of names and last names and you want to give the ability to user to change those proprties of list.For more See the example in action
The "html" part
<div id="app">
<template v-for="item in list" :key="list.id">
<input type="text" :value="item.name" #input="changeList($event, item.id, 'name')">
<input type="text" :value="item.last_name" #input="changeList($event, item.id, 'last-name')">
Your full name is {{item.name}} {{item.last_name}}
<hr>
</template>
</div>
The "javascript(vue)" part
new Vue({
el: "#app",
data: {
list: [
{ id: 1, name: "name1", last_name: 'last_name 1' },
{ id: 2, name: "name2", last_name: 'last_name 2' },
{ id: 3, name: "name3", last_name: 'last_name 3' },
{ id: 4, name: "name4", last_name: 'last_name 4' }
]
},
methods: {
changeList(event, id, property) {
let value = event.target.value
for (item of this.list) {
if (item.id === id) {
if(property === 'name') {
item.name = value
}else if (property === 'last-name') {
item.last_name = value
}
}
}
}
}
})
As it's been said you can't use 2 values in v-model
But if you want to use <b-autocomplete> that means you already have the data and you can compute it in any way you want.
If you have an array of user objects (with firstname and lastname for example) you can do something like:
data() {
return {
users: [
//...
],
computedUsers: [],
}
},
mounted() {
this.users.forEach(user => {
this.computedUsers.push(user.firstname + ' ' + user.lastname)
})
}
and use this new array in the filteredDataArray (from the Buefy autocomplete example)
Fiddle example here

Angular2 Getting very deep nested json value using pipe! *ngFor

Hi I am having trouble getting json value which is really deeply nested using pipe.
What am I doing wrong?
Pipe I'm using
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'keyValues'
})
export class KeysPipe implements PipeTransform {
transform(value, args: string[]): any {
let keys = [];
for (let key in value) {
keys.push({
key: key,
value: value[key]
});
}
return keys;
}
}
Json I'm getting from server.
data:
0: {
Profile: { ...
}
BasicInfo: { ...
}
introduceInfo: {
curriculum: { ...
}
experience: {
0: {
category: "Mentor"
year: "2011"
duration: "24"
}
1: {
category: "Student"
year: "2011"
duration: "14"
}
}
}
}
It's actually a huge json object but I've simplified to only show what I need to get.
I want to get the value of category (which is "Mentor"and "Student".
And to do so, I've tried in my html
<div *ngFor="let detail of teaInfo | keyValues">
<div *ngFor="let experience of detail.value['introduceInfo'] | keyValues">
<div *ngFor="let exp of experience.value['experience'] | keyValues">
<p class="fontstyle2">{{exp.value['category']}} {{exp.value['year']}}년 | {{ex.value['duration']}}개월</p>
</div>
</div>
</div>
And I'm getting my json object in my component like this.
teaInfo: any[];
getTeacherDetail(): void {
let params = new URLSearchParams();
params.set('gradeType', `${this.getVal2()}`)
params.set('subjectType', `${this.getVal3()}`)
params.set('district', `${this.getVal1()}`)
this.teaDetail.getTeachersDetail(params)
.subscribe(
teaInfo => this.teaInfo = teaInfo,
error => this.errorMessage = error
)
}
And the result is I am getting nothing
What am I doing wrong?
Trying to interpret how your JSON looks like, something like this:
{
"data":{
"0": {
"Profile":{
"prof":"prof"
},
"BasicInfo":{
"basic":"basic"
},
"introduceInfo":{
"curriculum": {
"curr":"curr"
},
"experience":{
"0":{
"category":"Mentor",
"year":"2011",
"duration":"24"
},
"1":{
"category":"Student",
"year":"2011",
"duration":"14"
}
}
}
}
}
}
In below example, I have extracted the values from data, so:
.map(res => res.json().data)
To reach values Mentor and Student, first change your pipe to this:
export class KeysPipe implements PipeTransform {
transform(value: any, args: any[] = null): any {
return Object.keys(value).map(key => value[key]);
}
}
and change your HTML to this:
<div *ngFor="let detail of teaInfo | keyValues">
<div *ngFor="let experience of detail['introduceInfo']['experience'] | keyValues">
{{experience.category}}
</div>
</div>
This should work nicely:
Demo

fail reading object type of json

i have an Object type of json that I cant read...
this is my json:
body: {
"111": {
"name": "name1",
"status": 10000
},
"222": {
"name": "name2",
"status": 20000
},
"333": {
"name": "name3",
"status": 30000
}
}
and I want to know how to present it in my html?
this is my attempt:
<md-content>
<h1 align="center">{{title}}</h1>
<h2>list of items:</h2>
<div class="list-bg" *ngFor="#item of items | async">
ID: {{item.name}} <p></p> Number of Items: {{item.status}}
</div>
</md-content>
not only that it dosent work, im trying to figure out how to read each line the object id's(those: 111, 222, 333)
this is my model:
export interface MyModel {
name: string;
status: number;
}
this is my component:
export class MyCmp implements OnInit {
retJson: Observable<MyModel[]>
constructor(private _myService: MyService) {};
public showData(): void {
this.retJson = this._myService.getData();
}
}
thanks!
You haven't included how you load your json, so I'll write a more general example:
interface MyModel {
name: string;
status: number;
}
interface MyResponse {
body: { [id: string]: MyModel }
}
let response: MyResponse = JSON.parse(RESPONSE_STRING);
Object.keys(response.body).forEach(id => {
let model = response.body[id];
console.log(`id: ${ id }, name: ${ model.name }, status: ${ model.status }`);
});
What's missing here is the RESPONSE_STRING, which I'm not sure how you get.
As for the template, I'm not an angular developer but as far as I understand ngFor is used for arrays, and you don't have an array in your json structure.
ngFor loop only will work for array. Your body json is key value object, so it wouldn't work.
If you want to make it work, it's either:
you use an additional pipe to convert key value object to array using pipe, solution discussed here: Iterate over TypeScript Dictionary in Angular 2, then you can use
*ngFor="let item of items | async | mapToIterable"
Or process it in your ts file, instead of
this.retJson = this._myService.getData();, use this._myService.getData().subscribe(x => this.retJson = processToArray(x))