diff --git a/app.js b/app.js index d6a0724..a99b7ef 100644 --- a/app.js +++ b/app.js @@ -1,30 +1,24 @@ -const path = require('path'); +const path = require('path'); const express = require('express'); const bodyParser = require('body-parser'); -const adminData = require('./routes/admin'); +const adminRoutes = require('./routes/admin'); const shopRoutes = require('./routes/shop'); const rootDir = require('./util/path'); +const errorController = require('./controller/error'); const app = express(); -// no need to register the engin, as exoress auto register it app.set('view engine', 'ejs'); app.set('views', 'views'); -app.use(bodyParser.urlencoded({extended : true})); +app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static(path.join(rootDir, 'public'))); -app.use('/admin',adminData.routes); +app.use('/admin', adminRoutes); app.use(shopRoutes); -app.use((req, res, next) => { - res.status(404); - res.setHeader('Content-type','text/html'); - // passing the argument to templating engine doesnt change, it remains the same - // "path: 'Error'" we passed becasue ejs engin will check "path" argument in naviagation bar logic of template. if we will not provide, we will get an error - res.render('404', {pageTitle: "404", path: 'Error'}); -}); +app.use(errorController.get404); app.listen(3000); \ No newline at end of file diff --git a/controller/error.js b/controller/error.js new file mode 100644 index 0000000..5d3d895 --- /dev/null +++ b/controller/error.js @@ -0,0 +1,5 @@ +exports.get404 = (req, res, next) => { + res.status(404); + res.setHeader('Content-type', 'text/html'); + res.render('404', { pageTitle: "404", path: 'Error' }); +}; \ No newline at end of file diff --git a/controller/products.js b/controller/products.js new file mode 100644 index 0000000..6ae5786 --- /dev/null +++ b/controller/products.js @@ -0,0 +1,27 @@ +const Product = require("../model/product"); + +exports.getAddProduct = (req, res, next) => { + res.render("addProduct", { + path: "admin/add-product", + pageTitle: "Add Products", + activeAddProduct: true, + formsCSS: true, + productCSS: true + }); +}; + +exports.postAddProduct = (req, res, next) => { + const product = new Product(req.body.title); + product.save(); + + console.log("admin.js ", product); + res.redirect("/"); +}; + +exports.getproduct = (req, res, next) => { + const products = Product.fetchAll(); + res.render("shop", { + pageTitle: "Shop", + prods: products, path: "/" + }); +}; diff --git a/data/products.json b/data/products.json new file mode 100644 index 0000000..8b086a0 --- /dev/null +++ b/data/products.json @@ -0,0 +1 @@ +[{"title":"book"}] \ No newline at end of file diff --git a/model/product.js b/model/product.js new file mode 100644 index 0000000..40bc28c --- /dev/null +++ b/model/product.js @@ -0,0 +1,89 @@ +// no more array, as we will store all our products in a file +// const products = []; + +const fs = require('fs'); +const path = require('path'); + +const rootDir = require('../util/path'); + +module.exports = class Product { + + constructor(t) { + this.title = t; + } + save() { + // no more pushing elements to array + // products.push(this); + + // creating a file + // if u dont want to use, "path" file which is in util folder, directly use the command, which we have provided in "path" file of util folder + // const p = path.join(path.dirname(process.mainModule.filename), 'data', 'products.json'); + + // we will store file in JSON format + const p = path.join(rootDir, 'data', 'products.json') + + // to store the new product, first we need to get existing products and then store new product at the end + // so, first we read the file + // for large file, we will not read file.ie, not putting the file in memory. we will be reading as a stream + // fs.createReadStream() + + // but our file will be shorter, we will read the file + // function in second argument will be executed when reading of file is done + fs.readFile(p, (err, fileContent) => { + // console.log(fileContent); + + //if we run the server, we will get + // ReferenceError: products is not defined at "shop.js" + // we got an error because, we dont have any file... so no content + + // now, if we see error + // console.log(err); + // in console, we can see + // "undefined" + // [Error: ENOENT: no such file or directory, open 'D:\My\vscode\node\5.express\data\products.json'] { + // errno: -4058, + // code: 'ENOENT', + // syscall: 'open', + // path: 'D:\\My\\vscode\\node\\5.express\\data\\products.json' + // } + + + let products = []; + if (!err) { + // parse method will takes incoming JSON data and gives back js array or object or whatever is there in a file + products = JSON.parse(fileContent); + } + // as we are using arrow function, it will reffer to the class. if we will use "function"(es5), it will losse its context and will not reffer to the class + // "this" refferes to the current object of the class + products.push(this); + + // after pushing to array, now we should save it to the file + // "stringify" method will take js object/arary and convert it into JSON format + fs.writeFile(p, JSON.stringify(products), (err) => { + console.log(err); + // we will still get an error, as we are not outputting anything. but we get + // "null" + // but in data folder, "products.json" is craeted where we can see the one object created in form of JSON + + }); + }) + } + + static fetchAll() { + const p = path.join(rootDir, 'data', 'products.json') + + // after stroing it in file, we should reterive the data + fs.readFile(p, (err, fileContent) => { + if(err) { + // if error is there, it will simply gives empty array and comes out of function + return []; + } + // convert json to JS form and pront it out + return JSON.parse(fileContent); + }); + + // running the server, we get + // Cannot read property 'length' of undefined + // this error can be hard to debug + } +} \ No newline at end of file diff --git a/notes.txt b/notes.txt index d5bb9e7..a6a7e17 100644 --- a/notes.txt +++ b/notes.txt @@ -1,38 +1,2 @@ -express js is all about middleware -ie, incoming request will passthrough bunch of functions -thus, there will be more than request handler. - it helps in code segreation - - - -we can have same url for more then one webpage till the time method ccessing that webpages are different -eg: /admin/add-products => GET - /admin/add-products => POST - routes.get('/add-products', (req, res, next) => { - routes.post('/add-products', (req, res, next) => { - - - -res.sendFile('/views/addProducts.html'); -this will cause error, as node will check for a file from root directory of and not from -root directory of the project -thus, "path" module will be used to specify the path to html files. - - - - -this will not work as node will not allow us to acces us the internal files on the browser -ie, localhost:300/public/css/main.css - -to access these static files, we have to modify our main app.js file -we need to serve files statically and stically simply means that its not handles by -router or expressjs or any other middleware. -but should be directly forwarded to file sysytem - - -installing templating engines -npm install --save ejs pug express-handlebars - - -pug: -html syntax is different but if we inspect page, it will shows us proper html code \ No newline at end of file +7.097 +controller/products.js \ No newline at end of file diff --git a/routes/admin.js b/routes/admin.js index 259e70e..c3fe8e1 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -1,22 +1,15 @@ - const path = require('path'); const express = require('express'); -const rootDir = require('../util/path'); +// no more using html pages, as we are using ejs engine +// const rootDir = require('../util/path'); +const productsController = require('../controller/products'); const routes = express.Router(); -const products = []; -routes.get('/add-product', (req, res, next) => { - res.render('addProduct', {path: "admin/add-product", pageTitle : 'Add Products', activeAddProduct: true, formsCSS: true, productCSS: true}) -}); +routes.get('/add-product', productsController.getAddProduct); -routes.post('/add-product', (req, res, next) => { - products.push({'title' : req.body.title}); - console.log('admin.js ', products); - res.redirect('/'); -}); +routes.post('/add-product', productsController.postAddProduct); -module.exports.routes = routes; -module.exports.productArr = products; \ No newline at end of file +module.exports = routes; diff --git a/routes/shop.js b/routes/shop.js index a558eea..fb40926 100644 --- a/routes/shop.js +++ b/routes/shop.js @@ -2,18 +2,10 @@ const path = require('path'); const express = require('express'); -const adminData = require('./admin'); +const productsController = require('../controller/products'); const routes = express.Router(); -routes.get('/', (req, res, next) => { - // "layout: false" is speacial keyword which is understood by handlerbars which tells us that we are not using anhy layouts. thus no error regarding layouts will pop up. - // res.render('shop', {pageTitle: 'Shop', prods : adminData.productArr, path : '/', hasProducts : adminData.productArr.length > 0, layout: false}); - - res.render('shop', {pageTitle: 'Shop', prods : adminData.productArr, path : '/', hasProducts : adminData.productArr.length > 0, activeShop: true, productCSS: true}); - - console.log('shop.js ', adminData.productArr); -}); +routes.get('/', productsController.getproduct); module.exports = routes; - diff --git a/views/shop.ejs b/views/shop.ejs index ca4ba38..4a09fce 100644 --- a/views/shop.ejs +++ b/views/shop.ejs @@ -1,24 +1,14 @@ - - - - <%- include('./includes/head.ejs') %> <%- include('./includes/navigation.ejs') %>
- - - <% if (prods.length > 0) { %>
- <% for (let product of prods) { %>
- -

<%= product.title %>