


Parlons de la façon de créer des applications angulaires à l'aide de MemFire Cloud
Comment créer une application Angular ? L'article suivant vous présentera comment utiliser MemFire Cloud pour créer des applications angulaires. J'espère qu'il vous sera utile !
【Recommandation de didacticiel connexe : "Tutoriel angulaire"】
MemFire Cloud est une base de données cloud qui offre aux utilisateurs la possibilité de créer des bases de données cloud, de gérer la base de données et de sauvegarder la base de données. Il fournit également un backend en tant que service. Les utilisateurs peuvent créer une nouvelle application en 1 minute, utiliser des API et des SDK générés automatiquement et accéder aux bases de données cloud, au stockage d'objets, à l'authentification et à l'autorisation des utilisateurs, ainsi qu'à d'autres fonctions. coder et accélérer le développement d’applications WEB ou APP.
Adresse de la vidéo d'apprentissage : www.bilibili.com/video/BV1wt…
Cet exemple fournit les étapes pour créer une application de gestion d'utilisateurs simple (à partir de zéro) en utilisant MemFire Cloud et angulaire. Cela inclut :
- MemFire Cloud : base de données MemFireDB pour stocker les données utilisateur.
- Vérification de l'utilisateur MemFire Cloud : les utilisateurs peuvent se connecter en utilisant le lien magique (uniquement l'e-mail requis, aucun mot de passe requis).
- MemFire Cloud Storage : les utilisateurs peuvent télécharger des photos.
- Politique de sécurité au niveau de la ligne : les données sont protégées afin que les individus ne puissent accéder qu'à leurs propres données.
- API instantanée : l'API est automatiquement générée lors de la création d'une table de base de données.
À la fin de ce guide, vous disposerez d'une application qui permet aux utilisateurs de se connecter et de mettre à jour certains détails de base de leur profil :
Création de l'application
Objectif : Notre application est créée ici Obtenir une série de ressources tels que les bases de données et le stockage cloud, et obtenez le lien d'accès API exclusif et la clé d'accès de l'application. Les utilisateurs peuvent facilement interagir avec les ressources ci-dessus.
Connexioncloud.memfiredb.com/auth/loginCréer une application
Créer une table de données
Cliquez sur l'application pour créer visuellement la table de données
1 Créer la table des profils ;
Sur les données. page de la table, cliquez sur "Nouvelle table de données", la configuration de la page est la suivante :
où l'identifiant du champ de la table des profils est lié à la clé étrangère du champ id (type uuid) dans la table auth.users.
2. Activez les règles d'accès de sécurité aux données RLS pour les profils ;
Sélectionnez la table Profils créée, cliquez sur la barre d'autorisation de la table, comme indiqué dans la figure ci-dessous, cliquez sur le bouton "Activer RLS"
3. chaque utilisateur pour afficher les informations personnelles publiques ;
Cliquez sur le bouton « Nouvelle règle », dans la boîte de dialogue contextuelle, sélectionnez « Activer l'accès pour tous les utilisateurs », saisissez le nom de la politique, sélectionnez l'opération « SÉLECTIONNER (requête) » et cliquez sur le bouton « Créer une politique », comme indiqué ci-dessous.
4. Autorisez uniquement les utilisateurs à ajouter, supprimer, modifier et vérifier leurs informations de profil personnel ;
Cliquez sur le bouton "Nouvelle règle", dans la boîte contextuelle, sélectionnez "Activer les autorisations d'accès pour les utilisateurs en fonction de l'utilisateur". ID" et entrez le nom de la stratégie. Sélectionnez l'opération "TOUS" et cliquez sur le bouton "Créer une stratégie", comme indiqué ci-dessous.
Créer un bucket d'avatars
Créez un bucket de stockage cloud pour stocker l'image de l'avatar de l'utilisateur. Les opérations impliquées incluent :
1. Créez un bucket d'avatars
Accédez au stockage cloud de la colonne de l'application, cliquez sur. le bouton "Nouveau bucket" pour créer des avatars de bucket.
2. Autorisez chaque utilisateur à afficher les avatars du bucket
Sélectionnez les avatars du bucket, passez à la colonne Paramètres d'autorisation, cliquez sur le bouton "Nouvelle règle", une boîte de dialogue contextuelle d'édition de politique apparaîtra, sélectionnez "Personnalisé", comme le montre l'image ci-dessous :
Sélectionnez l'opération SELECT, entrez le nom de la stratégie et cliquez sur le bouton « Générer une stratégie », comme indiqué dans la figure ci-dessous.
3. Autorisez les utilisateurs à télécharger des avatars de bucket ;
Sélectionnez les avatars de bucket, passez à la colonne Paramètres d'autorisation, cliquez sur le bouton "Nouvelle règle", une boîte de dialogue d'édition de politique apparaîtra, sélectionnez "Personnalisé", comme indiqué ci-dessous Comme indiqué :
Sélectionnez l'opération INSÉRER, entrez le nom de la stratégie et cliquez sur le bouton "Générer une stratégie", comme indiqué dans la figure ci-dessous.
Afficher les résultats
Toutes les tables de données et SQL de RLS (le nom de la stratégie est remplacé par l'anglais)
-- 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' );
Obtenir la clé API
Maintenant que vous avez créé des tables de base de données, vous pouvez utiliser la API générée pour insérer des données. Nous avons juste besoin d'obtenir l'URL et la clé d'anon à partir des paramètres de l'API.
Sur la page Application->Résumé, obtenez l'adresse du service et les informations sur le jeton.
La clé Anon (publique) est la clé API du client. Il permet un « accès anonyme » à votre base de données jusqu'à ce que l'utilisateur se connecte. Après la connexion, la clé est remplacée par le propre jeton de connexion de l'utilisateur. Cela permettra la sécurité au niveau des lignes pour les données.
REMARQUE : La clé service_role (secret) permet un accès complet à vos données, en contournant toute politique de sécurité. Cette clé doit être gardée secrète et utilisée dans un environnement serveur, jamais sur le client ou le navigateur. Dans l’exemple de code suivant, supabaseUrl et supabaseKey doivent être fournis.
Paramètres d'authentification
Lorsque l'utilisateur clique sur le lien magique dans l'e-mail pour se connecter, il doit accéder à l'interface de connexion de notre application. Ici, vous devez configurer la redirection d'URL appropriée dans les paramètres d'authentification.
Parce que notre application finale sera démarrée sur le port local 4200 (ou d'autres ports), nous définissons donc ici temporairement l'url sur http://localhost:4200
De plus, cette interface peut également être personnalisée. Utilisez notre propre smtp serveur.
Créer l'application
Créons une application Angular à partir de zéro.
Initialiser le projet
Nous pouvons utiliser Angular CLI pour initialiser un projet nommé memfiredb-angular
: 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 URL 和您上面anon
复制的密钥。
src/environments/environment.ts文件
export const environment = { production: false, supabaseUrl: "YOUR_SUPABASE_URL", supabaseKey: "YOUR_SUPABASE_KEY" };
现在我们已经有了 API 凭证,通过ng g s supabase
创建一个SupabaseService来初始化 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 g 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 id="Memfiredb-Angular">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
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(); } }
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);
}
}
Copier après la connexionCopier après la connexion Enfin, nous devons enregistrer les variables d'environnement dans Environment.ts. Ce dont nous avons besoin, c'est de l'URL de l'API et de la clé que vous avez copiée ci-dessus anon
.
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); } }
fichier src/environments/environment.tsnpm run start
ng g s supabase
pour initialiser le client Supabase et implémenter des fonctions pour communiquer avec la Supabase API. 🎜🎜src/app/supabase.service.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="Parlons de la façon de créer des applications angulaires à l'aide de MemFire Cloud" > </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>
🎜Mettre à jour le style🎜🎜🎜Vous voyez que l'interface n'est vraiment pas très élégante, mettez à jour le style pour lui donner un aspect mieux. Modifiez le fichier src/styles.css
. 🎜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();
}
}
Copier après la connexionCopier après la connexion
🎜Définir le composant de connexion🎜🎜🎜
🎜🎜Configurons un composant angulaire pour gérer Connectez-vous et inscrivez-vous. Nous utiliserons Magic Links pour que les utilisateurs puissent se connecter en utilisant leur adresse e-mail sans avoir à utiliser de mot de passe. Créez un 🎜AuthComponent à l'aide des commandes Angular CLI. 🎜 ng g c auth
🎜🎜src/app/auth/auth.component.ts🎜rrreee🎜Page d'informations sur l'utilisateur🎜🎜🎜Une fois l'utilisateur connecté , nous pouvons être autorisés à modifier les détails de leur profil et à gérer leur compte. Créez un 🎜AccountComponent à l'aide des commandes Angular CLI. 🎜 ng g c account
🎜🎜src/app/account/account.component.ts🎜rrreee🎜🎜Modifiez le fichier d'entrée du projet🎜🎜🎜Maintenant que tous les composants sont prêts, mettons à jour 🎜AppComponent🎜 :🎜
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(); } }
ng g c auth
🎜🎜src/app/auth/auth.component.ts🎜rrreee🎜Page d'informations sur l'utilisateur🎜🎜🎜Une fois l'utilisateur connecté , nous pouvons être autorisés à modifier les détails de leur profil et à gérer leur compte. Créez un 🎜AccountComponent à l'aide des commandes Angular CLI. 🎜 ng g c account
🎜🎜src/app/account/account.component.ts🎜rrreee🎜🎜Modifiez le fichier d'entrée du projet🎜🎜🎜Maintenant que tous les composants sont prêts, mettons à jour 🎜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="Parlons de la façon de créer des applications angulaires à l'aide de MemFire Cloud" > </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(); } }
恭喜!在这个阶段,您拥有一个功能齐全的应用程序!
更多编程相关知识,请访问:编程视频!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Cet article poursuit l'apprentissage d'Angular, vous amène à comprendre les métadonnées et les décorateurs dans Angular, et comprend brièvement leur utilisation. J'espère qu'il sera utile à tout le monde !

