Quick Start Guide for Supabase and Angular - DZone (2023)

  1. Zone D
  2. coding
  3. JavaScript
  4. 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.

Quick Start Guide for Supabase and Angular - DZone (1)Von

rory salvaje


28., 22. June · tutorial

As (2)

save not computer

to share

5,15KPoints of view

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:

Quick Start Guide for Supabase and Angular - DZone (2)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!


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

  1. Gonnaapp.subase.com.
  2. Click New Project.
  3. Enter your project details.
  4. 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.


-- 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 andimmediatelyAPI 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:


npx new superbase-angular --routing false --style csscd superbase-angular

Then we install the only additional dependency:superbase-js


npm install @supbase/supbase-js

And finally, we want to store the environment variables in theenvironment.tsArchive. All we need is the API URL and theimmediatelykey 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.


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 supabasesto initialize the Supabase client and implement functions to communicate with the Supabase API.


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.cssto 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 cCLI command angle.


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-KontosCLI command angle.


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:


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.

Quick Start Guide for Supabase and Angular - DZone (3)

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 avatarCLI command angle.


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:


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!

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



Top Articles
Latest Posts
Article information

Author: Aracelis Kilback

Last Updated: 09/10/2023

Views: 6155

Rating: 4.3 / 5 (64 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Aracelis Kilback

Birthday: 1994-11-22

Address: Apt. 895 30151 Green Plain, Lake Mariela, RI 98141

Phone: +5992291857476

Job: Legal Officer

Hobby: LARPing, role-playing games, Slacklining, Reading, Inline skating, Brazilian jiu-jitsu, Dance

Introduction: My name is Aracelis Kilback, I am a nice, gentle, agreeable, joyous, attractive, combative, gifted person who loves writing and wants to share my knowledge and understanding with you.