Intro to MVC
Lesson Objectives
- Define MVC and explain why it matters
- Move our data into a separate file
- Move our presentation code into an EJS file
Define MVC and explain why it matters
- One of the core tenants of good programming is to compartmentalize your code
-
Already our code is getting a little messy
- we have data, app instantiation (listening), and routes all in one file
-
One way to keep an app from getting messy is to separate it out into three sections
-
Models
- data (javascript variables)
-
Views
- how the data is displayed to the user (HTML)
-
Controllers
- the glue that connects the models with the views
-
-
This allows various developers to divide up a large code base
- minimizes likelihood of developers overwriting each others code
-
allows developers to specialize
- one can focus just on getting good with dealing with data
- one can focus just on getting good with html
- one can focus just on getting good with connecting the two
-
Think of MVC as a restaurant
-
Models are the cook
- prepares food/data
-
Views are the customer
- consumes food/data
-
Controllers are the waiter
- brings food from cook to customer
- has no idea how food/data is prepared
- has no idea how the food/data is consumed
-
Move our data into a separate file
- Create a directory called
models
inside our app directory - Inside
/models
, create a data file named fruits.js -
Put your fruits variable in there
const fruits = [ { name:'apple', color: 'red', readyToEat: true }, { name:'pear', color: 'green', readyToEat: false }, { name:'banana', color: 'yellow', readyToEat: true } ];
-
We now require that file in the original
server.js
const fruits = require('./models/fruits.js'); //NOTE: it must start with ./ if it's just a file, not an NPM package
-
But, we could have multiple variables in our
/models/fruits.js
file.- How does javascript know which variable in
/models/fruits.js
to assign to the fruits const inserver.js
(the result of therequire()
statment)? -
We must tell javascript which variable we want to be the result of the
require()
statement inserver.js
//at the bottom of /models/fruits.js module.exports = fruits;
- How does javascript know which variable in
Move our presentation code into an EJS file
Now we want to move our View code (HTML) into a separate file just like we did with the data
-
Install the NPM package EJS (Embedded JavaScript)
- this is a templating library that allows us to mix data into our html
- the HTML will change based on the data!
npm install ejs
- Create a views directory inside our app directory
-
Inside
/views
, create a file called show.ejs- this will be the html for our show route
-
Put some html into show.ejs
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Fruits App</title> </head> <body> <h1>Fruits show page</h1> </body> </html>
-
Now, instead of
res.send('some text')
, we can callres.render('show.ejs')
- express will know to look inside the
/views
directory -
it will send the html in the show.ejs file as a response
app.get('/fruits/:indexOfFruitsArray', (req, res) => { res.render('show.ejs'); });
- express will know to look inside the
Now lets mix our data into our HTML
-
Our route is acting like the controller now. Let's gather the data and pass it to the view
app.get('/fruits/:indexOfFruitsArray', (req, res) => { res.render('show.ejs', { //second param must be an object fruit: fruits[req.params.indexOfFruitsArray] //there will be a variable available inside the ejs file called fruit, its value is fruits[req.params.indexOfFruitsArray] }); });
-
Access the data in the view:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Fruits App</title> </head> <body> <h1>Fruits show page</h1> The <%=fruit.name; %> is <%=fruit.color; %>. <% if(fruit.readyToEat === true){ %> It is ready to eat <% } else { %> It is not ready to eat <% } %> </body> </html>
-
Note that there are two types of new tags
<% %>
run some javascript<%= %>
run some javascript and insert the result of the javascript into the HTML
Update Index Route:
Update the index route in server.js
:
app.get('/fruits/', (request, response) => {
response.render(
'index.ejs',
{
allFruits:fruits
}
);
});
Create an index.ejs
file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Fruits App</title>
</head>
<body>
<h1>Fruits index page</h1>
<ul>
<% for(let i = 0; i < allFruits.length; i++) { %>
<li>
<a href="/fruits/<%=i%>"><%=allFruits[i].name %></a>
</li>
<% } %>
</ul>
</body>
</html>
Add a link back to the index route in show.ejs
:
<a href="/fruits">Back to Index</a>