MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

青灯夜游
リリース: 2022-08-30 20:44:12
転載
1718 人が閲覧しました

Angular アプリケーションを構築するにはどうすればよいですか?次の記事では、MemFire Cloud を使用して Angular アプリケーションを構築する方法を紹介します。

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

[関連チュートリアルの推奨事項: 「angular チュートリアル」]

MemFire Cloud はクラウドです-ベースのデータベースを使用すると、ユーザーはクラウド データベースを作成し、データベースを管理し、データベース上でバックアップ操作を実行できます。また、バックエンドをサービスとして提供するため、ユーザーは 1 分で新しいアプリケーションを作成し、自動生成された API と SDK を使用して、クラウド データベース、オブジェクト ストレージ、ユーザー認証と認可などの機能にアクセスでき、フロントエンドの作成に集中できます。アプリケーション コードを終了し、WEB または APP アプリケーション開発を加速します。

学習ビデオのアドレス: www.bilibili.com/video/BV1wt…

この例では、MemFire Cloud と angular の使用方法を示します。単純なユーザーを構築するための手順 アプリケーションを (最初から) 管理するための手順。これには以下が含まれます:

  • MemFire Cloud クラウド データベース: ユーザー データの保存に使用される MemFireDB データベース。
  • MemFire Cloud ユーザー認証: ユーザーはマジック リンクを使用してログインできます (電子メールのみが必要で、パスワードは必要ありません)。
  • MemFire クラウド ストレージ: ユーザーは写真をアップロードできます。
  • 行レベルのセキュリティ ポリシー: データは保護されるため、個人は自分のデータのみにアクセスできます。
  • インスタント API: データベース テーブルの作成時に API が自動的に生成されます。

このガイドの最後には、ユーザーがログインして基本的なプロファイルの詳細を更新できるアプリケーションが表示されます:

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

Createアプリケーション

目的: ここで作成したアプリケーションを通じてデータベースやクラウドストレージなどの一連のリソースを取得し、アプリケーションの専用APIアクセスリンクとアクセスキーを取得するためのアプリケーションです。ユーザーは上記リソースと簡単に通信できます。対話します。

ログインcloud.memfiredb.com/auth/login アプリケーションの作成

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

データ テーブルの作成

[適用]をクリックします、データ テーブルを視覚的に作成します。

1. プロファイル テーブルを作成します。

#データ テーブル ページで、[新しいデータ テーブル] をクリックします。ページ構成は次のとおりです:

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

プロファイル テーブルのフィールド ID は、auth.users テーブルの ID フィールド (uuid タイプ) の外部キーに関連しています。

2. プロファイルの RLS データ セキュリティ アクセス ルールを有効にします;

作成したプロファイル テーブルを選択し、以下の図に示すようにテーブルの権限バーをクリックし、[RLS を有効にする] をクリックします。ボタン

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

3. 各ユーザーに公開個人情報の表示を許可します;

[新しいルール] ボタンをクリックし、ポップアップ ボックスで [ルール] を選択します。以下に示すように、「すべてのユーザーのアクセスを有効にする」権限」にポリシー名を入力し、「SELECT (クエリ)」操作を選択して、「ポリシーの作成」ボタンをクリックします。

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

4. ユーザーに自分の個人プロフィール情報の追加、削除、変更、確認のみを許可します。

[新しいルール] ボタンをクリックし、以下に示すように、ポップアップ ボックスで「 ユーザー ID に基づいてユーザーのアクセス許可を有効にする」を選択し、ポリシー名を入力して「すべて」操作を選択し、「ポリシーの作成」ボタンをクリックします。

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

アバター バケットの作成

ユーザーのアバター画像を保存するクラウド ストレージ バケットを作成します。必要な操作は次のとおりです:

1. バケット アバターの作成

アプリケーションのクラウド ストレージ ナビゲーション バーで、[新しいバケット] ボタンをクリックしてバケット アバターを作成します。

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

2.各ユーザーにバケットのアバターの表示を許可します

バケットのアバターを選択し、

権限設定列に切り替えて、次の図に示すように、[新しいルール] ボタンをクリックすると、ポリシー編集ポップアップ ボックスが表示され、[カスタム] を選択します。

下の図に示すように、SELECT 操作を選択し、ポリシー名を入力して、[ポリシーの生成] ボタンをクリックします。

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

3. ユーザーにバケット アバターのアップロードを許可します。

バケット アバターを選択し、Permission Settings 列に切り替えて、クリックします。 「新規」 次の図に示すように、「ルール」ボタンをクリックしてポリシー編集ポップアップ ボックスを表示し、「カスタム」を選択します。

MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

INSERT 操作を選択します。以下に示すように、ポリシー名を入力し、「ポリシーの生成」ボタンをクリックします。

1MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

結果の表示

1MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう

すべてのデータ テーブルと RLS SQL (ポリシー名は英語に置き換えられます)

-- Create a table for public "profiles"
create table profiles (
  id uuid references auth.users not null,
  updated_at timestamp with time zone,
  username text unique,
  avatar_url text,
  website text,

  primary key (id),
  unique(username),
);

alter table profiles enable row level security;

create policy "Public profiles are viewable by everyone."
  on profiles for select
  using ( true );

create policy "Users can insert their own profile."
  on profiles for insert
  with check ( auth.uid() = id );

create policy "Users can update own profile."
  on profiles for update
  using ( auth.uid() = id );
-- Set up Storage!
insert into storage.buckets (id, name)
values ('avatars', 'avatars');

create policy "Avatar images are publicly accessible."
  on storage.objects for select
  using ( bucket_id = 'avatars' );

create policy "Anyone can upload an avatar."
  on storage.objects for insert
  with check ( bucket_id = 'avatars' );
ログイン後にコピー

API キーの取得

データベース テーブルをいくつか作成したので、自動生成された API を使用してデータを挿入できます。 API 設定から URL と anon のキーを取得するだけです。

[アプリケーション] -> [概要] ページで、サービス アドレスとトークン情報を取得します。

Anon (公開) キーはクライアント API キーです。ユーザーがログインするまで、データベースへの「匿名アクセス」が許可されます。ログイン後、キーはユーザー自身のログイン トークンに切り替わります。これにより、データの行レベルのセキュリティが有効になります。

注: service_role (秘密) キーは、セキュリティ ポリシーをバイパスして、データへの完全なアクセスを提供します。このキーは秘密にしておき、クライアントやブラウザでは決して使用せず、サーバー環境で使用する必要があります。後続のサンプル コードでは、supabaseUrl と supabaseKey を指定する必要があります。

認証設定

ユーザーが電子メール内のマジック リンクをクリックしてログインするとき、アプリケーションのログイン インターフェイスにジャンプする必要があります。ここでは、認証設定で関連する URL リダイレクトを構成する必要があります。

最終的なアプリケーションはローカル ポート 4200 (または他のポート) で起動されるため、ここでは URL を一時的に http://localhost:4200

に設定します。このインターフェイスで独自の SMTP サーバーをカスタマイズして使用することもできます。

アプリケーションの構築

Angular アプリケーションを最初から構築してみましょう。

プロジェクトの初期化

Angular CLI を使用して、memfiredb-angular:

という名前のプロジェクトを初期化できます。

