Open In App

Real Estate Management using MEAN

Last Updated : 08 May, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In this tutorial, we’ll create a Real Estate Management Application using Angular for the front end and Express with MongoDB for the back end. With the help of modern web technologies, we can develop applications to streamline property management tasks.

Project Preview:

Screenshot-2024-05-08-005829

Real Estate Management using MEAN

Prerequisites

Approach to Create Real Estate Management

  • Frontend: Use Angular to create a user-friendly interface for the Real Estate Management Application.
  • Backend: Utilize Express with MongoDB to handle data storage and retrieval.
  • Integration: Connect the frontend and backend to enable seamless communication between the user interface and the database.
  • Functionality: Implement features such as viewing properties, adding new properties, adding reviews, and deleting properties to ensure comprehensive management capabilities.

Steps to Create Application

Step 1: Create a server folder

mkdir server

Step 2: Initialize the Node application using the following command.

npm init -y

Step 3: Install the required dependencies:

npm install express mongoose cors body-parser

Updated dependencies will look like

"dependencies": {
        "body-parser": "^1.20.2",
        "cors": "^2.8.5",
        "express": "^4.19.2",
        "mongoose": "^8.3.2"
  }

Folder Structure(Backend)

Screenshot-2024-05-08-010254

Backend Folder Structure

Example:

JavaScript
// server.js

const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const bodyParser = require("body-parser");
const propertyRoutes = require("./routes/propertyRoutes");

const app = express();
const PORT = process.env.PORT || 5000;

app.use(cors());
app.use(express.json());
app.use(bodyParser.json());

mongoose.connect("mongodb://localhost:27017/real_estate", {
    useNewUrlParser: true,
    useUnifiedTopology: true,
}).then(() => {
    console.log("Connected to MongoDB");
}).catch((error) => {
    console.error("MongoDB connection error:", error);
});

app.use("/api/properties", propertyRoutes);

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});
JavaScript
// propertyController.js

const Property = require("../models/Property");

exports.createProperty = async (req, res) => {
    try {
        const { title, description, image, contact, price, area } = req.body;

        if (!title || !description || !image || !contact || !price || !area) {
            return res.status(400).json({ message: "Incomplete property data" });
        }

        const newProperty = new Property({
            title,
            description,
            image,
            contact,
            price,
            area,
            reviews: [],
        });

        const savedProperty = await newProperty.save();
        res.status(201).json(savedProperty);
    } catch (error) {
        console.error("Error adding property:", error);
        res.status(500).json({ message: "Internal Server Error" });
    }
};

