sorry about my english.
I use sessionstorage for keeping data. In sessionstorage have data enter image description here
but in html, not showing data form sessionstorage. when I get only {{currentUser}} in html show like this enter image description here
mycode services
import { Injectable } from '#angular/core';
const USER_KEY = 'auth-user';
#Injectable({
providedIn: 'root'
})
export class TokenStorageService {
constructor() { }
signOut(): void {
window.sessionStorage.clear();
}
public saveUser(user: any): void {
window.sessionStorage.removeItem(USER_KEY);
window.sessionStorage.setItem(USER_KEY, JSON.stringify(user));
}
public getUser(): any {
const user = window.sessionStorage.getItem(USER_KEY);
if (user) {
return JSON.parse(user);
}
return {};
}
}
html
<div class="container" *ngIf="currentUser; else loggedOut">
<header class="jumbotron">
<h3>
<strong>{{ currentUser.employee_code }}</strong> Profile
</h3>
</header>
<p>
<strong>Token:</strong>
{{ currentUser.accessToken.substring(0, 20) }} ...
{{ currentUser.accessToken.substr(currentUser.accessToken.length - 20) }}
</p>
<p>
<strong>Emp:</strong>
{{ currentUser }}
</p>
</div>
{{ currentUser }}
<ng-template #loggedOut>
Please login.
</ng-template>
and component
import { Component, OnInit } from '#angular/core';
import { TokenStorageService } from '../../../services/token-storage.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
currentUser: any;
constructor(private token: TokenStorageService) { }
ngOnInit(): void {
this.currentUser = this.token.getUser();
console.log(this.currentUser = this.token.getUser())
}
}
how i can do to use please help me
this image for {{ currentUser|json}}
{{ currentUser|json}}
In TokenStorageService change getUser() method.
public getUser(): any {
return JSON.parse(window.sessionStorage.getItem(USER_KEY));
}
In HTML you are printing {{ currentUser }} Which will be an object. You need to specify the property of object.
Note: If you want to see the object in html use json pipe. ({{ currentUser | json }})
if I could see it correctly in your attached image, It is an array not an object, so you will need to use it like currentUser[0], to check it on your own please use
{{ currentUser | json}} in HTML it will show the exact content.
Hi, I have created a similar app with the source code provided by you stackblitz link here. I have made some modifications to mimic the login scenario.
You should be able to see the data on the initial load of the data. As the component is being initialized for the first time. But whereas when you change the user with the change user button. Although the session storage data changes. You won't be able to see the new data. In order to see these kinds of dynamic changes, you need to make use of Observables/Subjects.
Edit 1: The issue here was that the key & value stored in the local storage as stored as strings. So while storing we have to do JSON.Stringify() and JSON.Parse() while extracting back. This is explained in detail here.
Related
This is the function I am using to insert orders into the database, which works fine.
async createPackage(){
const itemsRef = this.afDatabase.database.ref(`delivery orders/${this.uid}`);
const userId =
itemsRef.push({packageName: this.packageName, packageSize: this.packageSize, packageDescription: this.packageDescription, packageFrom: this.packageFrom, packageTo: this.packageTo, deliveryDate: this.deliveryDate, receiverNumber: this.receiverNumber, paymentOption: this.paymentOption, UID: this.uid})
this.packageName = '';
this.packageDescription = '';
this.packageFrom = '';
this.packageTo = '';
this.deliveryDate = '';
this.paymentOption = '';
this.receiverNumber = '';
this.packageSize = '';
this.showAlert('Your package delivery order has been successfully taken.', 'You will be contacted by one of our Administrators soon.');
}
here is a screenshot of how it's been structured in the database, the parent node is the user uid for each user, while the child node is the id for each order by each user.
the problem I am having is how to query and display each user's order separately on their dashboard differently on the front end.
For context, the complete files for this answer can be found here: https://gist.github.com/nclarx/ef581b0e1a95a2d43531411fe91a9814
To Query the User's Orders
To query the user's data you need to use a function similar to the following:
getCurrentOrder(): Observable<Order[] | never> {
return this.afAuth.authState // authState is an observable
.pipe( // use pipe
switchMap((user) => { // switchMap gets authState and then lets you return a different observable
// The following returns an observable call to the real-time database:
return user ? this.afDatabase.list<Order>(`delivery-orders/${user.uid}`).valueChanges() // if the user is authenticated an observable with the Orders is returned
: EMPTY; // if the user is not authenticated an empty observable is returned
})
);
}
This isn't an ideal way to do authentication in a larger application. I suggest you look at this video on Authentication with AngularFire https://www.youtube.com/watch?v=qP5zw7fjQgo and https://fireship.io/lessons/angularfire-google-oauth/ to create an AuthService that can be used across your application.
Displaying the Orders
To display that information in an Angular component using Observables from AngularFire I suggest the following structure/pattern:
OrderService - contains methods for accessing the database (generate the service with the Angular CLI)
AppComponent - has OrderService injected and calls getCurrentUserOrder() when the component initialises ngOnInit()
Template: app.component.html - the template which uses the async pipe in a *ngFor directive to subscribe/unsubscribe to the observable automatically.
Handing an observable to the template and using the async pipe to subscribe to it is good practice because it means that you do not need to subscribe and unsubscribe from an observable manually.
The files can be found in their entirety here: https://gist.github.com/nclarx/ef581b0e1a95a2d43531411fe91a9814
See the comments in the code for important points about how this works.
The Service: OrderService.ts
import {Injectable} from '#angular/core';
import {EMPTY, Observable} from 'rxjs';
import {AngularFireAuth} from '#angular/fire/auth';
import {switchMap} from 'rxjs/operators';
import {AngularFireDatabase} from '#angular/fire/database';
export interface Order {
// write interfaces for all of your objects and use them
// when defining variables and function return types.
packageName: string;
packageSize: number;
packageDescription: string;
packageFrom: string;
packageTo: string;
deliveryDate: Date;
receiverNumber: number;
paymentOption: string;
UID: string;
}
export class OrderService {
constructor(private afAuth: AngularFireAuth, private afDatabase: AngularFireDatabase) {
}
getCurrentOrder(): Observable<Order[] | never> { // note the use of the interface: Order[], which means returning an array of Orders
return this.afAuth.authState // authState is an observable
.pipe( // use pipe
switchMap((user) => { // switchMap gets authState and then lets you return a different observable
// The following returns an observable call to the real-time database:
return user ? this.afDatabase.list<Order>(`delivery-orders/${user.uid}`).valueChanges() // if the user is authenticated an observable with the Orders is returned
: EMPTY; // if the user is not authenticated an empty observable is returned
// NOTE: this observable is not called until it is subscribed to in the template using the `async pipe`, see
// `app.component.html` where it has `*ngFor="let order of orders$ | async"` <== this is what kicks off the request to the database
})
);
}
}
The Component: app.component.ts
import {Component, OnInit} from '#angular/core';
import {Order, OrderService} from './order.service';
import {Observable} from 'rxjs';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'ng-fire-so-qtn';
orders$: Observable<Order[]>; // property to hold the observable which will have your array of Orders
constructor(public orderService: OrderService) { // inject the OrderService into the component
}
ngOnInit() {
this.orders$ = this.orderService.getCurrentOrder();
// When this component is initialised it will set the `orders$` property to the `Observable<Order[]>` so it is available in the template
}
}
The Template: app.component.html
<section>
<ul *ngIf="orders$ | async"> <!-- The *ngIf will hide the whole list until the data has arrived-->
<li *ngFor="let order of orders$ | async"> <!-- The *ngFor will loop over and create list items for the orders once the data has arrived-->
{{order.packageName}}: {{order.packageDescription}}
</li>
</ul>
</section>
Thanks everyone, i finally was able to query each user's submission from the firebase realtime database with angular with this few lines of code.
getCurrentUserOrder() {
return this.afAuth.authState.subscribe(user => {
if(user) {
this.userId = user.uid;
console.log(user.uid)
console.log(user.email)
}
this.afDatabase.list(`delivery orders/${this.userId}`).valueChanges().subscribe(
data => {
console.log(data);
this.orders = data;
}
);
});
after importing the AngularFireDatabase and the AngularFireAuth inside the component.On the frontend,
<section *ngFor="let order of orders">
<ion-card>
<ion-item>
<ion-icon name="cube" slot="end"></ion-icon>
<ion-label>{{order.packageName}}</ion-label>
</ion-item>
<ion-card-content>
</ion-card-content>
</ion-card>
</section>
this solves the entire problems completely.
In my application I'm having a big trouble 'refreshing' the view after model for that view was updated. Mainly when API call is resolved and its response's data should be published on that view.
This my component management.component.ts ts file (I've removed code not important to this issue):
import { Component, OnInit, ChangeDetectionStrategy } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
#Component({
selector: 'app-service',
templateUrl: './service.component.html',
styleUrls: ['./service.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ServiceComponent implements OnInit {
serviceForm: FormGroup;
notificationStatus: boolean;
constructor(
private http: HttpClient
) { }
ngOnInit() {
this.buildServiceForm();
// Example endpoint response: { active: false }
this.getNotificationInfo().subscribe((data: object) => {
this.notificationStatus = data['active'];
})
}
submit()
{
this.notificationStatus = !this.notificationStatus;
}
buildServiceForm()
{
this.serviceForm = this.formBuilder.group({
message_de: ['', { validators: [Validators.required] }],
message_en: ['', { validators: [Validators.required] }]
});
}
getNotificationInfo() {
return this.http.get(this.apiPath + 'service/notifications');
}
}
And this is the part in HTML that is responsible for displaying that model (button tag):
<form [formGroup]="serviceForm" (ngSubmit)="submit()">
<mat-form-field class="service__form__textarea">
<textarea matInput formControlName="message_de"></textarea>
</mat-form-field>
<mat-form-field class="service__form__textarea">
<textarea matInput formControlName="message_en"></textarea>
</mat-form-field>
<button>
<span *ngIf="notificationStatus == false"> Service Off </span>
<span *ngIf="notificationStatus == true"> Service On </span>
</button>
</form>
Whenever the button is clicked a form is submitted and the button's text should be updated (changed with use of ngIf) right away. But it only happens when I click randomly other objects on website.
I tried already with use of changeDetection: ChangeDetectionStrategy.OnPush but with no luck.
Here animation how it looks like in practice - after clicking the button its text changes only after clicking in textarea and not right after clicking the button:
gif animation of the behavior
Any one have any idea how can I refresh my view or what is the reason why my view behaves like that?
When using ChangeDetectionStrategy.OnPush the view will only update if object references change (see angular 2 change detection and ChangeDetectionStrategy.OnPush).
You may need to run the update to notificationStatus inside of zone using zone.run if that service is not already inside zone (the default Http client for example is already run inside zone automatically).
You also need to manually update the view using ChangeDetectorRef, or use the async pipe and observables which do this automatically.
You have two way to solve this:
Use CDR (quick & dirty)
Inject in your costructor ChangeDetectorRef
Call "cdr.markForCheck();" at the end of the submit method.
Transform your notificationStatus in a subject
In the class:
private notificationStatus$:Subject = new Subject(true);
In the submit method:
this.notificationStatus$:Subject.next(false);
In the html:
<span *ngIf="(notificationStatus$ | async ) == false"> Service Off </span>
PS: The $ in the variable name is a convention for obserable/subject
I have a blog feed in my Angular App connected with Contentful. Thanks to the Contentful javascript sdk.
https://www.contentful.com/developers/docs/javascript/tutorials/using-contentful-in-an-angular-project/
I'm trying to display the Title and the Text field. Here is my code:
import { Component, OnInit } from '#angular/core';
import {Observable} from 'rxjs';
import {ContentfulService} from '../../services/contentful/contentful.service';
import { Entry } from 'contentful';
#Component({
selector: 'app-blog',
templateUrl: './blog.component.html',
styleUrls: ['./blog.component.scss']
})
export class BlogComponent implements OnInit {
private posts: Entry<any>[] = [];
constructor(private postService: ContentfulService) {}
ngOnInit() {
this.postService.getPosts()
.then(posts => {
this.posts = posts;
console.log(this.posts);
});
}
}
And the html:
<div *ngFor="let post of posts">
{{ post.fields.title }}
<div>{{ post.fields.text }}</div>
</div>
The title field is displayed well because it is just a string field but the text field is RichText and display [object Object].
Indeed it contain several object. It seems like the Object is divided in several pieces.
https://www.contentful.com/developers/docs/concepts/rich-text/
Does somebody have already display Contentful RichText in an Angular App ?
Is there a specific way to do it?
First, you must install rich-text-html-renderer from your terminal:
npm install #contentful/rich-text-html-renderer
Then, you can import it from your Component:
import { documentToHtmlString } from '#contentful/rich-text-html-renderer';
and use it, simply like that:
_returnHtmlFromRichText(richText) {
if (richText === undefined || richText === null || richText.nodeType !== 'document') {
return '<p>Error</p>';
}
return documentToHtmlString(richText);
}
Finally, 'call the function' from your html like so:
<div [innerHtml]="_returnHtmlFromRichText(post.fields.text)">
</div>
You can also add some options to customise your rich text, more information here. Also, you should code a function similar to _returnHtmlFromRichText in your Contentful service to be able to reuse it later.
I created an Angular library that can render rich text using Angular components: https://github.com/kgajera/ngx-contentful-rich-text
Why use this over #contentful/rich-text-html-renderer? If you need to customize the default mark-up, it allows you to use your Angular components which you can't do using the documentToHtmlString function and [innerHTML].
I have made a login form which take username and password and store it into local storage and when clicked on login it shows welcome {username} on different page.But it only stores one username in localstorage. when we enter another username the previous get overwrite. i want to display all the usernames.
import { Component, OnInit } from '#angular/core';
import { FormBuilder, NgForm } from '#angular/forms';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private router: Router) {
}
model: any = {} ;
onSubmit(form: NgForm) {
console.log(form.value.username);
console.log(this.model.username);
localStorage.setItem ('username', this.model.username);
this.router.navigate(['/home']);
}
onRegister() {
this.router.navigate(['/register']);
window.alert('please wait while we process your request');
}
ngOnInit() {
}
}
<form (ngSubmit)="f.valid && onSubmit(f) " #f="ngForm" novalidate>
<div>
<label for="username">Username</label>
<input type="text" name="username" [(ngModel)]="model.username" #username="ngModel" required appForbiddenName="jimit" />
<div *ngIf="f.submitted && !username.valid" >Username is required</div>
<div *ngIf="username.errors.forbiddenName">
Username has already taken.
</div>
</div>
<div>
<label for="password">Password</label>
<input type="password" name="password" [(ngModel)]="model.password" #password="ngModel" required />
<div *ngIf="f.submitted && !password.valid">Password is required</div>
</div>
<div>
<button type="submit" >Login</button></div>
<div>
<button type="reset">Clear</button>
</div>
</form>
<button (click)="onRegister()">Register</button>
import { Component, OnInit, Input } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
user;
constructor(private router: Router) { }
onLogout() {
this.router.navigate(['']);
// localStorage.clear();
alert('you will be loged out');
}
ngOnInit() {
this.user = localStorage.getItem('username');
}
}
<p>
Welcome {{user}}
</p>
<button (click)="onLogout()">Logout</button>
I need to store each and every username entered to be stored in localstorage and to retrieve that usernames on home-page from that localstorage.
First of all you need to understand how localStorage works. Local storage works as key value pair. You can achieve that by saving different username as different keys and then to get the values you need to use all the keys. Please read this for more information : How to Use Local Storage with JavaScript
By the way it is not recommended to save passwords in the local storage.
LocalStorage acts like a key-value map to save variables.
When you do
localStorage.setItem ('username', this.model.username);
client saves in browser the key "username" with the value this.model.username.
Another client/browser will save his own value, but key 'username' refers to only one "storage unit".
Behaviour you are trying to implement has not sense in functional terms since you are using it to store as if it was a relational database.
You can understand local storage like cookies storage they act the same.
If you still want to use it as storage for your purpose, you can make a counter and implement a function to do:
localStorage.setItem ('username' + counter, this.model.username);
Then read those by iterating and store in an array, for example.
But I insist it is not a good idea because if the purpose is to try you can store them in an array simply
you can do something like this, to store them as array
to store them:
const newUsers = [...JSON.parse(localStorage.getItem('username')),this.model.username];
localStorage.setItem('username', JSON.stringify(newUsers));
and then to use:
const users = JSON.parse(localStorage.getItem('username'));
There is a fantastic library for this called ngx-webstorage you should try it out.
Store
import {Component} from '#angular/core';
import {LocalStorageService} from 'ngx-webstorage';
#Component({
selector: 'foo',
template: `
<section><input type="text" [(ngModel)]="attribute"/></section>
<section><button (click)="saveValue()">Save</button></section>
`,
})
export class FooComponent {
attribute;
constructor(private storage:LocalStorageService) {}
saveValue() {
this.storage.store('boundValue', this.attribute);
}
}
Retrieve
import {Component} from '#angular/core';
import {LocalStorageService} from 'ngx-webstorage';
#Component({
selector: 'foo',
template: `
<section>{{attribute}}</section>
<section><button (click)="retrieveValue()">Retrieve</button></section>
`,
})
export class FooComponent {
attribute;
constructor(private storage:LocalStorageService) {}
retrieveValue() {
this.attribute = this.storage.retrieve('boundValue');
}
}
to answer your question.
LocalStorage is composed of name/value pair. So by doing this,
you're overriding the value of previous username (let say you're
testing on the same browser window)
localStorage.setItem ('username', this.model.username);
"I need to store each and every username entered to be stored in
localstorage and to retrieve that usernames on home-page from that
localstorage."
In reality, each user will login with their own system & so have different instance of localStorage. They will see their own username after login in. For testing purpose, you can open multiple browser (Chrome, Firefox, etc.), login & inspect the value of the same key.
It's more of a common practice to extract username from your JWT token after a success response from your app authentication API (assume that you have integrated with backend)
"...when we enter another username the previous get overwrite. i
want to display all the usernames."
I'm not quit sure about the usecase of this.
I'm getting started with Observable in Angular 2 and I can't figure out how to use them properly in my views.
I'm using Angular 2 with angular-redux, and using the #select() decorator to retrieve my selectedMovie$ from the redux store. This part works fine, the component basically dispatch a redux event to set the default selectedMovie$ upon init. The redux store is correctly updated, but when I try to consumme it in the view, I face some issues.
import { Component, OnInit } from '#angular/core';
import { NgRedux, select } from '#angular-redux/store';
import { MovieActions} from '../store/app.actions';
import { IAppState} from '../store/reducers';
import { MovieService } from '../movie.service';
import { Observable } from 'rxjs/Observable';
import { IMovie } from '../movie.model';
#Component({
selector: 'app-movies-container',
templateUrl: './movies-container.component.html',
styleUrls: ['./movies-container.component.css'],
providers: [MovieService]
})
export class MoviesContainerComponent implements OnInit {
movies: Array<IMovie>;
#select() readonly selectedMovie$: Observable<IMovie>; // HERE - Get data from the redux store
constructor(
private movieService: MovieService,
private movieActions: MovieActions,
private ngRedux: NgRedux<IAppState>
) { }
ngOnInit() {
// Fetch movies and use the first one as default displayed movie.
this.getMovies() // HERE - Takes the first movie and make it the default selectedMovie by dispatching a redux action
.then(movies =>
this.ngRedux.dispatch(this.movieActions.changeSelectedMovie(this.movies[0]))
);
}
getMovies() { // HERE: Call an API, returns an array of movies in data.results
return this.movieService.getMostPopular()
.then(data => this.movies = data.results);
}
onSelect(movie: IMovie) {
this.ngRedux.dispatch(this.movieActions.changeSelectedMovie(movie));
}
}
Here comes the view:
<div *ngIf="movies">
<md-list>
<h3 md-subheader>Most popular movies NOW!</h3>
<pre>
{{(selectedMovie$ | async | json).id}} // This fails and displays nothing. I'd expect it to display the movie id
</pre>
<md-list-item
*ngFor="let movie of movies"
[class.selected]="movie.id === (selectedMovie$ | async | json).id" // This is a real deal, I don't know what's the syntax to use. I wanted to compare ids
(click)="onSelect(movie)"
>
<img src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" />
{{movie.title}}
</md-list-item>
</md-list>
<app-movie-card [movie]="selectedMovie$ | async | json"></app-movie-card> // This component gets the object correctly formatted
</div>
Maybe I'm just not using the right syntax. Or maybe I shouldn't use an Observer in the view in the first place?
Edit: Solution
<div *ngIf="movies && (selectedMovie$ | async); let selectedMovie">
<md-list>
<h3 md-subheader>Most popular movies NOW!</h3>
<md-list-item
*ngFor="let movie of movies"
[class.selected]="movie.id === selectedMovie.id"
(click)="onSelect(movie)"
>
<img src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" />
{{movie.title}}
</md-list-item>
</md-list>
<app-movie-card [movie]="selectedMovie"></app-movie-card>
</div>
The problem results from a common misconception that JSON is a synonym for plain object. It isn't.
json pipe converts input into actual JSON string. So (selectedMovie$ | async | json) expression evaluates to a string and doesn't have id property.
It is helpful to use AoT compilation, because it allows to detect type problems in template and would likely result in type error in this case.
It should be (selectedMovie$ | async).id instead.
If (selectedMovie$ | async) is used more than once (like in this case), it will result in several subscriptions. It can be optimized by assigning it to local variable, as explained here:
<div *ngIf="movies">
<ng-container *ngIf="(selectedMovie$ | async); let selectedMovie">
...
{{selectedMovie.id}}
...
</ng-container>
</div>