how to use asycn pipe on a promise

64 views
Skip to first unread message

Nhut Thai Le

unread,
Oct 7, 2019, 11:17:14 PM10/7/19
to Angular and AngularJS discussion
Hello,

I'm new to angular and promise/observable and i am trying some basic example to understand them. Here is my example:
I have an interface with 2 promise fields:
export interface Credential {
  readonly uname: Promise<string>;
  readonly pwd: Promise<string>;
}

A service with a method that return the instance of the interface above:
@Injectable({
  providedIn: 'root'
})
export class UserService {
  public getCredential(): Credential {
    let _uname = this.secureStore.get("uname");
    let _pwd = this.secureStore.get("pwd");

    return { uname: _uname, pwd: _pwd };
  }
}

A component that call the service to get the credential object:
@Component({
  selector: 'app-home',
  templateUrl: './home.page.html',
  styleUrls: ['./home.page.scss'],
})
export class HomePage implements OnInit {
  credential: Credential;
  constructor(private userService: UserService) { }

  ngOnInit() {
    this.credential = this.userService.getCredential();
  }
}

Finally my template:
{{ credential.uname | async }}

I'm not sure why there is nothing printed on the screen. Is it normal to have a promise inside an object like the way i define my interface?

Thai

Sander Elias

unread,
Oct 9, 2019, 11:34:15 PM10/9/19
to Angular and AngularJS discussion
Hi Nhut,

It's not very usual to wrap promises inside an object, and it's making handing your data harder.
You can use Promise.all to make your function return a promise that resolves when all data is in.

  public getCredential() {
    return Promise.all([this.secureStore.get('uname'), this.secureStore.get('pwd')]).then(
      ([unamepwd]) => ({ unamepwd })
    );
  }

An observation. You seem to stroe your passwords in plaintext. Which is fine for a demo app, but a huge security risk anywhere else.

Regards
Sander

Nhut Thai Le

unread,
Oct 10, 2019, 10:56:05 AM10/10/19
to ang...@googlegroups.com
Sander,

Thank you for the response. Returning promise makes more sense. I'll change my method accordingly. However, the reason for data not printed out is that 
1. secure storerage crap out earlier when i am running on browser since it only work in mobile device.
2. my form bidning was bad, there was no value passing to secure storage when i set().

About the plain text password, i am aware that it should be hashed and i have no intent to store password in production app. However, is it safe to use secure storerage to keep sensitive data on the device?

--
You received this message because you are subscribed to the Google Groups "Angular and AngularJS discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/angular/5f7be89e-7b37-44a6-960b-7b57e1f5018e%40googlegroups.com.


--
Castor Technologies Inc
460 rue St-Catherine St Ouest, Suite 613 
Montréal, Québec H3B-1A7

CONFIDENTIALITY NOTICE: The information contained in this e-mail is confidential and may be proprietary information intended only for the use of the individual or entity to whom it is addressed. If the reader of this message is not the intended recipient, you are hereby notified that any viewing, dissemination, distribution, disclosure, copy or use of the information contained in this e-mail message is strictly prohibited. If you have received and/or are viewing this e-mail in error, please immediately notify the sender by reply e-mail, and delete it from your system without reading, forwarding, copying or saving in any manner. Thank you.
AVIS DE CONFIDENTIALITE: L’information contenue dans ce message est confidentiel, peut être protégé par le secret professionnel et est réservé à l'usage exclusif du destinataire. Toute autre personne est par les présentes avisée qu'il lui est strictement interdit de diffuser, distribuer ou reproduire ce message. Si vous avez reçu cette communication par erreur, veuillez la détruire immédiatement et en aviser l'expéditeur. Merci.

Sander Elias

unread,
Oct 10, 2019, 12:35:52 PM10/10/19
to Angular and AngularJS discussion
Hi Nhut,

I would say no. AFAIK there is no official standard for this. Even when there is one, you still need to store/retrieve the key to access it, and once the key is in memory of the frontend, its a lost game. 
using tokens like JWT is currently the only option I know that gives some reasonable protection.

Regards
Sander

Nhut Thai Le

unread,
Oct 10, 2019, 1:41:07 PM10/10/19
to ang...@googlegroups.com
Hi Sander,

