Property Listing Platform using Node and ExpressJS
This tutorial can help you build a foundational understanding of the backend development. NodeJS and ExpressJS are used to build the backend infrastructure of the website and ReactJS is used for the front end of the project. With this project, you can learn essential concepts and best practices for building modern web applications.
Output Preview: Let us have a look at how the final output will look like.
Prerequisites:
Approach to create Property List App:
- Initialize the node project and install necessary dependencies.
- Set up the express server.
- Create react app and design it accordingly.
- Use cors for cross-domain communication.
Steps to Create NodeJS App and Installing Module:
Step 1: Create a new directory named backend.
mkdir backend
cd backend
Step 2: Create a server using the following command.
npm init -y
Step 3: Install necessary dependencies using the following command:
npm install express cors
Project Structure:
The updated dependencies in package.json file of backend will look like:
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.2"
}
Example: Below is an example of creating a server of property listing platform.
Javascript
// index.js const express = require( 'express' ); const cors = require( 'cors' ); const app = express(); const port = 5000; app.use(cors()); const propertySchema = { name: String, description: String, numberOfRooms: Number, washroom: Number, kitchen: Boolean, hall: Boolean, amenities: [String] }; // Temporary storage for properties let properties = [ { id: 1, name: "Luxury Beachfront Villa" , location: "Malibu, California" , room: 7, img: "https://cdn-icons-png.flaticon.com/512/48/48770.png" , price: 1500000, amenities: [ "Private Beach Access" , "Infinity Pool" , "Home Theater" ] }, { id: 2, name: "Charming Cottage" , location: "Cotswolds, England" , room: 3, img: "https://cdn-icons-png.flaticon.com/512/48/48775.png" , price: 400000, amenities: [ "Fireplace" , "Garden" , "Country Views" ] }, { id: 3, name: "Modern Downtown Loft" , location: "New York City, New York" , room: 2, img: "https://cdn-icons-png.flaticon.com/512/47/47636.png" , price: 800000, amenities: [ "City Views" , "Gym" , "Concierge Service" ] }, { id: 4, name: "Rustic Mountain Cabin" , location: "Aspen, Colorado" , room: 4, img: "https://cdn-icons-png.flaticon.com/512/209/209357.png" , price: 600000, amenities: [ "Hot Tub" , "Ski-In/Ski-Out Access" , "Wood-Burning Fireplace" ] }, { id: 5, name: "Paris Apartment" , location: "Paris, France" , room: 6, img: "https://cdn-icons-png.flaticon.com/256/509/509790.png" , price: 2500000, amenities: [ "Terrace" , "Panoramic City Views" , "24/7 Security" ] }, { id: 6, name: "Secluded Lakeside Retreat" , location: "Lake District, England" , room: 5, img: "https://cdn-icons-png.flaticon.com/512/58/58167.png" , price: 1000000, amenities: [ "Private Dock" , "Boathouse" , "Tranquil Surroundings" ] } ]; // Route to list properties app.get( '/properties' , (req, res) => { res.json(properties); }); // Route to create a new property app.post( '/properties' , (req, res) => { const newProperty = req.body; properties.push(newProperty); res.status(201).json({ message: 'Property created successfully' , property: newProperty }); }); app.listen(port, () => { console.log(`Server is running on port ${port}`); }); |
Start the server with the following command.
node index.js
Steps to Create the Frontend App and Installing Module:
Step 1: Create the frontend repository named client in the main repository.
mkdir client
cd client
Step 2: Create React project using following command.
npx create-react-app .
Project Structure:
Example: Create the files according to the project structure and write the following code.
CSS
.home-container { display : flex; flex- direction : column; align-items: center ; } .filter { margin-bottom : 20px ; } .filter label { margin-right : 10px ; } .filter input { margin-right : 10px ; padding : 5px ; border : 1px solid #ccc ; } .filter button { padding : 5px 10px ; background-color : #007bff ; color : #fff ; border : none ; cursor : pointer ; } .filter button:hover { background-color : #0056b3 ; } .property-list { display : grid; grid-template-columns: repeat (auto-fill, minmax( 300px , 1 fr)); grid-gap: 20px ; } .property-list p { font-style : italic ; color : #888 ; } .navbar { background-color : #333334 ; color : #fff ; padding : 10px 20px ; margin-bottom : 20px ; } .logo { font-size : 1.5 rem; font-weight : bold ; } .property-card { display : inline- block ; border : 1px solid #ccc ; border-radius: 5px ; margin : 10px ; } .property-image { display : inline- block ; width : 200px ; } .property-image img { width : 100% ; height : auto ; } .property-details { display : inline- block ; vertical-align : top ; margin-left : 10px ; padding : 10px ; } .property-details h 2 { margin-top : 0 ; } .property-details p { margin : 5px 0 ; } |
Javascript
// App.js import React from 'react' ; import Navbar from './Navbar.js' ; import Home from './Home' ; import './index.css' ; function App() { return ( <div className= "App" > <Navbar /> <Home /> </div> ); } export default App; |
Javascript
import React, { useState, useEffect } from 'react' ; import PropertyCard from './PropertyCard' ; import './index.css' ; // Import CSS file for styling function Home() { const [properties, setProperties] = useState([]); const [filteredProperties, setFilteredProperties] = useState([]); const [filters, setFilters] = useState({ minPrice: '' , maxPrice: '' , minRooms: '' , maxRooms: '' }); useEffect(() => { // Fetch properties from the backend fetch( 'http://localhost:5000/properties' ) .then(response => response.json()) .then(data => { setProperties(data); setFilteredProperties(data); // Initialize filtered properties with all properties }) . catch (error => console.error( 'Error fetching properties:' , error)); }, []); const applyFilters = () => { let filtered = properties; if (filters.minPrice !== '' && filters.maxPrice !== '' ) { filtered = filtered.filter(property => property.price >= filters.minPrice && property.price <= filters.maxPrice); } if (filters.minRooms !== '' && filters.maxRooms !== '' ) { filtered = filtered.filter(property => property.room >= filters.minRooms && property.room <= filters.maxRooms); } setFilteredProperties(filtered); }; const handleFilterChange = event => { const { name, value } = event.target; setFilters({ ...filters, [name]: value }); }; return ( <div className= "home-container" > <div className= "filter" > <label>Minimum Price:</label> <input type= "number" name= "minPrice" value={filters.minPrice} onChange={handleFilterChange} /> <label>Maximum Price:</label> <input type= "number" name= "maxPrice" value={filters.maxPrice} onChange={handleFilterChange} /> <label>Minimum Rooms:</label> <input type= "number" name= "minRooms" value={filters.minRooms} onChange={handleFilterChange} /> <label>Maximum Rooms:</label> <input type= "number" name= "maxRooms" value={filters.maxRooms} onChange={handleFilterChange} /> <button onClick={applyFilters}>Apply</button> </div> <div className= 'parent-property' > <div className= "property-list" > {filteredProperties.length > 0 ? ( filteredProperties.map(property => ( <PropertyCard key={property.id} property={property} /> )) ) : ( <p>No properties found</p> )} </div> </div> </div> ); } export default Home; |
Javascript
import React from 'react' ; function PropertyCard({ property }) { const { id, name, location, room, img, price, amenities } = property; return ( <div className= "property-card" > <div className= "property-image" > <img src={`${img}`} alt={name} /> </div> <div className= "property-details" > <h2>{name}</h2> <p>Location: {location}</p> <p>Rooms: {room}</p> <p>Price: ${price}</p> <p>Amenities: {amenities.join( ', ' )}</p> </div> </div> ); } export default PropertyCard; |
Javascript
import React, { useState, useEffect } from 'react' ; import PropertyCard from './PropertyCard.js' ; import './index.css' ; function Home() { const [properties, setProperties] = useState([]); const [filteredProperties, setFilteredProperties] = useState([]); const [filters, setFilters] = useState({ minPrice: '' , maxPrice: '' , minRooms: '' , maxRooms: '' }); useEffect(() => { // Fetch properties from the backend fetch( 'http://localhost:5000/properties' ) .then(response => response.json()) .then(data => { setProperties(data); setFilteredProperties(data); }) . catch (error => console.error( 'Error fetching properties:' , error)); }, []); const applyFilters = () => { let filtered = properties; if (filters.minPrice !== '' && filters.maxPrice !== '' ) { filtered = filtered.filter( property => property.price >= filters.minPrice && property.price <= filters.maxPrice); } if (filters.minRooms !== '' && filters.maxRooms !== '' ) { filtered = filtered.filter( property => property.room >= filters.minRooms && property.room <= filters.maxRooms); } setFilteredProperties(filtered); }; const handleFilterChange = event => { const { name, value } = event.target; setFilters({ ...filters, [name]: value }); }; return ( <div className= "home-container" > <div className= "filter" > <label>Minimum Price:</label> <input type= "number" name= "minPrice" value={filters.minPrice} onChange={handleFilterChange} /> <label>Maximum Price:</label> <input type= "number" name= "maxPrice" value={filters.maxPrice} onChange={handleFilterChange} /> <label>Minimum Rooms:</label> <input type= "number" name= "minRooms" value={filters.minRooms} onChange={handleFilterChange} /> <label>Maximum Rooms:</label> <input type= "number" name= "maxRooms" value={filters.maxRooms} onChange={handleFilterChange} /> <button onClick={applyFilters}>Apply</button> </div> <div className= 'parent-property' > <div className= "property-list" > {filteredProperties.length > 0 ? ( filteredProperties.map(property => ( <PropertyCard key={property.id} property={property} /> )) ) : ( <p>No properties found</p> )} </div> </div> </div> ); } export default Home; |
Start the project using the given command.
npm start
Output:
Contact Us