Angular.js est une plateforme JavaScript librement accessible pour créer des applications dynamiques. Il vous permet d'exprimer rapidement et clairement divers aspects de votre application en étendant la syntaxe HTML en tant que langage de modèle. Angular.js fournit une gamme d'outils pour vous aider à écrire, mettre à jour et tester votre code. De plus, il offre de nombreuses fonctionnalités telles que le routage et la gestion des formulaires. Ce guide expliquera comment installer Angular sur Ubuntu24. Tout d’abord, vous devez installer Node.js. Node.js est un environnement d'exécution JavaScript basé sur le moteur ChromeV8 qui vous permet d'exécuter du code JavaScript côté serveur. Être à Ub

Cet article vous donnera une compréhension approfondie du gestionnaire d'état NgRx d'Angular et vous présentera comment utiliser NgRx. J'espère qu'il vous sera utile !

Comment utiliser monaco-editor en angulaire ? L'article suivant enregistre l'utilisation de monaco-editor dans angulaire qui a été utilisé dans une entreprise récente. J'espère qu'il sera utile à tout le monde !

Connaissez-vous Angular Universel ? Cela peut aider le site Web à fournir un meilleur support SEO !

Le projet Angular est trop volumineux, comment le diviser raisonnablement ? L'article suivant vous expliquera comment diviser raisonnablement les projets Angular. J'espère qu'il vous sera utile !

Comment personnaliser le format angulaire-datetime-picker ? L'article suivant explique comment personnaliser le format. J'espère qu'il sera utile à tout le monde !

Cet article partagera avec vous une expérience pratique d'Angular et apprendra comment développer rapidement un système backend en utilisant Angualr combiné avec ng-zorro. J'espère que cela sera utile à tout le monde !