Angular には Node.js (>=14.15

npm install -g @angular/cli
npx ng new memfiredb-angular --routing false --style css
cd memfiredb-angular
ログイン後にコピー

次に、唯一の追加の依存関係をインストールしましょう: supabase-js

npm install @supabase/supabase-js
ログイン後にコピー

最後に、環境変数をenvironment.tsに保存します。必要なのはAPIです。 anon でコピーした URL とキー。

src/environments/environment.ts ファイル

export const environment = {
  production: false,
  supabaseUrl: "YOUR_SUPABASE_URL",
  supabaseKey: "YOUR_SUPABASE_KEY"
};
ログイン後にコピー

API 認証情報を取得したので、SupabaseService を作成して、ng g s supabase## によって初期化します。 # Supabase クライアントであり、Supabase API と通信するための機能を実装します。

src/app/supabase.service.ts

import { Injectable } from '@angular/core';
import {AuthChangeEvent, createClient, Session, SupabaseClient} from '@supabase/supabase-js';
import {environment} from "../environments/environment";

export interface Profile {
  username: string;
  website: string;
  avatar_url: string;
}

@Injectable({
  providedIn: 'root'
})
export class SupabaseService {
  private supabase: SupabaseClient;

  constructor() {
    this.supabase = createClient(environment.supabaseUrl, environment.supabaseKey);
  }

  get user() {
    return this.supabase.auth.user();
  }

  get session() {
    return this.supabase.auth.session();
  }

  get profile() {
    return this.supabase
      .from('profiles')
      .select(`username, website, avatar_url`)
      .eq('id', this.user?.id)
      .single();
  }

  authChanges(callback: (event: AuthChangeEvent, session: Session | null) => void) {
    return this.supabase.auth.onAuthStateChange(callback);
  }

  signIn(email: string) {
    return this.supabase.auth.signIn({email});
  }

  signOut() {
    return this.supabase.auth.signOut();
  }

  updateProfile(profile: Profile) {
    const update = {
      ...profile,
      id: this.user?.id,
      updated_at: new Date()
    }

    return this.supabase.from('profiles').upsert(update, {
      returning: 'minimal', // Don't return the value after inserting
    });
  }

  downLoadImage(path: string) {
    return this.supabase.storage.from('avatars').download(path);
  }

  uploadAvatar(filePath: string, file: File) {
    return this.supabase.storage
      .from('avatars')
      .upload(filePath, file);
  }
}
ログイン後にコピー

スタイルの更新

インターフェイスがあまり洗練されていないことがわかります。スタイルを更新します。 . 見栄えを良くします。

src/styles.css ファイルを変更します。

html,
body {
  --custom-font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
    Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
  --custom-bg-color: #101010;
  --custom-panel-color: #222;
  --custom-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.8);
  --custom-color: #fff;
  --custom-color-brand: #24b47e;
  --custom-color-secondary: #666;
  --custom-border: 1px solid #333;
  --custom-border-radius: 5px;
  --custom-spacing: 5px;

  padding: 0;
  margin: 0;
  font-family: var(--custom-font-family);
  background-color: var(--custom-bg-color);
}

* {
  color: var(--custom-color);
  font-family: var(--custom-font-family);
  box-sizing: border-box;
}

html,
body,
#__next {
  height: 100vh;
  width: 100vw;
  overflow-x: hidden;
}

/* Grid */

.container {
  width: 90%;
  margin-left: auto;
  margin-right: auto;
}
.row {
  position: relative;
  width: 100%;
}
.row [class^='col'] {
  float: left;
  margin: 0.5rem 2%;
  min-height: 0.125rem;
}
.col-1,
.col-2,
.col-3,
.col-4,
.col-5,
.col-6,
.col-7,
.col-8,
.col-9,
.col-10,
.col-11,
.col-12 {
  width: 96%;
}
.col-1-sm {
  width: 4.33%;
}
.col-2-sm {
  width: 12.66%;
}
.col-3-sm {
  width: 21%;
}
.col-4-sm {
  width: 29.33%;
}
.col-5-sm {
  width: 37.66%;
}
.col-6-sm {
  width: 46%;
}
.col-7-sm {
  width: 54.33%;
}
.col-8-sm {
  width: 62.66%;
}
.col-9-sm {
  width: 71%;
}
.col-10-sm {
  width: 79.33%;
}
.col-11-sm {
  width: 87.66%;
}
.col-12-sm {
  width: 96%;
}
.row::after {
  content: '';
  display: table;
  clear: both;
}
.hidden-sm {
  display: none;
}

@media only screen and (min-width: 33.75em) {
  /* 540px */
  .container {
    width: 80%;
  }
}

@media only screen and (min-width: 45em) {
  /* 720px */
  .col-1 {
    width: 4.33%;
  }
  .col-2 {
    width: 12.66%;
  }
  .col-3 {
    width: 21%;
  }
  .col-4 {
    width: 29.33%;
  }
  .col-5 {
    width: 37.66%;
  }
  .col-6 {
    width: 46%;
  }
  .col-7 {
    width: 54.33%;
  }
  .col-8 {
    width: 62.66%;
  }
  .col-9 {
    width: 71%;
  }
  .col-10 {
    width: 79.33%;
  }
  .col-11 {
    width: 87.66%;
  }
  .col-12 {
    width: 96%;
  }
  .hidden-sm {
    display: block;
  }
}

