how to save and retrieve data from Angular2 local storage? - angularjs

I was able store an auth token in the browser's localstorage, but I wasn't able retrieve it as string. I can't find any examples on how to do that.

You could write yourself a service to encapsulate the serializing and deserializing:
export class StorageService {
write(key: string, value: any) {
if (value) {
value = JSON.stringify(value);
}
localStorage.setItem(key, value);
}
read<T>(key: string): T {
let value: string = localStorage.getItem(key);
if (value && value != "undefined" && value != "null") {
return <T>JSON.parse(value);
}
return null;
}
}
Add it to your providers either in the bootstrap call:
bootstrap(App, [ ..., StorageService]);
or in your root component:
#Component({
// ...
providers: [ ..., StorageService]
})
export class App {
// ...
}
Then in the component where you need it, just inject it in the constructor:
export class SomeComponent {
private someToken: string;
constructor(private storageService: StorageService) {
someToken = this.storageService.read<string>('my-token');
}
// ...
}

Related

Why do I keep getting error while pushing data to Array in Angular 10?

I'm trying to create Angular Material Chips as shown on the site, but I keep getting this error about the array being null.
Here's the component
import { Component, Input, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { IStatement } from 'src/Interface/ICorporateStatement';
import { StatementService } from '../services/statement.service';
import { MatChipInputEvent } from '#angular/material/chips';
import {COMMA, ENTER} from '#angular/cdk/keycodes';
export interface Tag{
corporate_statement_link_id: number;
name: string;
}
#Component({
selector: 'app-statement-detail',
templateUrl: './statement-detail.component.html',
styleUrls: ['./statement-detail.component.css']
})
export class StatementDetailComponent implements OnInit {
statement: IStatement;
id: number;
tags: Tag[] = [];
visible = true;
selectable = true;
removable = true;
addOnBlur = true;
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
constructor(private statementService: StatementService,
private router:ActivatedRoute) { }
ngOnInit(): void {
this.tags = [
{ corporate_statement_link_id: 1, name: 'EDI'}
];
console.log("Tags: ", this.tags);
this.router.queryParams.subscribe(param => {
this.id = param.id;
this.getStatement(this.id);
});
}
addTag(event: MatChipInputEvent): void {
console.log(this.tags);
const input = event.input;
const value = event.value;
console.log("Input: ", input);
console.log("Value: ", value);
console.log("Tags: ", this.tags);
this.tags.push({corporate_statement_link_id: this.statement.corporate_statement_link_id, name: value.trim()});
// // Add our fruit
// if ((value || '').trim()) {
// this.fruits.push({name: value.trim()});
// }
// // Reset the input value
// if (input) {
// input.value = '';
// }
}
removeTag(tag: Tag): void {
console.log("removing");
// const index = this.fruits.indexOf(fruit);
// if (index >= 0) {
// this.fruits.splice(index, 1);
// }
}
// get statement
getStatement(id){
this.statementService.getStatement(id).subscribe(data => {
this.statement = <IStatement>data[0];
//get tags
this.statementService.getTags(this.statement.corporate_statement_link_id)
.subscribe(tag => {
this.tags = <Tag[]>tag;
})
}, error => {
console.log(error);
});
}
}
I've refactored the code and moved things here and there, but still can't figure out why the array is still null.
It looks like this code is setting this.tags to null.
.subscribe(tag => {
this.tags = <Tag[]>tag;
})
It may be an issue with your <Tag[]> cast, or maybe the data coming back is null?
if it is expected you could replace any null value here with an empty array like this:
.subscribe(tag => {
this.tags = <Tag[]>tag || [];
})
and see if that helps.

How to filter an observable wrapped json file response?

I am working on a angular project and my task is to filter a huge file based on the "_type" key which can take different values. Right now I want to first filter _type = "COMPETITION".
My model is defined in a competition.model.ts file which looks like this:
export interface Competition {
product: { active: true };
schemaVersion: number; // 2,
status: string; // PUBLISHED",
comp: string; // "4fc16b10-b8b4-4a99-b9f1-842f0d8b8413",
_createdDate: number; // 1594249198,
discipline: string; // "TRAP [ACTA]",
categories: any; // ["OPEN", "LADIES", "JUNIOR", "VETERAN", "CLAYS_ONLY"],
host: string; // "2",
changeSet: number; // 257,
sync: number; // 155,
seq: number; // 120,
id: string; // "4fc16b10-b8b4-4a99-b9f1-842f0d8b8413",
_type: string; // "COMPETITION",
when: number; // 1597154400,
title: string; // "ACTA Self Nom Test"
}
Here is a my service class where I am trying to implement this:
import { Injectable, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { map } from 'rxjs/Operators';
import { Competition } from '../interfaces/competition.model';
#Injectable ({providedIn: 'root'})
export class CompetitionListService {
private loadedCompetitions: Competition[];
private url = '../../assets/data/program1.json';
constructor(private http: HttpClient) {}
public getCompetitions(): Competition[] { return this.loadedCompetitions; }
public fetchCompetition(){
return this.http
.get<Competition[]>(this.url)
.pipe(
map( (responseData) => {
const competitionsArray = [];
for (const key in responseData ) { // responseData is an object
if (responseData.hasOwnProperty(key)) {
// get the_type property
// if ( key.valueOf() === 'COMPETITION') {
competitionsArray.push(
// responseData[key]._createdDate,
responseData[key]._createdDate,
responseData[key]._type,
responseData[key].categories,
responseData[key].changeSet,
responseData[key].comp,
responseData[key].discipline,
responseData[key].host,
responseData[key].id,
responseData[key].product,
responseData[key].schemaVersion,
responseData[key].seq,
responseData[key].status
);
}
}
console.log(competitionsArray);
return competitionsArray;
})
)
.subscribe(competitions => {
console.log(competitions);
this.loadedCompetitions = competitions;
});
}
}
I attached the snapshot of the result on my console, which doesn't really do what I really want to achieve.
I see multiple issues here
You're trying to fetch the asynchronous variable this.loadedCompetitions synchronously. It is not possible. All async variables should be accessed asynchronously. You could use RxJS ReplaySubject multicast observable with buffer 1 to hold and emit the last value.
You don't to manually loop through each item of the array and create a new array with the _type === 'COMPETITION' property. You could use Array filter function to filter out the objects based on a condition.
...
import { Observable, ReplaySubject } from 'rxjs';
import { map } from 'rxjs/operators';
#Injectable ({providedIn: 'root'})
export class CompetitionListService {
private loadedCompetitions: ReplaySubject<Competition[]> = new ReplaySubject<Competition[]>(1);
private url = '../../assets/data/program1.json';
constructor(private http: HttpClient) {
this.fetchCompetition(); // <-- triggers the request and pushes value to `loadedCompetitions`
}
public getCompetitions(): Observable<Competition[]> {
return this.loadedCompetitions.asObservable();
}
public fetchCompetition() { // return nothing here
this.http.get<Competition[]>(this.url).pipe(
map(res => res.filter(item => item['_type'] !== 'COMPETITION'))
).subscribe(
res => this.loadedCompetitions.next(res),
err => console.log(err) // <-- handle error
);
}
}
Now you need to subscribe to loadedCompetitions variable to obtain notifications from it. I've used RxJS takeWhile operator with Subject to close any open subscriptions in the ngOnDestroy hook of the component.
...
import { Observable, Subject } from 'rxjs';
import { takeWhile } from 'rxjs/operators';
export class SomeComponent implements OnInit, OnDestroy {
private close$ = new Subject<any>(); // <-- use to close open subscriptions
constructor(private competitionListService: CompetitionListService) { }
ngOnInit() {
this.competitionListService.loadedCompetitions.pipe(
takeWhile(this.close$)
).subscribe(
res => {
console.log(res);
// other statements that depend on `res`
}
);
}
ngOnDestroy() {
this.close$.next(); // <-- close open subscriptions
}
}

Observable to Array *ngFor saying undefined

I am new to Angular. I have a Node and Express backend pulling data from an MS SQL database. If I go to the endpoint URL it displays my data as JSON. I am running on localhost so I set a proxy for CORS. I have a class that defines the data, a service that pulls the data from the endpoint and a component that tries to set an array equal to the data pulled from the service. The HTML has an *ngFor that is supposed to loop through the values and display them in a grid.
If I call my data in my component through my service, so this.userService.getUsers(), and do a console.log I can see the recordset in the browser console. I try to set the array equal to the userService.getUsers() and then call the array and I get "undefined". Being that I am new, I have tried to follow the Heroes tutorial and that did not work. I spent a day searching Google and trying different solutions that I have come across but they all come up as undefined. I will attach the code here. If someone can guide me a bit, it would be much appreciated.
User class defining User:
export class User{
id: number;
ccn: string;
firstName: string;
lastName: string;
email: string;
}
User Service doing Http request:
import { Injectable } from '#angular/core';
import { User } from './user';
import { USERS } from './mock-users';
import { MessageService } from './message.service';
import { Observable, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class UserService {
private userURL = 'api/users'
//private userURL = 'localhost:5000'
httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
constructor(
private http: HttpClient,
private messageService: MessageService) { }
//getUsers(): Observable<User[]> {
// this.messageService.add('UserService: fetched users');
// return of(USERS);
//}
/** GET users from the server */
getUsers(): Observable<User[]> {
//console.log('getting users');
return this.http.get<User[]>("http://localhost:5000/api/user")
.pipe(
tap(_ => this.log('Fetched users')),
catchError(this.handleError<User[]>('getUsers', []))
);
//return this.http.get<User[]>("http://localhost:5000/api/user");
//console.log('got users');
}
/* GET heroes whose name contains search term */
searchUsers(term: string): Observable<User[]> {
if (!term.trim()) {
// if not search term, return empty hero array.
return of([]);
}
return this.http.get<User[]>(`${this.userURL}/?ccn=${term}`).pipe(
tap(_ => this.log(`found users matching "${term}"`)),
catchError(this.handleError<User[]>('searchUsers', []))
);
}
addUser (user: User): Observable<User> {
return this.http.post<User>(this.userURL, user, this.httpOptions).pipe(
tap((newUser: User) => this.log(`added user w/ id=${newUser.id}`)),
catchError(this.handleError<User>('addUser'))
);
}
private handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(error);
this.log(`${operation} failed: ${error.message}`);
return of(result as T);
};
}
private log(message: string) {
this.messageService.add(`User service: ${message}`);
}
}
Display Users Component TS file:
import { Component, OnInit } from '#angular/core';
//import { USERS } from '../mock-users';
import { UserService } from '../user.service';
import { User } from '../user';
import { Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { element } from 'protractor';
#Component({
selector: 'app-display-users',
templateUrl: './display-users.component.html',
styleUrls: ['./display-users.component.css']
})
export class DisplayUsersComponent implements OnInit {
users: User[] = [];
constructor(private userService: UserService) { }
//users$ = this.getUsers();
ngOnInit() {
this.getUsers();
console.log(this.userService.getUsers());
this.userService.getUsers().forEach(element => {
console.log(element);
});
}
getUsers(): void {
/*this.userService.getUsers()
.subscribe(users => this.users = users);*/
const userObservable = this.userService.getUsers();
userObservable.subscribe((userData: User[]) => {
this.users = userData;
});
}
}
Display Users Component HTML:
<div class="clr-row">
<div class="clr-col-lg-11 clr-col-md-11 clr-col-11 main-div">
<div class="card card-style" style="box-shadow: 0 0 0 0;">
<div class="card-header">
<h1><img src="../assets/images/BSOLOGO_gray.png" class="title-img"><span class="title"> Users</span></h1>
</div>
<div class="card-block">
<div class="card-title">
<clr-datagrid>
<clr-dg-column>CCN</clr-dg-column>
<clr-dg-column>Last Name</clr-dg-column>
<clr-dg-column>First Name</clr-dg-column>
<clr-dg-column>Email</clr-dg-column>
<clr-dg-row *ngFor="let user of users">
<clr-dg-cell>{{user.ccn}}</clr-dg-cell>
<clr-dg-cell>{{user.lastName}}</clr-dg-cell>
<clr-dg-cell>{{user.firstName}}</clr-dg-cell>
<clr-dg-cell>{{user.email}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>{{users.length}} users</clr-dg-footer>
</clr-datagrid>
</div>
</div>
</div>
</div>
</div>
Any help would be greatly appreciated!
UPDATED
Ypu can replace getUsers on both classes by these. HTML looks fine to me. I converted users to public too.
//userService
getUsers(callback: Function) {
return this.http.get<User[]>("http://localhost:5000/api/user")
.subscribe(
response => callback(response)
);
}
//Component
public users: User[] = [];
getUsers(): void {
this.userService.getUsers((result) => {this.users = result;})
}
If you do not need it to be Observable you can use toPromise() and using async/await makes it waaay easier
Service
async getUsers(): Promise<User[]> {
return await this.http.get<User[]>('http://localhost:5000/api/user').toPromise();
}
Component.ts
users: User[] = [];
async ngOnInit() {
this.users = await this.userService.getUsers();
}
Component.html
<clr-datagrid *ngIf="users">
<clr-dg-column>CCN</clr-dg-column>
<clr-dg-column>Last Name</clr-dg-column>
<clr-dg-column>First Name</clr-dg-column>
<clr-dg-column>Email</clr-dg-column>
<clr-dg-row *ngFor="let user of users">
<clr-dg-cell>{{user.ccn}}</clr-dg-cell>
<clr-dg-cell>{{user.lastName}}</clr-dg-cell>
<clr-dg-cell>{{user.firstName}}</clr-dg-cell>
<clr-dg-cell>{{user.email}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>{{users.length}} users</clr-dg-footer>
</clr-datagrid>
My issue has been resolved. In my SQL statement I was calling SELECT * FROM table FOR JSON PATH which was creating a weird object being pulled from the server. Removing the FOR JSON PATH provided JSON data. Then the second part of my issue was mapping my DB fields with my user class.
This was done like this:
request.query('SELECT * FROM Table ORDER BY myField', function (err, recordset) {
if (err) console.log(err);
const records = recordset.recordset;
const result = records.map(r => { return { id: r.tableID, field1: r.dbField1, field2: r.dbField2, field3: r.dbField3, field4: r.dbField4}});
res.send(result);
});
I hope this helps someone! Thanks to everyone that posted to help me.

How transfer data from component to another component wia Subject/Observable?

I find interesting example how transfer data from one component to another component using Subject/Observable in Service:
http://plnkr.co/edit/yMBoVkxohwhPig5COgkU?p=preview
I find it similar to broadcast event from Angular 1.X. But I notice that subscribe to data changes can only component that inishiated data change. I need somehow modify this example to get data in one component after another component changed it. Console.log dos't show any error, but data-transfer not working. Can anyone help?
Service:
#Injectable()
export class ClientsService {
private _client$: Subject<Client>;
private _clients$: Subject<Client[]>;
constructor(private http: Http) {
this._client$ = <Subject<Client>>new Subject();
this._clients$ = <Subject<Client[]>>new Subject();
}
getClients(): Promise<Client[]> {
return this.http.get('api/Client')
.toPromise()
.then(res => {
this._clients$.next(res.json());
return res.json();
})
.catch(this.handleError);
}
get client$() {
return this._client$.asObservable();
}
get clients$() {
return this._clients$.asObservable();
}
clientChangeBroadcast(objClient: Client) {
this._client$.next(objClient);
}
clientsChangeBroadcast(arrClients: Client[]) {
this._clients$.next(arrClients);
}
private handleError(error: any): Promise<any> {
return Promise.reject(error.message || error);
}
First component:
#Component({
selector: 'app',
templateUrl: './app/app.component.html'
})
export class AppComponent implements OnInit {
clients: Client[];
constructor(public clientsService: ClientsService) {
this.clients = [];
}
ngOnInit() {
}
loadClients() {
this.clientsService.getClients().then(clients => {
this.clients = clients;
this.clientsService.clientsChangeBroadcast(clients);
});
}
selectClient(objClient: Client) {
this.clientsService.getClients();
this.clientsService.clientChangeBroadcast(objClient);
}
}
Second component:
export class TestComponent implements OnInit {
client: Observable<Client>;
clients: Observable<Client[]>;
constructor(private clinetsService: ClientsService) {
}
ngOnInit() {
//this.clinetsService.getClients();
this.client = this.clinetsService.client$;
this.clients = this.clinetsService.clients$;
this.clinetsService.client$.subscribe(value => {
// try to get changes here
});
this.clinetsService.clients$.subscribe(value => {
// try to get changes here
});
}
reLoadClients() {
this.clinetsService.getClients();
}
}
I try to get data changinf in 'Second component' after data was changed by 'First component'. When I click on button for 'selectClient' method in 'First component' I expect data transfer wia service and I catch changes ob 'Second component' -> it not working. When from 'Second component' I press button for 'reLoadClients' data transfer wia service and I catch changes in all subscribe functions on 'Second component'.

Using hello.js with React.js

I'd like to understand how to make Hello.js work with React.js , especially the custom event handler hello.on
As I'm new to React.js, I don't understand how to bind non React events into the app flow.
I tried putting the event handler in the componentDidMount handler
handleClick(){
hello('twitter').login();
}
componentDidMount(){
hello.on('auth.login', function(auth) {
// Call user information, for the given network
hello(auth.network).api('/me').then(function(r) {
console.log(r);
});
});
hello.init({
'twitter' : 'J1jqqO50tcLtLx8Js0VDitjZW'
},
{
redirect_uri:'/',
oauth_proxy: 'https://auth-server.herokuapp.com/proxy'
});
}
thanks
And 3 years later:
You need a class for authentication, for example:
import * as React from "react";
import * as hello from "hellojs";
import { Event } from "../interfaces/Event";
export class Authentication extends React.Component<{}, { sendEvent: boolean }> {
constructor(public props, public context) {
super(props, context);
this.state = {
sendEvent: true
};
}
public login(network) {
hello.init({
aad: {
name: "Azure Active Directory",
oauth: {
version: 2,
auth: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
grant: "https://login.microsoftonline.com/common/oauth2/v2.0/token"
},
// Authorization scopes
scope: {
// you can add as many scopes to the mapping as you want here
profile: "user.read",
offline_access: ""
},
scope_delim: " ",
login: p => {
if (p.qs.response_type === "code") {
// Let's set this to an offline access to return a refresh_token
p.qs.access_type = "offline_access";
}
},
base: "https://www.graph.microsoft.com/v1.0/",
get: {
me: "me"
},
xhr: p => {
if (p.method === "post" || p.method === "put") {
JSON.parse(p);
} else if (p.method === "patch") {
hello.utils.extend(p.query, p.data);
p.data = null;
}
return true;
},
// Don't even try submitting via form.
// This means no POST operations in <=IE9
form: false
}
});
hello.init(
{
aad: "ClientID"
},
{
redirect_uri: "YOUR REDIRECT_URI",
//redirect_uri: 'https://localhost:4321/temp/workbench.html',
scope: "user.read"
}
);
// By defining response type to code, the OAuth flow that will return a refresh token to be used to refresh the access token
// However this will require the oauth_proxy server
hello(network)
.login({ display: "none" })
.then(
authInfo => {
console.log(authInfo);
localStorage.setItem("logged", authInfo.authResponse.access_token);
},
e => {
console.error("Signin error: " + e.error.message);
}
);
}
//when the component is mounted you check the localstorage
//logged ==> undefined you call login and save a token in localstorage
//logged ==> with a token -> setEvent call a function that use graph api
public componentDidMount() {
let logged = localStorage["logged"];
if (logged === undefined) this.login("aad");
else {
if (this.state.sendEvent) {
this.props.setEvent(null);
this.props.setEvent(Event.GET_ALL_USERS);
}
}
}
public render() {
return null;
}
}
the file name is auth.tsx and you can call this class in the main react class:
export class mainClass extends React.Component{
......
......
private getEvent = (event) => {
this.setState({ event: event });
//HERE YOU recive the event when auth is ready
}
public render(){
<Authentication setEvent={this.getEvent} />
}
}

Resources