dispay json data in ngfor loop in angular (data from firebase) - json

In my Angular code, I am getting data from a firebase database through an Http get request and when I try to display the result with an ngfor loop, I have an error message. This example was replicated from a tutorial and it worked for him. Where is the problem and how could I make it work? Thanks for helping!
I use a service to get data here is the code:
import {Http} from '#angular/http';
import { Injectable } from '#angular/core';
import {Response} from "#angular/http";
import {map} from 'rxjs/operators';
#Injectable()
export class ServerService {
constructor(private http:Http){}
StoreServers(servers:any[]){
return this.http.post('https://ng-http-a5718.firebaseio.com/data.json',servers);
}
GetServers(){
return this.http.get('https://ng-http-a5718.firebaseio.com/data.json').pipe(map(
(res:Response) =>{
const dataserver = res.json() as any[];
for(const server of dataserver ){
server.name='fetched_server'+server.name
}
return dataserver;
}
)
)
}
}
Here is the .ts code of the component where I try to display the data:
import { Component } from '#angular/core';
import { ServerService } from './server.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private ServerService : ServerService){}
servers = [
{
name: 'Testserver',
capacity: 10,
id: this.generateId()
},
{
name: 'Liveserver',
capacity: 100,
id: this.generateId()
}
];
onAddServer(name: string) {
this.servers.push({
name: name,
capacity: 50,
id: this.generateId()
});
}
private generateId() {
return Math.round(Math.random() * 10000);
}
OnSave(){
this.ServerService.StoreServers(this.servers).subscribe(
(Response)=>(console.log(Response)),
(Error)=>(console.log(Error))
)
}
OnGet(){
this.ServerService.GetServers().subscribe(
(data) => { this.servers=data}
,
(Error)=>{
return (console.log(Error));
}
)
}
}
Here is the html code of the component where I try to display the data:
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
<input type="text" #serverName>
<button class="btn btn-primary" (click)="onAddServer(serverName.value)">Add Server</button>
<hr>
<button class="btn btn-primary" (click)='OnSave()'>Save servers</button>
<button class="btn btn-primary" (click)='OnGet()'>Get servers</button>
<br>
<ul class="list-group" *ngFor="let server of servers">
<li class="list-group-item">{{ server.name }} (ID: {{ server.id }})</li>
</ul>
</div>
</div>
</div>
And finally here it is the error message I get:
enter image description here

this.server expecting Array in onGet() method but getting Object from firebase with the unique key. so you can modify onGet() method in following:
OnGet(){
this.ServerService.GetServers().subscribe(
(data) => {
const keys = Object.keys(data);
const firstKey = keys[0];
this.servers = data[firstKey]; // get the inside array
}
,
(Error)=>{
return (console.log(Error));
}
)
}

Related

My codes are not doing get,set,post so what is my codes error how can i fix it?