@media only screen and (min-width: 60em) {
  /* 960px */
  .container {
    width: 75%;
    max-width: 60rem;
  }
}

/* Forms */

label {
  display: block;
  margin: 5px 0;
  color: var(--custom-color-secondary);
  font-size: 0.8rem;
  text-transform: uppercase;
}

input {
  width: 100%;
  border-radius: 5px;
  border: var(--custom-border);
  padding: 8px;
  font-size: 0.9rem;
  background-color: var(--custom-bg-color);
  color: var(--custom-color);
}

input[disabled] {
  color: var(--custom-color-secondary);
}

/* Utils */

.block {
  display: block;
  width: 100%;
}
.inline-block {
  display: inline-block;
  width: 100%;
}
.flex {
  display: flex;
}
.flex.column {
  flex-direction: column;
}
.flex.row {
  flex-direction: row;
}
.flex.flex-1 {
  flex: 1 1 0;
}
.flex-end {
  justify-content: flex-end;
}
.flex-center {
  justify-content: center;
}
.items-center {
  align-items: center;
}
.text-sm {
  font-size: 0.8rem;
  font-weight: 300;
}
.text-right {
  text-align: right;
}
.font-light {
  font-weight: 300;
}
.opacity-half {
  opacity: 50%;
}

/* Button */

button,
.button {
  color: var(--custom-color);
  border: var(--custom-border);
  background-color: var(--custom-bg-color);
  display: inline-block;
  text-align: center;
  border-radius: var(--custom-border-radius);
  padding: 0.5rem 1rem;
  cursor: pointer;
  text-align: center;
  font-size: 0.9rem;
  text-transform: uppercase;
}

button.primary,
.button.primary {
  background-color: var(--custom-color-brand);
  border: 1px solid var(--custom-color-brand);
}

/* Widgets */

.card {
  width: 100%;
  display: block;
  border: var(--custom-border);
  border-radius: var(--custom-border-radius);
  padding: var(--custom-spacing);
}

.avatar {
  border-radius: var(--custom-border-radius);
  overflow: hidden;
  max-width: 100%;
}
.avatar.image {
  object-fit: cover;
}
.avatar.no-image {
  background-color: #333;
  border: 1px solid rgb(200, 200, 200);
  border-radius: 5px;
}

.footer {
  position: absolute;
  max-width: 100%;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  flex-flow: row;
  border-top: var(--custom-border);
  background-color: var(--custom-bg-color);
}
.footer div {
  padding: var(--custom-spacing);
  display: flex;
  align-items: center;
  width: 100%;
}
.footer div > img {
  height: 20px;
  margin-left: 10px;
}
.footer > div:first-child {
  display: none;
}
.footer > div:nth-child(2) {
  justify-content: left;
}

