Angular + firebase - can't get the key value in html - html

I want to navigate to an URL based on the key of an object in my database, but when i acces the p.$key value is always undefined.
service:
getAll(){
return this.db.list('/products').valueChanges();
}
component:
products$;
constructor(private productService: ProductService) {
this.products$ = this.productService.getAll();
}
html:
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of products$ | async">
<td>{{p.title}}</td>
<td>{{p.price}}</td>
<td>
<a [routerLink]="['/admin/products/', p.$key]" >Edit</a>
</td>
</tr>
</tbody>
</table>
I am getting the right values for p.title and p.price, but p.$key is always undefined. I also tried p.key , same thing.

The valueChanges() stream doesn't include the key of the nodes. According to the AngularFire documentation on [valueChanges](When would you not use it? - When you need a more complex data structure than an array or you need the key of each snapshot for data manipulation methods. This method assumes you either are saving the key for the snapshot data or using a "readonly" approach.):
When would you not use it? - When you need a more complex data structure than an array or you need the key of each snapshot for data manipulation methods. This method assumes you either are saving the key for the snapshot data or using a "readonly" approach.
I think you may want to use the snapshotChanges stream instead, which gives you the entire DataSnapshot for each object from which you can get the key and the val().

Service:
Pipe is not necessary. I used it so you can console.log your object to view.
getAll(){
return this.db.list('/products').snapshotChanges()
.pipe(
map(object => {
console.log(object);
return object;
})
);
}
Component
Same as yours
html
<span *ngFor="let item of items$ | async">
<!-- print out the key values -->
{{item.key}}
</span>

Related

How can I display the values in HTML for unknown properties in a object?

I have an array(formResponses) of objects. My object structure is as shown below. In the below picture I have userResponses object, where I have keys and value loaded dynamically. I want to display userResponses object in my HTML. How can I do this?
All the keys and values in userResponses object are loaded differently each time.
I know I can display if I do it like this:
<p>{{userResponses.firstName}}</p>
<p>{{userResponses.lastName}}</p>
But, I don't know what values are loaded everytime. Is there a way to display any value which is in the object.
<table>
<thead>
<th>Name/Attributes</th>
<th>arrtibute1</th>
<th>attribute2</th>
</thead>
<tbody>
<tr *ngFor="let item of formResponses">
<td>{{item.userName}}</td>
<td>{{item.userResponses.firstName}}</td>
<td>{{item.userResponses.lastName}}</td>
</tr>
</tbody>
</table>
Create a pipe to loop json keys.
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({ name: 'keys' })
export class KeysPipe implements PipeTransform {
transform(value): any {
if(!value) return null;
return Object.keys(value);
}
}
<td *ngFor="let key of item.userResponses | keys">{{item.userResponses[key]}}</td>

Angular write data lines dynamically to a table

In my project I getting the data from JSONPlaceholder - Users
I'm new in Angular, so if you find something stupid in the way I get the data please warn me.
dataFromServer;
constructor(private http: HttpClient){
this.dummyPromise.then(
response => {
console.log("response from dummy promise:", response);
this.dataFromServer = response;
},
error => {
console.log("Error happened with dummy promise:", error)
}
)
}
dummyPromise = new Promise((resolve, reject) => {
this.http.get('https://jsonplaceholder.typicode.com/users').subscribe(data => {
console.log(data);
this.dataFromServer = data;
});
//resolve(returnData);
});
Problem is, in my HTML file, I write the data into a table like this:
<tr *ngIf="dataFromServer">
<td>{{dataFromServer[0].id}}</td>
<td>{{dataFromServer[0].name}}</td>
<td>{{dataFromServer[0].username}}</td>
<td>{{dataFromServer[0].email}}</td>
</tr>
<tr *ngIf="dataFromServer">
<td>{{dataFromServer[1].id}}</td>
<td>{{dataFromServer[1].name}}</td>
<td>{{dataFromServer[1].username}}</td>
<td>{{dataFromServer[1].email}}</td>
</tr>
... for all the 10 people. I want to do it dynamically, as many lines as many people's data I get.
I think that you should try to use *ngFor instead of *ngIf. I will give you an example.
<tr *ngFor="let data of dataFromServer">
<td>{{data.id}}</td>
<td>{{data.name}}</td>
<td>{{data.username}}</td>
<td>{{data.email}}</td>
</tr>
So, it will repeat for every object in your dataFromServer
use ngFor to iterate on an array of data:
<table *ngIf="dataFromServer">
<tr *ngFor="let item of dataFromServer">
<td>{{item.id}}</td>
...
</tr>
</table>
the ngIf condition on the table will prevent console errors/rendering issues if dataFromServer is null/undefined before receiving from your API
You can replace your html code as bellow
<tr *ngFor="let row of dataFromServer">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.username}}</td>
<td>{{row.email}}</td>
</tr>
You can use *ngFor to do it. It's pratically a for in the html. As an example we assume that we have a component like this :
private users: User[] = [];
ngOnInit(){
this.service.getUser()
.subscribe(userList => {
this.users = userList;
});
}
The User class :
export class User {
public id: number;
public name: string;
}
You can use the *ngFor in your html like this way :
<span *ngFor="let user of users">
UserID: {{user.id}} - User Name: {{user.name}}
</span>
So basically, related to your code, just put in an object of User the json data you get from the http call, then modify the html like this way :
<tr *ngFor="let user of users">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
.....
</tr>