these are my .ts codes i write these becasue i want to get product details and delete
import { Component, OnInit } from '#angular/core';
import {FormGroup,FormBuilder, FormControl, Validators} from "#angular/forms"
import { ToastrService } from 'ngx-toastr';
import { Product } from 'src/app/models/product';
import { ProductService } from 'src/app/services/product.service';
import { LocalStorageService } from 'src/app/services/local-storage.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-product-delete',
templateUrl: './product-delete.component.html',
styleUrls: ['./product-delete.component.css']
})
export class ProductDeleteComponent implements OnInit {
products: Product[] = [];
dataLoaded = false;
deleteProductForm:FormGroup;
product :Product
productId :number;
constructor(private formBuilder:FormBuilder,
private productService:ProductService
, private toastrService:ToastrService
,private router:Router,
private localStorageService:LocalStorageService) { }
ngOnInit(): void {
this.createdeleteProductForm();
}
createdeleteProductForm(){
this.deleteProductForm = this.formBuilder.group({
productId:["", Validators.required],
})
}
getbyid() {
Number(localStorage)
Number(this.productService)
this.productService.getbyid(Number(localStorage.getItem("productId"))).subscribe(
(response) => {
this.products = response.data;
this.dataLoaded = true;
this.deleteProductForm.setValue({
productId: this.product,
categoryId: this.product.categoryId,
productName: this.product.productName,
unitPrice: this.product.unitPrice
});
},
(responseError) => {
this.toastrService.error(responseError.error);
}
)
}
deleteProduct() {
if (this.deleteProductForm.valid) {
let productModel = Object.assign({}, this.deleteProductForm.value);
productModel.productId=parseInt(productModel.productId);
this.productService.delete(productModel).subscribe(
(response) => {
this.toastrService.success('Lütfen tekrar giriş yapınız');
this.router.navigate(['/login']);
},
(responseError) => {
this.toastrService.error(responseError.error);
}
);
} else {
this.toastrService.error('Bir hata oluştu.');
}
}
}
these are my html codes i trying to do when user sign in a productId after that click the button delete the product in that ıd
<div class="card">
<div class="card-header"><h5 class="title">Ürün Sil</h5></div>
<div class="card-body">
<form [formGroup]="deleteProductForm">
<div class="mb-3">
<label for="productId">ÜrünId'si</label>
<div class="form-group">
<input type="number"
id="productId"
formControlName="productId" class="form-control"
placeholder="productId"/>
</div>
<div class="card-footer" style="background-color: rgb(4, 62, 255)">
<button
class="btn btn-lg btn-outline-success float-end"
(click)="deleteProduct()"
>
Sils
</button>
</div>
and these are my service
delete(product:Product):Observable<ResponseModel>{
let newPath = this.apiUrl + 'products/delete';
return this.httpClient.post<ResponseModel>(newPath, product );
}
getbyid(productId:number) : Observable<ListResponseModel<Product>> {
let newPath = this.apiUrl + 'products/getbyid?productId=' + productId;
return this.httpClient.get<ListResponseModel<Product>>(newPath);
}
what i'm going for is that when the user goes on a productId click the button, I want to delete the data including the Id first, but what's the null time on main at the moment?
note:Value cannot be null. says back-end
in html POST https://localhost:44314/api/products/delete
[HTTP/2 500 Internal Server Error 9591ms gives this error
First of all, have you checked the value of product in the call of delete ?
Also, maybe it's the httpClient.delete you need since it's the best way to delete an object to the back end. I suggest this:
https://angular.io/guide/http#making-a-delete-request

Angular 13 Parent-Child not Communicating

Trying to get an array from a parent component to a child component. The Angular docs make it look really simple but I'm not sure what I'm doing wrong. The variable is activePost. Angular version is 13
Parent ts file (HomepageComponent):
import { Component, OnInit } from '#angular/core';
import { PostService } from 'src/app/services/post.service';
import { map } from 'rxjs/operators';
import { Post } from 'src/app/models/post.model';
import { ActivatedRouteSnapshot, Router } from '#angular/router';
import { PostDisplayComponent } from '../components/post-display/post-display.component';
#Component({
selector: 'app-homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.scss']
})
export class HomepageComponent implements OnInit {
posts?: Post[];
category?:'';
currentpost?: Post;
currentIndex = -1;
title = '';
content='';
activePost: Post;
images: string[] =["../assets/img/damwon.jpg",
"../assets/img/FPX.jpg",
"../assets/img/2015skt.webp",
"../assets/img/2017SSG.webp",
"../assets/img/2014SSW.webp",
"../assets/img/TPA.webp",
"../assets/img/Fnatic.webp"]
backgroundImage: string = '';
constructor(private PostService: PostService,
private route: Router) { }
ngOnInit() {
let ran = Math.floor(Math.random()*6);
console.log(ran, Math.random()*100)
this.backgroundImage = this.images[ran];
this.retrieveposts();
}
refreshList(): void {
this.currentpost = undefined;
this.currentIndex = -1;
this.retrieveposts();
}
retrieveposts(): void {
this.PostService.getAll().snapshotChanges().pipe(
map(changes =>
changes.map(c =>
({ id: c.payload.doc.id, ...c.payload.doc.data() })
)
)
).subscribe(data => {
this.posts = data;
});
}
setActivepost(post: Post, index: number): void {
this.currentpost = post;
this.currentIndex = index;
console.log("Post:", post, "Index:", index);
this.activePost = this.currentpost
this.route.navigate(['/Read/'])
}
}
Child ts file (post-display component)
import { Component, OnInit, Input, OnChanges, Output, EventEmitter } from '#angular/core';
import { Post } from 'src/app/models/post.model';
import { PostService } from 'src/app/services/post.service';
import { HomepageComponent } from 'src/app/homepage/homepage.component';
#Component({
selector: 'app-post-display',
templateUrl: './post-display.component.html',
styleUrls: ['./post-display.component.scss']
})
export class PostDisplayComponent implements OnInit {
#Input() activePost: Post;
#Output() refreshList: EventEmitter<any> = new EventEmitter();
currentPost: Post = {
title: '',
description: '',
category:'',
published: false,
content: ''
};
message = '';
constructor(private PostService: PostService) { }
ngOnInit(): void {
console.log(this.activePost)
}
}
Child HTML:
<div class="container" style="padding-top: 200px;">
<div class="post">
ACTIVE POST HERE:
{{activePost}}
</div>
Looking at the console, the child component always returns undefined for activePost. I'm not sure if this is because I dont have anything in the parent html code for the child to look at? I feel like I should just be able to do this in the .ts file.
Help would be appreciated. Let me know if there are other project docs I should share as well.
Edit, added parent html:
<header class="header" [ngStyle]="{'background-image': 'url(' + backgroundImage + ')'}">
<div class="content">
<h1 class="heading">
<span class="small">Samsite:</span>
Stat
<span class="no-fill">check</span>
</h1>
<!--write a blog-->
</div>
</header>
<section class="blogs-section">
<div class="blog-card"
*ngFor="let post of posts; let i = index"
>
<h1>Title: {{ post.title }}</h1>
<h2> Category: {{ post.category }}</h2>
<p class="blog-overview"> Preview: {{ post.description }}</p>
<div class="btn" (click)="setActivepost(post, i)">Read!</div>
</div>
</section>