@media only screen and (min-width: 60em) {
  /* 960px */
  .footer > div:first-child {
    display: flex;
  }
  .footer > div:nth-child(2) {
    justify-content: center;
  }
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.mainHeader {
  width: 100%;
  font-size: 1.3rem;
  margin-bottom: 20px;
}

.avatarPlaceholder {
  border: var(--custom-border);
  border-radius: var(--custom-border-radius);
  width: 35px;
  height: 35px;
  background-color: rgba(255, 255, 255, 0.2);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Auth */

.auth-widget {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.auth-widget > .button {
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background-color: #444444;
  text-transform: none !important;
  transition: all 0.2s ease;
}

.auth-widget .button:hover {
  background-color: #2a2a2a;
}

.auth-widget .button > .loader {
  width: 17px;
  animation: spin 1s linear infinite;
  filter: invert(1);
}

/* Account */

.account {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.account > * > .avatarField {
  display: flex;
  align-items: center;
  margin-bottom: 30px;
}

.account > * > .avatarField > .avatarContainer {
  margin-right: 20px;
}

/* Profile Card */

.profileCard {
  border-radius: 5px;
  display: flex;
  border: var(--custom-border);
  background-color: var(--custom-panel-color);
  padding: 20px 20px;
  margin-bottom: 20px;
}

.profileCard:last-child {
  margin-bottom: 0px;
}

.profileCard > .userInfo {
  margin-left: 20px;
  font-weight: 300;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.profileCard > .userInfo > p {
  margin: 0;
}

.profileCard > .userInfo > .username {
  font-size: 1.3rem;
  font-weight: 500;
  margin-bottom: 5px;
}

.profileCard > .userInfo > .website {
  font-size: 0.9rem;
  color: var(--custom-color-brand);
  margin-bottom: 10px;
  text-decoration: none;
}
ログイン後にコピー

ログイン コンポーネントのセットアップ

ログインと登録を管理するために Angular コンポーネントをセットアップしましょう。ユーザーがパスワードを使用せずに電子メールを使用してログインできるように、Magic Links を使用します。 Angular CLI コマンドを使用して

AuthComponent を作成します。 ng c auth##src/app/auth/auth.component.ts

import { Component } from '@angular/core';
import {SupabaseService} from "../supabase.service";

@Component({
  selector: 'app-auth',
  template: `
    <div>
      <form>
        <h1>Memfiredb + Angular</h1>
        <p>使用下面的电子邮件通过魔术链接登录</p>
        <div>
          <input>
        </div>
        <div>
          <button>
          {{loading ? 'Loading' : 'Send magic link'}}
          </button>
        </div>
      </form>
    </div>
  `,
})
export class AuthComponent {
  loading = false;

  constructor(private readonly supabase: SupabaseService) { }

  async handleLogin(input: string) {
    try {
      this.loading = true;
      await this.supabase.signIn(input);
      alert('请检查您的电子邮件以获取登录链接!');
    } catch (error:any) {
      alert(error.error_description || error.message)
    } finally {
      this.loading = false;
    }
  }
}
ログイン後にコピー

#ユーザー情報ページ

#ユーザーがログインすると、プロフィールの詳細を編集し、アカウントを管理できるようになります。 Angular CLI コマンドを使用して AccountComponent を作成します。

ng g c account

##src/app/account/account.component.ts

import {Component, Input, OnInit} from '@angular/core';
import {Profile, SupabaseService} from "../supabase.service";
import {Session} from "@supabase/supabase-js";

@Component({
  selector: 'app-account',
  template: `
    <div>
      <div>
        <label>邮箱</label>
        <input>
      </div>
      <div>
        <label>名称</label>
        <input>
      </div>
      <div>
        <label>网址</label>
        <input>
      </div>

      <div>
        <button>
          {{loading ? 'Loading ...' : 'Update'}}
        </button>
      </div>

      <div>
        <button>
          退出登录
        </button>
      </div>
    </div>
  `
})
export class AccountComponent implements OnInit {
  loading = false;
  profile: Profile | undefined;

  @Input() session: Session | undefined;

  constructor(private readonly supabase: SupabaseService) { }

  ngOnInit() {
    this.getProfile();
  }

  async getProfile() {
    try {
      this.loading = true;
      let {data: profile, error, status} = await this.supabase.profile;

      if (error && status !== 406) {
        throw error;
      }

      if (profile) {
        this.profile = profile;
      }
    } catch (error:any) {
      alert(error.message)
    } finally {
      this.loading = false;
    }
  }

  async updateProfile(username: string, website: string, avatar_url: string = '') {
    try {
      this.loading = true;
      await this.supabase.updateProfile({username, website, avatar_url});
    } catch (error:any) {
      alert(error.message);
    } finally {
      this.loading = false;
    }
  }

  async signOut() {
    await this.supabase.signOut();
  }
}
ログイン後にコピー
プロジェクト エントリ ファイルを変更します

#すべてのコンポーネントの準備ができたので、

AppComponent: を更新しましょう。

src/app/app.component.ts

import {Component, OnInit} from '@angular/core';
import {SupabaseService} from "./supabase.service";

@Component({
  selector: 'app-root',
  template: `
  <div>
    <app-account></app-account>
    <ng-template>
      <app-auth></app-auth>
    </ng-template>
  </div>
  `
})
export class AppComponent implements OnInit {
  session = this.supabase.session;

  constructor(private readonly supabase: SupabaseService) { }

  ngOnInit() {
    this.supabase.authChanges((_, session) => this.session = session);
  }
}
ログイン後にコピー

完成后,在终端窗口中运行它:

npm run start
ログイン後にコピー

然后打开浏览器到 http://localhost:4200,你应该会看到完整的应用程序。

实现:上传头像及更新用户信息

每个 MemFire Cloud项目都配置了存储,用于管理照片和视频等大文件。

创建上传小组件

让我们为用户创建一个头像,以便他们可以上传个人资料照片。使用Angular CLI 命令创建AvatarComponent 。 ng g c avatar

src/app/avatar/avatar.component.ts

import {Component, EventEmitter, Input, Output} from '@angular/core';
import {SupabaseService} from "../supabase.service";
import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser";

@Component({
  selector: 'app-avatar',
  template: `
    <div>
      <img  alt="MemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょう" >
</div>
    <div></div>
    <div>
      <label>
        {{uploading ? 'Uploading ...' : 'Upload'}}
      </label>
      <input>
    </div>
  `,
})
export class AvatarComponent {
  _avatarUrl: SafeResourceUrl | undefined;
  uploading = false;

  @Input()
  set avatarUrl(url: string | undefined) {
    if (url) {
      this.downloadImage(url);
    }
  };

  @Output() upload = new EventEmitter<string>();

  constructor(
    private readonly supabase: SupabaseService,
    private readonly dom: DomSanitizer
  ) { }

  async downloadImage(path: string) {
    try {
      const {data} = await this.supabase.downLoadImage(path);
       if (data instanceof Blob) {
        this._avatarUrl = this.dom.bypassSecurityTrustResourceUrl(
          URL.createObjectURL(data)
        );
      }
    } catch (error:any) {
      console.error('下载图片出错: ', error.message);
    }
  }

  async uploadAvatar(event: any) {
    try {
      this.uploading = true;
      if (!event.target.files || event.target.files.length === 0) {
        throw new Error('必须选择要上载的图像。');
      }

      const file = event.target.files[0];
      const fileExt = file.name.split('.').pop();
      const fileName = `${Math.random()}.${fileExt}`;
      const filePath = `${fileName}`;

      await this.supabase.uploadAvatar(filePath, file);
      this.upload.emit(filePath);
      this.downloadImage(filePath)
    } catch (error:any) {
      alert(error.message);
    } finally {
      this.uploading = false;
    }
  }
}</string>
ログイン後にコピー

然后我们可以在AccountComponent html 模板的顶部添加小部件:

src/app/account/account.component.ts

import {Component, Input, OnInit} from '@angular/core';
import {Profile, SupabaseService} from "../supabase.service";
import {Session} from "@supabase/supabase-js";

@Component({
  selector: 'app-account',
  template: `
      <app-avatar>
    </app-avatar>
    <div>
      <div>
        <label>邮箱</label>
        <input>
      </div>
      <div>
        <label>名称</label>
        <input>
      </div>
      <div>
        <label>网址</label>
        <input>
      </div>

      <div>
        <button>
          {{loading ? 'Loading ...' : 'Update'}}
        </button>
      </div>

      <div>
        <button>
          退出登录
        </button>
      </div>
    </div>
  `
})
export class AccountComponent implements OnInit {
  loading = false;
  profile: Profile | undefined;

  @Input() session: Session | undefined;

  constructor(private readonly supabase: SupabaseService) { }

  ngOnInit() {
    this.getProfile();
  }

  async getProfile() {
    try {
      this.loading = true;
      let {data: profile, error, status} = await this.supabase.profile;

      if (error && status !== 406) {
        throw error;
      }

      if (profile) {
        this.profile = profile;
      }
    } catch (error:any) {
      alert(error.message)
    } finally {
      this.loading = false;
    }
  }

  async updateProfile(username: string, website: string, avatar_url: string = '') {
    try {
      this.loading = true;
      await this.supabase.updateProfile({username, website, avatar_url});
      alert("修改成功")
    } catch (error:any) {
      alert(error.message);
    } finally {
      this.loading = false;
    }
  }

  async signOut() {
    await this.supabase.signOut();
  }
}
ログイン後にコピー

恭喜!在这个阶段,您拥有一个功能齐全的应用程序!

更多编程相关知识,请访问:编程视频!!

以上がMemFire Cloud を使用して Angular アプリケーションを構築する方法について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!