Not able to Retrieve data from firebase using keys in angular 2

Hi I want to iterate the data of firebase and need to display it in table.
Below is my firebase structure.I want to display the bill to, email id and po number in the tables.i can see the data in console.log, but its not populating in tables.
EDI855
Bill To
-L9ac7clRzSVT-EfGxYv:
"123456789"
-L9acDp2k34qDpubJFr6:
"123456780"
Email Id
-L9ac7cxYSALI3Ogj-nt:
"test#gmail.com"
-L9acDp87NO83OQutasK:
"test1#gmail.com"
Po Number
-L9ac7cvtNNzg7hYa355:
"123456789"
-L9acDp4PPOSo9VL9ysB:
"VV002"
Below is my html table:
div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>No</th>
<th>Bill To</th>
<th>Requested by</th>
<th>Po Number</th>
</tr>
</thead>
<tbody>
<tr>>
<td *ngFor="let x of items">{{x.$value}}</td>
</tr>
</tbody>
</table>
Below is my firebase code:
constructor(public af: AngularFire) {
af.database.list('/EDI855').subscribe(x =>{
this.items=x;
console.log(this.items)
}
Try implementing your query in the init event instead
export class MyComponent implements OnInit {
items;
constructor(public af: AngularFire) {
}
ngOnInit() {
this.af.database.list('/EDI855').subscribe(x =>{
this.items=x;
}
}
Or even better, to get the most out of the real-time database, you should consider using the async pipe. When you do that, your app will react to any changes on your data and immediately refresh the UI.
<td *ngFor="let x of items | async">{{x.$value}}</td>
Just that in this case, remember that you're changing the type of items (it is no longer the list of items, but an observable of items), than therefore, no need to subscribe to it. The async pipe will do the work.
constructor(public af: AngularFire) {
this.items = af.database.list('/EDI855');
}

Vue v-bind - access array object from another array loop

I'm working on a project where I created a table component which is used on multiple pages with different configuration. Every table has it's configuration in a separate file where I store keys, titles and size classes for each column.
Data for each table body come from REST calls and they are loaded dynamically, paginated and then displayed.
<template slot="thead">
<tr>
<th v-for="item in headers" :key="item.id" :class="item.classes">{{item.title}}</th>
</tr>
</template>
<template slot="tbody">
<tr v-for="skill in paginatedSkills"
:key="skill.id"
v-on:click="selectRow(skill)"
v-bind:class="{selectedRow: selectedSkill === skill}"
>
<td class="cell-l">{{skill.name}}</td>
<td class="cell-m">{{skill.owner}}</td>
<td class="cell-s">{{skill.complexity}}</td>
<td class="cell-full">{{skill.description}}</td>
</tr>
</template>
What I want to do is to avoid writing size class for every single cell in the tbody loop. I was hoping to get index of looped object and use it to retrieve the class from config object which is used to populate cells in thead.
<tr v-for="(skill, index) in paginatedSkills" ...>
<td class="{headers[index].classes}">{{skill.name}}</td>
Using index on headers will return the correct item but as a string so obviously classes are not accessible. Any idea how to tweak it?
This options are no go, failing on compile
<td :class="{JSON.parse(headers[index]).classes}">{{skill.name}}</td>
<td :class="{JSON.parse(headers)[index].classes}">{{skill.name}}</td>
<td :class="{{JSON.parse(headers[index]).classes}}">{{skill.name}}</td>
To set class from a variable/property you have two options:
<td v-bind:class="headers[index].classes">{{skill.name}}</td>
<td :class="headers[index].classes">{{skill.name}}</td>
No need for curly braces here since v-bind already expects JS expression.
Update:
What you can also do, is to associate keys of skill object (name, owner, complexity, description) with their header, so each item of headers array will also have for example key property used to access value from skill object:
headers: [
{ id: 1, classes: 'cell-l', title: 'title', key: 'name' },
{ id: 2, classes: 'cell-s', title: 'title', key: 'owner' },
...
]
Thus, your code can be simplified the following way:
<tr v-for="skill in paginatedSkills" ...>
<td v-for="header in headers" v-bind:class="header.classes">{{skill[header.key]}}</td>
</tr>

create dynamic html table with dynamic tr ,td using angularjs

how can I create an html table from a json file, which I do not know the number of columns or the number of rows (the number of row ng-repeat enough),
this json file is editable and the number of column and row change
You would need to load your JSON file into your app with either the $http or $resource service. This is best done in a service, which you would inject whereever you need your data.
this.getJson = function() { // real json get
$http.get('/api/GetJson').then(function(data) {
return data;
});
};
I created a small plunker with a service that holds my fake getJson function which returns the json data with the rows. Then I injected the service into my HomeController and put the rows on the $scope.
$scope.rows = loadJsonService.getFakeJson().rows;
When the rows are on the $scope, you only have to use the ngRepeat directive to create your table structure.
<table class="table table-striped">
<tr class="row" ng-repeat="row in rows">
<th>row {{$index + 1}}</th>
<td class="column" ng-repeat="column in row.column">{{column}}</td>
</tr>
</table>