Currently logged in user won’t display on the navbar until I manually refresh the browser

The last previous account name is displayed. It's only when I refresh the browser the displayed name changes to the current logged in account.
below is the Auth service.
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { environment } from 'src/environments/environment';
import { map } from 'rxjs/operators';
import { DefaultUrlSerializer } from '#angular/router';
import { JwtHelperService } from '#auth0/angular-jwt';
import { Observable } from 'rxjs';
import { yearsPerPage } from '#angular/material/datepicker';
#Injectable({
providedIn: 'root'
})
export class AuthService {
baseUrl = environment.apiUrl + 'auth/';
decodedToken: any;
jwtHelper = new JwtHelperService();
constructor(private http: HttpClient) { }
login(model: any) {
return this.http.post(this.baseUrl + 'login', model)
.pipe(
map((response: any) => {
const user = response;
if (user) {
localStorage.setItem('token', user.token);
localStorage.setItem('user', JSON.stringify(user.user));
this.decodedToken = this.jwtHelper.decodeToken(user.token);
localStorage.setItem('role', JSON.stringify(this.decodedToken.role));
}
})
);
}
register(model: any) {
return this.http.post(this.baseUrl + 'register', model, { responseType: 'text' });
}
loggedIn() {
const token = localStorage.getItem('token');
return !this.jwtHelper.isTokenExpired(token);
window.location.reload();
}
role() {
return localStorage.getItem('role');
}
}
I’m getting the logged in details from the local storage and storing the details into a variable called userDisplayName in the navbar component. As you can see below the code is in ngONInit method.
“this.userDisplayName = JSON.parse (localStorage.getItem('user'));”
import { AddTaskComponent } from './../addTask/addTask.component';
import { AuthService } from './../_services/auth.service';
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { MatDialog } from '#angular/material/dialog';
import { UpdateTaskComponent } from '../updateTask/updateTask.component';
import { Router } from '#angular/router';
import { UserMemberService } from '../_services/userMember.service';
import { StateStorageService } from '../_services/stateStorage.service';
#Component({
selector: 'app-navigation-bar',
templateUrl: './navigationBar.component.html',
styleUrls: ['./navigationBar.component.css']
})
export class NavigationBarComponent implements OnInit {
model: any = {};
loginReactiveForm: FormGroup;
role;
users: any[];
userAuthorised: boolean;
searchTask: FormControl;
Username: string;
userDisplayName;
constructor(
private authService: AuthService,
public dialog: MatDialog,
private router: Router,
private userMemberService: UserMemberService,
private stateStorageService: StateStorageService) { }
ngOnInit() {
this.initForm();
this.isUserAdmin();
// this.userDisplayName = this.authService.login(this.model);
this.userDisplayName = JSON.parse (localStorage.getItem('user'));
console.log(this.role);
}
login() {
this.model.username = this.loginReactiveForm.value.username;
this.model.password = this.loginReactiveForm.value.password;
this.authService.login(this.model).subscribe(next => {
this.loadUsers();
this.router.navigateByUrl('/CalendarView');
this.isUserAdmin();
}, error => {
console.log('failed to login');
});
}
isUserAdmin() {
// get users role
this.role = JSON.parse(localStorage.getItem('role'));
console.log('this is role = ' + this.role);
// if user is not an Admin
if (this.role !== 'Admin') {
this.userAuthorised = false;
console.log('value of auth is = ' + this.userAuthorised );
} // if user is an Admin
else {
// list of users for the drop down
this.userAuthorised = true;
console.log('value of auth is = ' + this.userAuthorised );
}
}
loadUsers() {
this.userMemberService.getUsers().subscribe((data) => {
this.users = data;
this.stateStorageService.setUserMemberStorage(this.users);
}, error => {
console.log(error);
});
}
initForm() {
this.loginReactiveForm = new FormGroup({
username: new FormControl(),
password: new FormControl()
});
this.searchTask = new FormControl();
}
// has the user logged in
loggedIn() {
return this.authService.loggedIn();
}
loggedOut() {
const token = localStorage.removeItem('token');
const username = localStorage.removeItem('user');
const userId = localStorage.removeItem('role');
localStorage.removeItem('user');
}
}
Below is the html
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<ul *ngIf="!loggedIn()" class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link">
<span class="sr-only"></span></a>
</li>
</ul>
<form *ngIf="!loggedIn()" class="form-inline my-2 my-lg-0" [formGroup]="loginReactiveForm"
(ngSubmit)="login()">
<input formControlName="username" class="form-control mr-sm-2"
type="text" placeholder="Username" aria-label="username">
<input formControlName="password" class="form-control mr-sm-2"
type="password" placeholder="Password" autocomplete="off" aria-label="password">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Login</button>
</form>
<div *ngIf="loggedIn()" class="username" style="position:relative; left:70%; color: white ;" >Username: {{userDisplayName.username}}</div>
<div style="position:relative; left:85%">
<button *ngIf="loggedIn()" class="btn btn-outline-success float-right"
type="submit" (click)="loggedOut()" [routerLink]="['/login']">Log Out</button>
</div>
</nav>
Why is is that the loggedin user is only displayed once the browser has been refreshed?
I'm currently logged in as “Matt Briggs” but it shows “Sallyjones” on the navbar in the image.
Link to the image is here
Problem
The problem in your code is that you only set userDisplayName once in ngOnInit. NgOnInit is only called once when the component is initialised. So this is why you need to refresh to see the new user from localstorage.
There's no other place where you change or update userDisplayName...
Solution
I think your code could use a little refactoring to make it work like you expect. You're putting to much logic in your component code.
Save your decodedToken in a currentUser subject which is exposed as an observable ==> By doing this, you can subscribe to this observabel in your component's ngOnInit function. This way every change will be shown in your component too.
This is a tutorial which gives a complete overview of how you can implement authentication in Angular. Give it a good read and try this out in your code.
https://jasonwatmore.com/post/2020/07/09/angular-10-jwt-authentication-example-tutorial#authentication-service-ts
this sounds like a change detection problem. Can you use a Subject to store the userDisplayName?
e.g.
export class NavigationBarComponent implements OnInit {
...
userDisplayName = new Subject<{username: string}>;
...
const _u = JSON.parse(localStorage.getItem('user'));
this.userDisplayName.next(_u);
then in your template
<div *ngIf="loggedIn()"
class="username"
style="position:relative; left:70%; color: white ;" >
Username: {{(userDisplayName | aasync)?.username}}
</div>
Using a subject will cause ng to redraw the ui when the value of userDisplayName changes.
I am guessing that ng is drawing the dom on init, when there is an old value in userDisplayName and doesn't know the value has changed. Using a subscribable will fix that.
you can directly call it from your server to html page
get loggedInUser(): any {
const uname = localStorage.getItem('uname');
return uname;
}
In your html page
<li><a *ngIf="auth.isLoggedIncheck"><span class="glyphicon glyphicon-log-in"></span> Welcome{{auth.loggedInUser| uppercase}} </a> </li>

How to fetch a particular data from database using Angular Observer

In the input box when I enter 'Title' i should get the list of the title but when I run this I get the list of [object Object][object Object][object Object]...
Here is the API
https://jsonplaceholder.typicode.com/posts
I need to get the particular information
HTML
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
<input type="text" #name>
<button class="btn btn-primary" (click)="onGet(name.value)">Add Server</button>
<p>{‌{ servers }}</p>
</div>
</div>
</div>
COMPONENT.TS
import { Component } from '#angular/core';
import {ServerService} from "./server.service";
#Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.css'],
providers: [ServerService]
})
export class ListComponent {
servers = [];
constructor(private serverService: ServerService) {}
onGet(name: string) {
this.serverService.getServers( name )
.subscribe(
(servers: any[]) => this.servers = servers,
(error) => console.log(error)
);
}
}
SERVICE.TS
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import {map} from "rxjs/operator/map";
#Injectable()
export class ServerService {
constructor(private _http: Http) {}
getServers(name: string) {
console.log(name);
return this._http.get('https://jsonplaceholder.typicode.com/posts' )
.map(
(response: Response) => {
const data = response.json();
console.log(data)
return data.name;
}
)
}
}
Please help me with this.
Update you service as following:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import {map} from "rxjs/operator/map";
#Injectable()
export class ServerService {
constructor(private _http: Http) {}
getServers(name: string) {
console.log(name);
return this._http.get('https://jsonplaceholder.typicode.com/posts' )
.map(
(response: Response) => {
const data = response.json();
console.log(data)
return data;
}
)
}
}
Here data is returned instead of data.name. As data is an array of object there is no property "name" in data. "name" is an property of it's item.
And template should be:
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
<input type="text" #name>
<button class="btn btn-primary" (click)="onGet(name.value)">Add Server</button>
<div *ngFor="let server of servers">
<p *ngIf="name.value == 'title'">{{server.title}}</p>
<p *ngIf="name.value == 'id'">{{server.id}}</p>
<p *ngIf="name.value == 'userId'">{{server.userId}}</p>
<p *ngIf="name.value == 'body'">{{server.body}}</p>
</div>
</div>
</div>
</div>
Then it will show the list of title.
The value you try to interpolate in your template is an Array (servers). When you try to interpolate reference type objects in Angular templates, you will get the string representation of them (interpolation uses toString()), so, [object Object] or [object Array]. If you want to see the object in plain text inside a template, consider using the json pipe, like this: <p>{‌{ servers | json }}</p>, but most probably you will want to use ngFor and unwrap the objects inside the array, like this, probably: <p *ngFor="let server of servers">{{ server.title}}</p>, for example. Read more about json pipe and ngFor here and here

