← Back to all tutorials

Posting Data to Firebase

Build a complete form that posts data to Firebase — create, display, and delete items in real time.

Posting Data to Firebase

Let's build a complete feature that lets users create, view, and delete posts — all stored in Firebase's Realtime Database.

The Post Form Component

// post-form.component.ts
import { Component } from '@angular/core';
import { DataService } from '../services/data.service';

@Component({
    selector: 'app-post-form',
    templateUrl: './post-form.component.html',
    styleUrls: ['./post-form.component.css']
})
export class PostFormComponent {
    title = '';
    content = '';
    author = '';
    isSaving = false;
    successMessage = '';

    constructor(private dataService: DataService) {}

    onSubmit(): void {
        if (!this.title || !this.content) return;

        this.isSaving = true;
        const post = {
            title: this.title,
            content: this.content,
            author: this.author || 'Anonymous',
            createdAt: new Date().toISOString(),
        };

        this.dataService.createPost(post).subscribe({
            next: (response) => {
                console.log('Saved with key:', response.name);
                this.successMessage = 'Post created successfully!';
                this.isSaving = false;
                this.resetForm();

                // Clear success message after 3 seconds
                setTimeout(() => this.successMessage = '', 3000);
            },
            error: (err) => {
                console.error('Error saving:', err);
                this.isSaving = false;
            }
        });
    }

    resetForm(): void {
        this.title = '';
        this.content = '';
        this.author = '';
    }
}

The Form Template

<!-- post-form.component.html -->
<div class="form-container">
    <h2>Create a New Post</h2>

    <div *ngIf="successMessage" class="success">
        {{ successMessage }}
    </div>

    <form (submit)="onSubmit()">
        <div class="form-group">
            <label for="title">Title</label>
            <input 
                id="title"
                [(ngModel)]="title" 
                name="title" 
                type="text" 
                placeholder="Post title"
                required>
        </div>

        <div class="form-group">
            <label for="author">Author</label>
            <input 
                id="author"
                [(ngModel)]="author" 
                name="author" 
                type="text" 
                placeholder="Your name (optional)">
        </div>

        <div class="form-group">
            <label for="content">Content</label>
            <textarea 
                id="content"
                [(ngModel)]="content" 
                name="content" 
                rows="6"
                placeholder="Write your post..."
                required></textarea>
        </div>

        <button type="submit" [disabled]="isSaving || !title || !content">
            {{ isSaving ? 'Saving...' : 'Publish Post' }}
        </button>
    </form>
</div>

The Post List Component

// post-list.component.ts
export class PostListComponent implements OnInit {
    posts: any[] = [];
    isLoading = true;

    constructor(private dataService: DataService) {}

    ngOnInit(): void {
        this.loadPosts();
    }

    loadPosts(): void {
        this.isLoading = true;
        this.dataService.getPosts().subscribe({
            next: (posts) => {
                this.posts = posts.reverse();  // Newest first
                this.isLoading = false;
            },
            error: () => {
                this.isLoading = false;
            }
        });
    }

    deletePost(id: string): void {
        if (!confirm('Are you sure?')) return;
        
        this.dataService.deletePost(id).subscribe(() => {
            this.posts = this.posts.filter(p => p.id !== id);
        });
    }
}

// post-list.component.html
<div class="post-list">
    <h2>All Posts</h2>

    <div *ngIf="isLoading" class="loading">Loading posts...</div>

    <div *ngIf="!isLoading && posts.length === 0" class="empty">
        No posts yet. Be the first to write one!
    </div>

    <div *ngFor="let post of posts" class="post-card">
        <div class="post-header">
            <h3>{{ post.title }}</h3>
            <button (click)="deletePost(post.id)" class="delete-btn">
                Delete
            </button>
        </div>
        <p class="meta">
            By {{ post.author }} · {{ post.createdAt | date:'medium' }}
        </p>
        <p>{{ post.content }}</p>
    </div>
</div>

Putting It All Together

<!-- app.component.html -->
<app-header></app-header>
<div class="container">
    <app-post-form></app-post-form>
    <app-post-list></app-post-list>
</div>
<app-footer></app-footer>

The App Flow

User fills out form
    │
    ▼
(submit) → PostFormComponent.onSubmit()
    │
    ▼
DataService.createPost(post)
    │  POST /posts.json → Firebase
    ▼
Firebase stores the data
    │  Response: { "name": "-NxAbC123" }
    ▼
Success message shown, form resets

PostListComponent.loadPosts()
    │
    ▼
DataService.getPosts()
    │  GET /posts.json → Firebase
    ▼
Firebase returns all posts
    │  Transform object → array with map()
    ▼
*ngFor renders each post as a card

Form Styles

/* post-form.component.css */
.form-container {
    max-width: 600px;
    margin: 30px auto;
    padding: 30px;
    background: white;
    border-radius: 12px;
    box-shadow: 0 2px 16px rgba(0,0,0,0.08);
}

.form-group {
    margin-bottom: 20px;
}

label {
    display: block;
    margin-bottom: 6px;
    font-weight: 600;
    color: #333;
}

input, textarea {
    width: 100%;
    padding: 10px 14px;
    border: 2px solid #e0e0e0;
    border-radius: 8px;
    font-size: 14px;
    transition: border-color 0.2s;
}

input:focus, textarea:focus {
    outline: none;
    border-color: #3498db;
}

button[type="submit"] {
    width: 100%;
    padding: 12px;
    background: #3498db;
    color: white;
    border: none;
    border-radius: 8px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.2s;
}

button:hover:not(:disabled) { background: #2980b9; }
button:disabled { opacity: 0.6; cursor: not-allowed; }

.success {
    background: #d4edda;
    color: #155724;
    padding: 12px;
    border-radius: 8px;
    margin-bottom: 20px;
}

Congratulations! 🎉

You've built a complete Angular application that:

  • Creates, reads, and deletes data from Firebase
  • Uses services for data management
  • Has reactive forms with two-way binding
  • Displays loading states and success messages
  • Uses pipes for date formatting

Key Takeaways

  • Use [(ngModel)] for form two-way binding (requires FormsModule)
  • POST to Firebase returns a { name: "key" } response with the auto-generated ID
  • Transform Firebase object-of-objects to an array using map()
  • Handle loading states (isLoading) and saving states (isSaving) for UX
  • The Angular pattern: Components → Services → HTTP → Firebase