From a6eacacdc55fa0188bb517b835a14316f6ab57a6 Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Fri, 6 Nov 2020 12:01:00 +0100 Subject: [PATCH] feat: angular guide --- src/common/navigation.yaml | 1 + .../authentication/building-with-angular.md | 213 ++++++++++++++++++ src/pages/authentication/overview.md | 14 +- src/pages/ecosystem/overview.md | 2 +- 4 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 src/pages/authentication/building-with-angular.md diff --git a/src/common/navigation.yaml b/src/common/navigation.yaml index 5fe0ff5c..26ed3c92 100644 --- a/src/common/navigation.yaml +++ b/src/common/navigation.yaml @@ -57,6 +57,7 @@ sections: usePageTitles: true pages: - path: /building-todo-app + - path: /building-with-angular - path: /data-storage pages: - path: /overview diff --git a/src/pages/authentication/building-with-angular.md b/src/pages/authentication/building-with-angular.md new file mode 100644 index 00000000..dde47c00 --- /dev/null +++ b/src/pages/authentication/building-with-angular.md @@ -0,0 +1,213 @@ +--- +title: Building an app with Angular +description: Learn how to integrate authentication within an Angular application +experience: beginners +duration: 30 minutes +tags: + - tutorial +# images: +# large: /images/pages/todo-app.svg +# sm: /images/pages/todo-app-sm.svg +--- + +# Building an with Angular + + + +## Getting started with Angular + +In this tutorial, you'll learn how to work with Stacks Connect when using [Angular](https://angular.io/) as your framework of choice. It builds on what you've learnt in the [Authentication Overview](/authentication/overview). + +-> This article presumes some familiarity with [Angular](https://angular.io/), as well as [Reactive Extensions (RxJS)](https://rxjs.dev/). + +### Prerequisites + +We'll be using the [Angular CLI](https://cli.angular.io/) to scaffold the project, so make sure you've got the latest version installed. We're using version `10.2.0`. + +```sh +npm install --global @angular/cli +``` + +## 1. Scaffold & Run + +Use the `ng new` command to scaffold a new project. We've named ours `ng-stacks-connect`. + +```sh +ng new --minimal --inline-style --inline-template +``` + +Inside the newly created `ng-stacks-connect` directory, we can boot up the development server on [localhost:4200](http://localhost:4200). + +```sh +ng serve +``` + +## 2. Add Stacks Connect + +```sh +npm install --save @stacks/connect blockstack +``` + +-> Note that we're also installing the `blockstack` package, as it's a [peer dependency](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#peerdependencies) of Stacks Connect + +## 3. Declare missing globals + +Some dependencies of these packages were written for a Nodejs environment. In a browser environment, tools such as Webpack (v4) often abstract the polyfilling of Nodejs specific APIs. Using the Angular CLI, this must be done manually. + +-> `Buffer`, for example, is a global class in a Nodejs environment. In the browser is it `undefined` so we must declare it to avoid runtime exceptions + +Add the following snippet to your `src/polyfills.ts` + +```typescript +(window as any).global = window; +(window as any).process = { + version: '', + env: {}, +}; +global.Buffer = require('buffer').Buffer; +``` + +This does 3 things: + +1. Declares `global` to `window` +2. Declares a global `Buffer` class +3. Declares a global `process` object + +## 4. Authentication flow + +Now everything's set up, we're ready to create our auth components + +We can use the CLI's generator to scaffold components. + +### 4.1 Sign In button + +```sh +ng generate component +``` + +Enter the name: `stacks-sign-in-button`. You'll find the newly generated component in `src/app/stacks-sign-in-button`. + +Here's our Sign In button component + +```typescript +import { Component, OnInit, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'app-stacks-sign-in-button', + template: ` `, +}) +export class StacksSignInButtonComponent { + @Output() onSignIn = new EventEmitter(); +} +``` + +### 4.2 Connecting Stacks Connect + +Let's add this button to our `app-root` component (`app.component.ts`) and wire up the `(onSignIn)` event. + +```typescript +@Component({ + selector: 'app-root', + template: ``, +}) +export class AppComponent { + stacksAuth$ = new Subject(); +} +``` + +Here we're using an Rxjs `Subject` to represent a stream of sign in events. `stacksAuth$` will emit when we should trigger the sign in action. + +### 4.3 Authentication + +First, describe the auth options we need to pass to Connect. [Learn more about `AuthOptions` here](https://docs.blockstack.org/authentication/overview). + +```typescript +import { Component } from '@angular/core'; +import { AuthOptions, FinishedData } from '@stacks/connect'; +import { ReplaySubject, Subject } from 'rxjs'; +import { switchMap } from 'rxjs/operators'; + +@Component({ + selector: 'app-root', + template: ` + + +
{{ authResponse$ | async | json }}
+
+ `, +}) +export class AppComponent { + stacksAuth$ = new Subject(); + authResponse$ = new ReplaySubject(1); + + authOptions: AuthOptions = { + finished: response => this.authResponse$.next(response), + appDetails: { name: 'Angular Stacks Connect Demo', icon: 'http://placekitten.com/g/100/100' }, + }; + + ngOnInit() { + this.stacksAuth$ + .pipe(switchMap(() => import('@stacks/connect'))) + .subscribe(connectLibrary => connectLibrary.showBlockstackConnect(this.authOptions)); + } +} +``` + +Let's run through what's going on. In the `authOptions` field, we're using the `finished` handler to emit a value to the `authResponse$` which uses a `ReplaySubject` to persist the latest response. + +-> A [`ReplaySubject`](https://rxjs.dev/api/index/class/ReplaySubject) is an Observable that starts without an initial value, but replays the latest x emissions when subscribed to + +For initial load performance, we're using `import("@stacks/connect")` to only load the Stacks Connect library when it's needed. The `switchMap` operators "switches" out the `stacksAuth$` event for the library. + +The output of `authResponse$` can be added to the template for debugging purposes. This uses Angular's `async` and `json` pipes. + +### 4.3 Loading text + +One problem with the current implementation is that there's a network delay while waiting to load the Connect library. Let's keep track of the loading state and display some text in the sign in button component. + +```typescript +isLoadingConnect$ = new BehaviorSubject(false); + +ngOnInit() { + this.stacksAuth$ + .pipe( + tap(() => this.isLoadingConnect$.next(true)), + switchMap(() => import("@stacks/connect")), + tap(() => this.isLoadingConnect$.next(false)) + ) + .subscribe(connectLibrary => + connectLibrary.showBlockstackConnect(this.authOptions) + ); +} +``` + +We can keep track of it with a [BehaviorSubject](https://rxjs.dev/api/index/class/BehaviorSubject), which always emits its initial value when subscribed to. + +Let's add a `loading` input to the `StacksSignInButtonComponent` component. + +```typescript highlight=3,6 +@Component({ + selector: 'app-stacks-sign-in-button', + template: ` `, +}) +export class StacksSignInButtonComponent { + @Input() loading: boolean; + @Output() onSignIn = new EventEmitter(); +} +``` + +Then, pass the `isLoadingConnect$` Observable into the component, and hide it when the user has already authenticated. + +```html + +``` + +## Next steps + +This tutorial has shown you how to integrate Stacks Connect with an Angular application. You may want to consider abstracting the Stacks Connect logic behind an [Angular service](https://angular.io/guide/architecture-services), or using [Material Design](https://material.angular.io/) to theme your application. diff --git a/src/pages/authentication/overview.md b/src/pages/authentication/overview.md index 09bad0ba..ef3460e4 100644 --- a/src/pages/authentication/overview.md +++ b/src/pages/authentication/overview.md @@ -221,13 +221,13 @@ Follow these steps to create and register a profile for a BNS username (`identif ```jsx "account": [ - { - "@type": "Account", - "service": "twitter", - "identifier": "naval", - "proofType": "http", - "proofUrl": "https://twitter.com/naval/status/12345678901234567890" - } + { + "@type": "Account", + "service": "twitter", + "identifier": "naval", + "proofType": "http", + "proofUrl": "https://twitter.com/naval/status/12345678901234567890" + } ] ``` diff --git a/src/pages/ecosystem/overview.md b/src/pages/ecosystem/overview.md index 337f87b0..0df196bd 100644 --- a/src/pages/ecosystem/overview.md +++ b/src/pages/ecosystem/overview.md @@ -51,7 +51,7 @@ scalable consensus algorithm to increase the number of transactions it can process. This consensus algorithm is planned to be introduced in additional hard forks in 2019. -Addtionally, a future Stacks blockchain will support truly decentralized mobile +Additionally, a future Stacks blockchain will support truly decentralized mobile applications by removing the need to trust a remote Stacks Node. Instead, it will be possible for light clients to calculate the economic weight of different Stacks blockchain forks, and identify the fork with the most