How to use input in angular2 with material design.I got the ORIGINAL EXCEPTION: No value accessor for ' '

Here I am trying to use the input in angular2 with material design and I got the error.My code is generate error only when i add the input filed.I want to implement input with material design.
<dialog class="mdl-dialog" [open]="isOpen">
<h4 class="mdl-dialog__title">Allow data collection?</h4>
<div class="mdl-dialog__content">
<p>
Allowing us to collect data will let us get you the information you want faster.
</p>
<md-input placeholder="amount">
<span md-prefix>$ </span>
<span md-suffix>.00</span>
</md-input>
</div>
<div class="mdl-dialog__actions">
<button md-raised-button color="primary" (click)="toggleDialog()">Agree</button>
<button md-raised-button>Disagree</button>
</div>
</dialog>
But I got the following error.
EXCEPTION: Error in http://localhost:5555/node_modules/#angular2-material/input/input.js class MdInput - inline template:0:844
ORIGINAL EXCEPTION: No value accessor for ''
Error: No value accessor for ''
at new BaseException (forms.umd.js:599)
at _throwError (forms.umd.js:1569)
at setUpControl (forms.umd.js:1546)
at NgModel._setUpStandalone (forms.umd.js:2349)
at NgModel._setUpControl (forms.umd.js:2341)
at NgModel.ngOnChanges (forms.umd.js:2300)
at DebugAppView._View_MdInput0.detectChangesInternal (MdInput.template.js:249)
at DebugAppView.AppView.detectChanges (core.umd.js:11841)
at DebugAppView.detectChanges (core.umd.js:11945)
at DebugAppView.AppView.detectViewChildrenChanges (core.umd.js:11867)
ViewWrappedException {_wrapperMessage: "Error in http://localhost:5555/node_modules/#angul…ut/input.js class MdInput - inline template:0:844", _originalException: BaseException, _originalStack: "Error: No value accessor for ''↵ at new BaseExc…dules/#angular/core/bundles/core.umd.js:11867:23)", _context: DebugContext, _wrapperStack: "Error: Error in http://localhost:5555/node_modules…esInternal (LoginComponent_Host.template.js:30:8)"}
here is my .ts file
import { Component, OnInit } from '#angular/core';
import { ROUTER_DIRECTIVES } from '#angular/router';
import { MdToolbar } from '#angular2-material/toolbar';
import { MdCard } from '#angular2-material/card';
import { MdButton } from '#angular2-material/button';
import { MdCheckbox } from '#angular2-material/checkbox';
import {FORM_DIRECTIVES} from '#angular/forms'
import { MdSpinner, MdProgressCircle } from '#angular2-material/progress-circle';
import {MD_INPUT_DIRECTIVES} from '#angular2-material/input'
//import { REACTIVE_FORM_DIRECTIVES } from '#angular/forms/index';
/**
* This class represents the lazy loaded LoginComponent.
*/
#Component({
moduleId: module.id,
selector: 'login-cmp',
styleUrls: ['dialog.css'],
templateUrl: 'login.component.html',
directives: [
ROUTER_DIRECTIVES,
MdToolbar,
MdButton,
MdCheckbox,
MdSpinner,
MdProgressCircle,
MdCard,
MD_INPUT_DIRECTIVES, FORM_DIRECTIVES]
})
export class LoginComponent implements OnInit {
googleUrl: string = 'https://www.google.com';
title1: string = 'Button';
title4: string = 'Warn';
isDisabled: boolean = true;
isOpen: boolean = false;
dialog:any;
modalMethod: string;
user: {
email: string
password: string
} = {
email: '',
password: '',
}
toggleDialog() {
this.isOpen = !this.isOpen;
if (this.isOpen) {
this.dialog.showModal();
} else {
this.dialog.close();
}
}
ngOnInit() {
this.dialog = document.querySelector('dialog');
}
}
Since Angular Material 2 now supports RC.4 with the new forms update, you'll have to provide / install the forms.
bootstrap(AppComponent, [
disableDeprecatedForms(),
provideForms()
])
This solved for me.
Please check this