I just realized I haven't set the context for my question to begin with. I am building a ionic app which base on angular. The secure storage is an ionic plugin which delegates to device native function to store data securely (i presume). So the part of storing, retrieving data from the secure storage is not happening on the browser. Which also explains partly why i could not retrieve data earlier because i was running the app on the desktop browser

Thai

--
You received this message because you are subscribed to the Google Groups "Angular and AngularJS discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.

Hervé Le Cornec

unread,
Oct 23, 2019, 9:47:38 AM10/23/19
to Angular and AngularJS discussion
In my sens you shouldn't do that. 

The | async is a bad practice. 

Prefer using the Elvis operator (myvar?.myproperty) for async variables, and initiate your component in the ngOnInit(), or ngAfterViewInit() in some cases, instead of the constructor.


Sander Elias

unread,
Oct 23, 2019, 10:03:53 AM10/23/19
to Angular and AngularJS discussion
Hi Hervé,

Can you please elaborate on that? The entire Angular team, and NG-RX team, and almost all people I know are advising the async pipe as best practice. (I'm including myself here!)
But millage can vary, so I'm very curious to hear why you think it's a bad practice.

Regards
Sander

Hervé Le Cornec

unread,
Oct 25, 2019, 3:36:10 AM10/25/19
to Angular and AngularJS discussion
Here is your component, with a timeout to simulate an async process to get some user data :
import { ComponentOnInit } from '@angular/core';

@Component({
  selector: 'app-mycomponent',
  templateUrl: './mycomponent.component.html',
  styleUrls: ['./mycomponent.component.css']
})
export class MycomponentComponent implements OnInit {

  customerany;

  constructor() { }

  ngOnInit() {

    setTimeout(()=> {
      this.customer = {
        name: 'Bob',
        age: 25
      }
    }, 1000);

  }
}


And here is the HTML template of your component :
<p>
  mycomponent works!
</p>
<ul>
  <li>name : {{customer?.name}}</li>
  <li>Age : {{customer?.age}}</li>
</ul>


You need nothing else.

Hervé Le Cornec

unread,
Oct 25, 2019, 3:45:04 AM10/25/19
to Angular and AngularJS discussion
Now, if you use an angular service as a store, the async process is the same, you will just feed
store.customer
instead of only
customer
locally in your component.

And in your template you will use
{{store.customer?.name}}
directly, so a change of this will be instantly and natively propagated to all the component imorting the store.

Redux is usefull when coding React, but it is a very bad pratice with Angular that embeds already natively such stores, as services, fully two-way data binding.

Hervé Le Cornec

unread,
Oct 25, 2019, 4:09:26 AM10/25/19
to Angular and AngularJS discussion
Here is the complete solution.

1) Angular store as a service
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class StoreService {

  customerany;

  constructor() { }
}


2) Api service to get the data and store it inside the store (a timeout is used to simulate the async process)
import { Injectable } from '@angular/core';
import { StoreService } from './store.service'

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  constructor(
    private storeStoreService
  ) { }

  getData() {

    setTimeout(()=> {
      this.store.customer = {
        name: 'Bob',
        age: 25
      }
    }, 1000);

  }
}

3) The typescript of your component
import { ComponentOnInit } from '@angular/core';
import { ApiService } from '../api.service'
import { StoreService } from '../store.service'

@Component({
  selector: 'app-mycomponent',
  templateUrl: './mycomponent.component.html',
  styleUrls: ['./mycomponent.component.css']
})
export class MycomponentComponent implements OnInit {

  customerany;

  constructor(
    private apiApiService,
    private storeStoreService
  ) { }

  ngOnInit() {

    this.api.getData();

  }
}

4) The template of your component
<p>
  mycomponent works!
</p>
<ul>
  <li>name : {{store.customer?.name}}</li>
  <li>Age : {{store.customer?.age}}</li>
</ul>


All the components importing the same store are then related by the two way data binding. A change of store.customer.name, for instance, in one of these components will be natively propagated to all other components importing the same store. At any time the store relates the current state of your app. For instance you can backup it (to the server, to the IndexedDB, ...) in order to setup a rewind/forward behavior.

Cheers

Hervé Le Cornec

unread,
Oct 25, 2019, 4:17:01 AM10/25/19
to Angular and AngularJS discussion
Oupps, the declaration of customer in the typescript of the component is of course useless, I forgot to delete it from an older version.
Reply all
Reply to author
Forward
0 new messages