exports.getAllProperties = async (req, res) => {
    try {
        const properties = await Property.find();
        res.json(properties);
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
};

exports.getPropertyById = async (req, res) => {
    try {
        const property = await Property.findById(req.params.id);
        if (!property) {
            return res.status(404).json({ message: "Property not found" });
        }
        res.json(property);
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
};

exports.updateProperty = async (req, res) => {
    try {
        const { title, description, image, contact, price, area } = req.body;

        if (!title || !description || !image || !contact || !price || !area) {
            return res.status(400).json({ message: "Incomplete property data" });
        }

        const property = await Property.findByIdAndUpdate(req.params.id, {
            title,
            description,
            image,
            contact,
            price,
            area,
        }, { new: true });

        if (!property) {
            return res.status(404).json({ message: "Property not found" });
        }

        res.json(property);
    } catch (error) {
        console.error("Error updating property:", error);
        res.status(500).json({ message: "Internal Server Error" });
    }
};

exports.deleteProperty = async (req, res) => {
    try {
        const property = await Property.findByIdAndDelete(req.params.id);
        if (!property) {
            return res.status(404).json({ message: "Property not found" });
        }
        res.json({ message: "Property deleted", deletedProperty: property });
    } catch (error) {
        console.error("Error deleting property:", error);
        res.status(500).json({ message: "Internal Server Error" });
    }
};
JavaScript
// Property.js

const mongoose = require("mongoose");

const propertySchema = new mongoose.Schema({
    title: String,
    description: String,
    image: String,
    contact: String,
    price: Number,
    area: Number,
    reviews: [
        {
            user: String,
            rating: Number,
            comment: String,
        },
    ],
});

const Property = mongoose.model("Property", propertySchema);

module.exports = Property;
JavaScript
// propertyRoutes.js

const express = require("express");
const router = express.Router();
const propertyController = require("../controllers/propertyController");

router.post("/", propertyController.createProperty);

router.get("/", propertyController.getAllProperties);

router.get("/:id", propertyController.getPropertyById);

router.put("/:id", propertyController.updateProperty);

router.delete("/:id", propertyController.deleteProperty);

module.exports = router;

To start the server run the following command.

node server.js

Step 4: Set Up the Angular Frontend

Run the following command to install Angular CLI globally:

npm install -g @angular/cli

Step 5: Create Angular Application

ng new client

Folder Structure(Frontend)

Screenshot-2024-05-08-010704

Frontend Folder Structure

Step 6: Install the required dependencies

npm install bootstrap

Dependencies

"dependencies": {
"@angular/animations": "^17.3.0",
"@angular/common": "^17.3.0",
"@angular/compiler": "^17.3.0",
"@angular/core": "^17.3.0",
"@angular/forms": "^17.3.0",
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@angular/router": "^17.3.0",
"bootstrap": "^5.3.3",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
}

Creating and managing files

  • Inside the /client/src/app/components folder, create the necessary components:property-list.component.ts, add-property.component.ts, property-item.component.ts
  • Inside the /client/src/app/services folder create : property.service.ts
  • Inside the /client/src/app/models folder, create: property.model.ts
  • Inside app create app.module.ts
  • update main.ts , styles.css , app.component.html and app.component.ts

Example

HTML
<!-- app/app.component.html -->

<h1>Real Estate Management</h1>
<app-add-property (propertyAdded)="onPropertyAdded($event)">
    </app-add-property>

<!-- Filter Options -->
<div>
  <label for="sortBy">Sort By:</label>
  <select
    id="sortBy"
    [(ngModel)]="filterOptions.sortBy"
    (change)="applyFilter()"
  >
    <option value="">None</option>
    <option value="price">Price</option>
    <option value="area">Area</option>
  </select>
  <label for="sortOrder">Sort Order:</label>
  <select
    id="sortOrder"
    [(ngModel)]="filterOptions.sortOrder"
    (change)="applyFilter()"
  >
    <option value="asc">Ascending</option>
    <option value="desc">Descending</option>
  </select>
</div>

<app-property-list
  [properties]="filteredProperties"
  (deleteProperty)="onDeleteProperty($event)"
></app-property-list>
CSS
/* styles.css */

input {
    border: 2px solid black;
}

button {
    background-color: #007BFF;
    color: #fff;
    border: none;
    padding: 10px;
    cursor: pointer;
    border-radius: 4px;
}

button:hover {
    background-color: #0056b3;
}

h1,
h2 {
    text-align: center;
}

/* Property List component */
.property-list {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

.property-card {
    border: 1px solid #ddd;
    border-radius: 18px;
    padding: 15px;
    width: -moz-fit-content;
    width: fit-content;
    box-shadow: 0 14px 18px rgba(0, 0, 0, 0.1);
    background-color: #fff;
    margin-bottom: 3rem;
}

.property-card h3 {
    margin-bottom: 10px;
}

.property-card button {
    background-color: #007BFF;
    color: #fff;
    border: none;
    padding: 8px;
    cursor: pointer;
    border-radius: 4px;
}

.property-card button:hover {
    background-color: #0056b3;
}

img {
    height: 200px;
    width: 300px;
    border-radius: 10px;
    margin-bottom: 10px;
}

/* AddProperty component */
.form-container {
    max-width: 300px;
    margin: 20px auto;
    padding: 20px;
    background-color: #f7f7f7;
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.form-row {
    display: flex;
    gap: 20px;
    margin-bottom: 15px;
}

.form-row label {
    flex: 1;
}

.form-row input {
    flex: 2;
    padding: 8px;
    width: 100%;
    box-sizing: border-box;
}

/* GFG style */
.gfg {
    background-color: green;
    text-align: center;
    color: white;
    padding: 15px;
    border-radius: 10px;
    margin-bottom: -20px;
}

.list {
    margin-top: -50px;
}
JavaScript
// components/add-property.component.ts
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Property } from '../models/property.model';
import { PropertyService } from '../services/property.service';

@Component({
    selector: 'app-add-property',
    template: `
    <div>
      <h2 style="color: #007BFF;">Add a New Property</h2>
      <form (submit)="addProperty()">
        <div class="form-row">
          <label
            >Title:
            <input
              type="text"
              [(ngModel)]="newProperty.title"
              name="title"
              required
            />
          </label>
          <label
            >Description:
            <input
              type="text"
              [(ngModel)]="newProperty.description"
              name="description"
              required
            />
          </label>
        </div>
        <div class="form-row">
          <label
            >Image URL:
            <input
              type="text"
              [(ngModel)]="newProperty.image"
              name="image"
              required
            />
          </label>
          <label
            >Contact:
            <input
              type="text"
              [(ngModel)]="newProperty.contact"
              name="contact"
              required
            />
          </label>
        </div>
        <div class="form-row">
          <label
            >Price:
            <input
              type="number"
              [(ngModel)]="newProperty.price"
              name="price"
              required
            />
          </label>
          <label
            >Area (sq/feet):
            <input
              type="number"
              [(ngModel)]="newProperty.area"
              name="area"
              required
            />
          </label>
        </div>
        <button type="submit" style="background-color: blue;">
          Add Property
        </button>
      </form>
    </div>
  `,
    styles: [],
})
export class AddPropertyComponent implements OnInit {
    newProperty: Property = {
        title: '',
        description: '',
        image: '',
        contact: '',
        price: 0,
        area: 0,
    };

    @Output() propertyAdded = new EventEmitter<Property>();

    constructor(private propertyService: PropertyService) { }

    ngOnInit(): void { }

    addProperty(): void {
        this.propertyService.addProperty(this.newProperty).subscribe(
            (res: Property) => {
                this.propertyAdded.emit(res);
                this.newProperty = {
                    title: '',
                    description: '',
                    image: '',
                    contact: '',
                    price: 0,
                    area: 0,
                };
            },
            (error) => console.error(error)
        );
    }
}
JavaScript
//components/property-item.component.ts

import { Component, Input } from '@angular/core';
import { Property } from '../models/property.model';

@Component({
    selector: 'app-property-item',
    template: `
    <div>
      <h3>{{ property.title }}</h3>
      <p>{{ property.description }}</p>
      <img [src]="property.image" alt="{{ property.title }}" />
      <p>Contact: {{ property.contact }}</p>
    </div>
  `,
})
export class PropertyItemComponent {
    @Input() property!: Property;

    constructor() { }
}
JavaScript
//components/property-list.component.ts

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Property } from '../models/property.model';
import { PropertyService } from '../services/property.service';

@Component({
    selector: 'app-property-list',
    template: `
    <div class="property-list">
      <div *ngFor="let property of properties" class="property-card">
        <h3>{{ property.title }}</h3>
        <p>{{ property.description }}</p>
        <p>Price: {{ property.price }}</p>
        <p>Area: {{ property.area }} sq/ft</p>
        <img [src]="property.image" alt="{{ property.title }}" />
        <p>Contact: {{ property.contact }}</p>
        <button (click)="onDeleteProperty(property._id)">Delete</button>
      </div>
    </div>
  `,
    styles: [
        // Styles remain the same
    ],
})
export class PropertyListComponent implements OnInit {
    @Input() properties: Property[] = [];
    @Output() deleteProperty = new EventEmitter<string>();

    constructor(private propertyService: PropertyService) { }

    ngOnInit(): void { }

    onDeleteProperty(id: string | undefined): void {
        if (id) {
            this.propertyService.deleteProperty(id).subscribe(
                () => {
                    this.properties = this.properties.filter(
                        (property) => property._id !== id
                    );
                },
                (error) => console.error(error)
            );
        }
    }
}
JavaScript
// models/property.model.ts

export interface Property {
    _id?: string;
    title: string;
    description: string;
    image: string;
    contact: string;
    price: number;
    area: number;
    reviews?: Review[];
}

export interface Review {
    user: string;
    rating: number;
    comment: string;
}
JavaScript
//services/property.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Property } from '../models/property.model';

@Injectable({
    providedIn: 'root',
})
export class PropertyService {
    private apiUrl = 'http://localhost:5000/api/properties';

    constructor(private http: HttpClient) { }

    getAllProperties():
        Observable<Property[]> {
        return this.http.get<Property[]>
            (this.apiUrl);
    }

    addProperty(property: Property):
        Observable<Property> {
        return this.http.post<Property>
            (this.apiUrl, property);
    }

    deleteProperty(id: string):
        Observable<any> {
        return this.http
            .delete(`${this.apiUrl}/${id}`);
    }

    addReview(id: string, review: any):
        Observable<Property> {
        return this.http.post<Property>
            (`${this.apiUrl}/${id}/review`, review);
    }

    getFilteredProperties(params: any):
        Observable<Property[]> {
        return this.http.get<Property[]>
            (this.apiUrl, { params: params });
    }
}
JavaScript
// app.component.ts

import { Component, OnInit } from '@angular/core';
import { Property, Review } from './models/property.model'; // Import Review
import { PropertyService } from './services/property.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
    properties: Property[] = [];
    filteredProperties: Property[] = [];
    filterOptions = { sortBy: '', sortOrder: 'asc' };

    constructor(private propertyService: PropertyService) { }

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

    getAllProperties(): void {
        this.propertyService.getAllProperties().subscribe(
            (res: Property[]) => {
                this.properties = res;
                this.applyFilter();
            },
            (error) => console.error(error)
        );
    }

    onPropertyAdded(property: Property): void {
        this.properties.push(property);
        this.applyFilter();
    }

    onDeleteProperty(id: string): void {
        this.properties = this.properties
            .filter((property) => property._id !== id);
        this.applyFilter();
    }

    applyFilter(): void {
        this.filteredProperties = this.properties.slice();
        if (this.filterOptions.sortBy) {
            this.filteredProperties.sort((a, b) => {
                if (this.filterOptions.sortBy === 'price') {
                    return this.filterOptions.sortOrder === 'asc'
                        ? a.price - b.price
                        : b.price - a.price;
                } else if (this.filterOptions.sortBy === 'area') {
                    return this.filterOptions.sortOrder === 'asc'
                        ? a.area - b.area
                        : b.area - a.area;
                } else {
                    return 0;
                }
            });
        }
    }
}
JavaScript
//app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms'; // Import FormsModule

import { AppComponent } from './app.component';
import { AddPropertyComponent } from './components/add-property.component';
import { PropertyListComponent } from './components/property-list.component';
import { PropertyItemComponent } from './components/property-item.component';
import { PropertyService } from './services/property.service';

@NgModule({
    declarations: [
        AppComponent,
        AddPropertyComponent,
        PropertyListComponent,
        PropertyItemComponent,
    ],
    imports: [
        BrowserModule,
        HttpClientModule,
        FormsModule,
    ],
    providers: [PropertyService],
    bootstrap: [AppComponent],
})
export class AppModule { }
JavaScript
//main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule)
    .catch(err => console.error(err));

To start the frontend run the following command.

ng serve

Output



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads