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>
Related
I am working on a dummy API with jsonplaceholder, I am getting all posts after clicking button, but i wanna get userid and title on load,and after clicking title need to get that particular body of that id How can i achieve this.
in jasonplaceholder there are 100 posts with id,title,body. on clicking getdata i need only id and title after when I click on title I need to get body as either in paragraph or popup or something.
html
<button (click)="get()">Get Data</button>
<div class="col-md mt-4 mb-4">
<table class="table table-bordered">
<thead>
<tr>
<th>id</th>
<th>title</th>
<th>body</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let d of data">
<td><span>{{d.id}}</span></td>
<td><span>{{d.title}}</span></td>
<td><span>{{d.body}}</span></td>
</tr>
</tbody>
</table>
</div>
ts
get(){
this.userservice.getData().subscribe((data) =>{
console.log(data)
this.data = data
})
}
service
getData():Observable<any>{
const url = "https://jsonplaceholder.typicode.com/posts";
return this.http.get(url)
}
A simple solution would be to use *ngIf and a variable, eg. selectedId
<td (click)="showBody(d.id)"><span>{{d.title}}</span></td>
<td *ngIf="selectedId === d.id"><span>{{d.body}}</span></td>
Then in your component, initiate it:
selectedId: any = null;
and
showBody(id: number){
this.selectedId ? this.selectedId = null : this.selectedId = id;
}
so that it would hide the body if you click on the title again.
As I understand, you need to get the id of the element you clicked on it to show the element's body.
so to achive this, you can write something like this:
component.html
<tr *ngFor="let d of data" (click)="setBody(d)">
<td><span>{{d.id}}</span></td>
<td><span>{{d.title}}</span></td>
</tr>
<!-- Show selected item body here -->
<h1>Selected item body</h1>
<p>{{selectedItemBody}}</p>
component.ts file
[Optional]: you can define the POST interface top of your ts file to have more clean code:
interface POST {
id: number;
title: string;
body: string;
}
setBody(post: POST) {
this.selectedItemBody = post.body;
alert(this.selectedItemBody); // you can remove this alert
}
I provided you this sample working code here in stackblits
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>
I need to populate a dynamic amount of Tabs on an Angular 2 site using a For Loop that is using a subscribe to get data from a database service and I am wondering if it is even possible.
My data set is broken down by Classes: A, B and C and they each have a Sub-Class of 1 and 2. So I would like to have my results dynamically create 3 tabs (Tab A, Tab B, and Tab C). So far I have this working.
I then need each of these tabs to then display the data of their Sub-Classes. As of now the loop runs the 3 times and provides the data needed but every page just shows data for Class C as it was the last one to run and the model is updated with all of its data.
Below is what I have thus far.
classdata.component.html
<mat-tab-group>
<mat-tab *ngFor="let classresult of classresults;" label="Class -{{classresult.Class_Name}}">
<table class ="responstable">
<thead>
<tr>
<th>Sub-Class Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let subclassresult of subclassresults;">
<td>{{subclassresult.Sub_Class_Name}} </td>
<td>{{subclassresult.Value}} </td>
</tr>
</tbody>
</table>
</mat-tab>
</mat-tab-group>
classdata.component.ts
// Populate Class Level Data
this.databaseService.getClass()
.subscribe(classresults => this.classresults = classresults,
error => console.log('ERROR!'),
// Populate Sub-Class Level Data
() => { for (const classresult of this.classresults) {
this.selectedClassId = classresult.Class_ID;
console.log(this.selectedClassId);
this.databaseService.getSubClass(this.selectedClassId)
.subscribe(subclassresults => this.subclassresults = subclassresults);
}
}
);
database.service.ts
getClass(): Observable<ClassResult[]> {
const url = 'http://localhost:3000/c';
const data = ({
});
return this._http.post(url, data)
.pipe(
map((res) => {
console.log(res);
return <ClassResult[]> res;
})
);
}
getSubClass(Class_ID): Observable<SubClassResult[]> {
const url = 'http://localhost:3000/sc';
const data = ({
classid: Class_ID
});
return this._http.post(url, data)
.pipe(
map((res) => {
console.log(res);
return <SubClassResult[]> res;
})
);
}
You are fetching each Subclass for every parentClass but you are reassigning each result to the class variable this.subclassresults. Basically you are overwriting each previous result with the current result. Thats why every page just shows data for Class C.
There are many different solutions how you can solve this problem.
On solution could be you are using forkJoin Observable and save the result of your parentClass with their subClasses in their own object:
this.databaseService.getClass().pipe(
switchMap(classResults => {
const subClassRequests = classResults.map(
classResult => this.dabaseService
.getSubClass(classResult)
.pipe(map(subClassResults => {classResult, subClassResults}))
)
return forkJoin(subClassRequests)
})
).subscribe(results => this.results = results);
results holds your data as an array.
And in your template use it like this:
<mat-tab-group>
<mat-tab *ngFor="let result of results;" label="Class -{{result.classresult.Class_Name}}">
<table class ="responstable">
<thead>
<tr>
<th>Sub-Class Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let subclassresult of result.subclassresults;">
<td>{{subclassresult.Sub_Class_Name}} </td>
<td>{{subclassresult.Value}} </td>
</tr>
</tbody>
</table>
</mat-tab>
</mat-tab-group>
I implemented a small working Demo: StackBlitz Demo
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');
}
So I'm using Angularjs with TypeScript to make a simple to-do list as a webpage just for fun/practice. This is my controller which queries the database and stores the objects:
module app.ToDo {
class ToDoCtrl {
toDoItems: app.domain.ToDoItems[];
static $inject = ["dataAccessService"];
constructor(private dataAccessService: app.common.DataAccessService)
{
this.toDoItems = [];
var toDoResource = dataAccessService.getToDoResource();
toDoResource.query((data: app.domain.ToDoItems[]) => {
this.toDoItems = data;
});
}
}
angular.module("toDoManagement").controller("ToDoCtrl", ToDoCtrl);
}
Here is my ToDoItems class:
module app.domain {
export class ToDoItems {
constructor(public id: number, public title: string, public description: string,
public due: Date, public completed: boolean) { }
}
}
Those are all of the fields in my database. This is my view:
<table>
<thead>
<tr>
<td>Title</td>
<td>Description</td>
<td>Due Date</td>
<td>Completed</td>
</tr>
</thead>
<tbody ng-repeat="item in vm.toDoItems">
<tr>
<td>{{item.title}}</td>
<td>{{item.description}}</td>
<td>{{item.due}}</td>
<td>{{item.completed}}</td>
</tr>
</tbody>
</table>
My problem is the Due column shows up empty for each row. Is this some sort of formatting error from MySQL to JavaScript? The Due field in my database is of type DATE not DATETIME in case that's relevant.
FIXED: The problem was the variable that because of the way I named the variable in the database, the value for Due was being assigned to a variable that didn't exist in the class and was instead making its own variable named due_Date that I didn't know about. I just had to change the binding from {{item.due}} to {{item.due_Date}}.
This is just a shot in the dark but does the date filter in angular help?
{{ item.todo | date : 'medium' }}
I think that's it just off the top of my head