- Zone D
- coding
- JavaScript
- Quick Start Guide for Supabase and Angular
This example shows the steps to create a simple user management application (from scratch!) using Supabase and Angular.
Von
rory salvaje
·
28., 22. June · tutorial
Join the DZone community and get the full member experience.
Join free
This example shows the steps to create a simple user management application (from scratch!) using Supabase and Angular. Contains:
- superbasedatabase: a Postgres database to store your user data.
- superbaseAuthentication: Users can login with magic links (no passwords, just email).
- superbasestore: Users can upload a photo.
- Row-level security: Data is protected so that people can only access their own data.
- ImmediateAPI: APIs are automatically generated when you create your database tables.
By the end of this guide, you'll have an app that allows users to log in and update some basic profile information:
By clicking this button, the application:
- Start and prepare the Postgres database on Supabase.
- Start the application in Vercel.
- Fork the sample on your own GitHub account.
- Prepare the deployed application with all the necessary environment variables.
If you want to do it yourself, let's get started!
GitHub
Every time you get stuck somewhere, take a lookthis repository.
project settings
Before we start building, let's set up our database and API. This is as easy as starting a new project in Supabase and creating a "schema" in the database.
create a project
- Gonnaapp.subase.com.
- Click New Project.
- Enter your project details.
- Wait for the new database to start.
Configure the database schema
Now let's set up the database schema. We can use the "Startup User Management" quickstart in the SQL Editor, or you can just copy/paste the SQL below and run it yourself.
sql
-- create table for public "profiles", create table profiles (id uuid points to non-null auth.users, updated_at timestamp with timezone, unique username text, avatar_url text, site text, primary key (id ), unique(username) , username_length constraint control (char_length(username) >= 3)); modifying table profiles enables row-level security; Create policy "Public profiles are visible to everyone." in profile to select using ( true ); Create policy "Users can enter their own profile." for profiles insert with tick ( auth.uid() = id ); Create Policy "Users can update their own profile." in profiles to update with ( auth.uid() = id );-- configure realtime!begin; Delete post if subase_realtime is present; create publish supabase_realtime;commit;modify publish supabase_realtime add table profiles;--configure storage!insert into storage.buckets(id,name)values('avatars', 'avatars');create policy The "avatar images "are publicly accessible." in storage.objects to select using (bucket_id = 'avatars'); create policy "Anyone can upload an avatar." in storage.objects to insert with tick(bucket_id = 'avatars');
user interface
Plain text
1. Go to the "SQL" section.2. Click "User Management Launcher".3. Click Run.
Get API keys
Now that you've created some database tables, you can enter data usingAuto-generated API. We only need the url andimmediately
API configuration key.
Plain text
1. Go to the "SQL" section.2. Click "User Management Launcher".3. Click Run.
creating the app
Let's start building the Angular app from scratch.
Initialize an Angular application
we can use thoseCLI Storeto start an application calledsuperbase angular
:
JavaScript
npx new superbase-angular --routing false --style csscd superbase-angular
Then we install the only additional dependency:superbase-js
manga
npm install @supbase/supbase-js
And finally, we want to store the environment variables in theenvironment.ts
Archive. All we need is the API URL and theimmediately
key that you copied earlier. These variables are displayed in the browser and this is perfectly fine since we have row level security enabled on our database.
JavaScript
environment.tsexport const environment = { production: false, supabaseUrl: "YOUR_SUPABASE_URL", supabaseKey: "YOUR_SUPABASE_KEY" };
Now that we have set up the API credentials, let's create anSuperbaseServicecomof g s supabases
to initialize the Supabase client and implement functions to communicate with the Supabase API.
JavaScript
src/app/supabase.service.tsimport { Injetável } from '@angular/core'; import {AuthChangeEvent, createClient, Session, SupabaseClient} from '@supabase/supabase-js'; import {environment} from "../environments /environment"; Schnittstellenprofil exportieren { username: string; Site: Zeichenkette; avatar_url: string;}@Injectable({ providedIn: 'root'})export class SupabaseService { private supabase: SupabaseClient; constructor() { this.supabase = createClient(environment.supabaseUrl, environment.supabaseKey); } get user() { returns this.supabase.auth.user(); } get session() { return this.supabase.auth.session(); } get profile() { return this.supabase .from('profile') .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) { returns this.supabase.auth.signIn({email}); } signOut() { returns 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, { return: 'minimal', // Den Wert nach dem Einfügen nicht zurückgeben }); } downLoadImage(path: string) { returns this.supabase.storage.from('avatars').download(path); } uploadAvatar(filePath: string, file: File) { return this.supabase.storage .from('avatars') .upload(filePath, file); }}
An optional step is to update the CSS filesrc/index.css
to make the app beautiful. You can find the full content of this fileHere.
Configuring a login component
Let's set up an Angular component to manage logins and logins. We use magic links to allow users to sign up with their email address without using passwords. create aAuthentication componentcomauthentication by g c
CLI command angle.
JavaScript
src/app/auth.component.tsimport { Componente } de '@angular/core';importar {SupabaseService} de "./supabase.service";@Component({ selector: 'app-auth', template: ` <div class="row flex flex-center"> <form class="col-6 form-widget"> <h1 class="header">Supabase + Angular</h1> <p class="description">Iniciar sesión con enlace mágico con seu e-mail abaixo</p> <div> <input #input class="inputField" type="email" placeholder="Seu e-mail" /> </div> <div> <button type="enviar" (clique)= "handleLogin(input.value)" class="button block" [disabled]="loading" > {{loading ? 'Loading' : 'Send magic link'}} </button> </div> < / form > < /div> `,}) export class AuthComponent { loading = false; construtor (privado somely leitura Supabase: SupabaseService) { } async handleLogin (input: string) { try { this.loading = true; espere por esto.supabase.signIn(input); alert('¡Verifique su correo electrónico para el enlace de inicio de sesión!'); } catch (error) { alert(error.error_description || error.message) } final { this.loading = false; } }}
account page
Once a user has registered, we may allow them to edit their profile details and manage their account. create aaccount componentcomdes g c-Kontos
CLI command angle.
JavaScript
src/app/account.component.tsimport {Component, Input, OnInit} from '@angular/core';import {Profile, SupabaseService} from "./supabase.service";importiere {Session} from "@supabase/supabase- js";@Component({ selector: 'app-account', template: ` <div class="form-widget"> <div> <label for="email">Email</label> <input id="email " type="text" [value]="session?.user?.email" disabled/> </div> <div> <label for="username">Nome</label> <input #username id="username " type="text" [value]="profile?.username ?? ''" /> </div> <div> <label for="website">Sitio</label> <input #website id="website " type="url" [value]="profile?.website ?? ''" /> </div> <div> <button class="button block primario" (clic)="updateProfile(username.value, website .value)" [deshabilitado]="cargando" > {{cargando ? 'Cargando...' : 'Actualizar'}} </button> </div> <div> <button class="bloque de botones" (Clique) ="signOut()"> Abmelden </button> </div> </div> `}) clase de exportación AccountComponent implementado OnInit { loading = false; Perfil: Perfil | nicht definiert; @Input() Sección: Sección | nicht definiert; Konstruktor (supabase schreibgeschützte privada: SupabaseService) {} ngOnInit() { this.getProfile(); } async getProfile() { tente { this.loading = true; deixe {dados: perfil, erro, status} = await this.supabase.profile; if (error && estado !== 406) { lanzar erro; } if (perfil) { este.perfil = perfil; } } catch (error) { alert(error.message) } final { this.loading = false; } } async updateProfile (nombre de usuario: cadena, sitio web: cadena, avatar_url: cadena = '') { try { this.loading = true; espere this.supabase.updateProfile({nombre de usuario, sitio web, avatar_url}); } catch (error) { alert(error.mensagem); } endlich { this.loading = false; } } async signOut() { espera this.supabase.signOut(); }}
To start!
Now that we have all the components in place, let's updateApplication component:
JavaScript
src/app/app.component.tsimport {Component, OnInit} de '@angular/core';import {SupabaseService} de "./supabase.service";@Component({ selector: 'app-root', plantilla: ` <div class="container" style="padding: 50px 0 100px 0"> <app-account *ngIf="session; else auth" [session]="session"></app-account> <ng-template # auth> <app-auth></app-auth> </ng-template> </div> `}) Export Klasse AppComponent implementiert OnInit { session = this.supabase.session; Konstruktor (private schreibgeschützte Supabase: SupabaseService) {} ngOnInit() { this.supabase.authChanges((_, session) => this.session = session); }}
Once this is done, run this in a terminal window:Start running npm
And then open the browserhost location: 4200and you should see the finished app.
Bonus: profile photos
Every Supabase project is set up with Storage to manage large files like photos and videos.
Create an upload widget
We are going to create an avatar for the user so they can upload a profile picture. create aAvatar Componentcomby g c avatar
CLI command angle.
JavaScript
src/app/avatar.component.tsimport {Componente, EventEmitter, Entrada, Salida} de '@angular/core';importador {SupabaseService} de "./supabase.service";importador {DomSanitizer, SafeResourceUrl} de "@angular/ plataforma-navegador";@Component({ selector: 'app-avatar', plantilla: ` <div> <img *ngIf="_avatarUrl" [src]="_avatarUrl" alt="Avatar" class="imagen de avatar" estilo =" Tamaño: 150px; Tamaño: 150px" ></div> <div *ngIf="!_avatarUrl" class="avatar sin imagen" style=" Tamaño: 150px; Tamaño: 150px"></div> <div style="width: 150px"> <label class="button bloque primario" for="single"> {{uploading ? 'Uploading...' : 'Upload'}} </label> <input style="visibility: versteckt; posição: absolute" type="file" id="single" accept="image/*" (change)="uploadAvatar($event)" [disabled]="uploading" /> </div> `,} ) clase de exportación AvatarComponent { _avatarUrl: SafeResourceUrl | nicht definiert; Hochladen = falso; @Input() set avatarUrl(url: string | indefinido) { if (url) { this.downloadImage(url); } }; @Output() upload = nunca EventEmitter<cadena>(); Konstruktor (sobre una base de lectura privada: SupabaseService, sobre una base de lectura particular: DomSanitizer) { } async downloadImage (ruta: cadena) { try { const {datos} = espera esta.supabase.downLoadImage (ruta); this._avatarUrl = this.dom.bypassSecurityTrustResourceUrl(URL.createObjectURL(datos)); } catch (error) { console.error('Fehler beim Herunterladen des Bildes: ', error.message); } } upload assíncronoAvatar(evento: qualquer) { tente { this.uploading = true; if (!event.target.files || event.target.files.length === 0) { throw new Error('Sie müssen ein Bild zum Hochladen auswählen.'); } arquivo const = event.target.files[0]; const archivoExt = archivo.nombre.split('.').pop(); const fileName = `${Math.random()}.${fileExt}`; const rutaArchivo = `${nombreArchivo}`; Warte auf this.subase.uploadAvatar(filePath, file); this.upload.emit (Dateipfad); } catch (error) { alert(error.mensagem); } endlich { this.uploading = false; } }}
Add the new widget
And then we can add the widget on topaccount componentHTML model:
JavaScript
src/app/account.component.tstemplate: `<app-avatar [avatarUrl]="this.profile?.avatar_url" (upload)="updateProfile(username.value, website.value, $event)"></app -avatar><!-- Eingabefelder -->`
Next steps
At this stage you have a fully functional application!
- You have a question?Ask here.
- Record:app.subase.com.
database JavaScript Fast guide AngularJS Profile (technology) Presentation type of data
Posted on DZone with permission fromrory salvaje. See the original article here.
Opinions expressed by DZone contributors are their own.
Popular in DZone
- Automated performance tests with ArgoCD and Iter8
- Introduction to Kubernetes event-based autoscaling (KEDA)
- How to create and edit Excel XLSX documents in Java
- 8 Great Source Control Tools to Stay in Control
Comments