Intro to MVC




Lesson Objectives

  1. Define MVC and explain why it matters
  2. Move our data into a separate file
  3. 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

  1. Create a directory called models inside our app directory
  2. Inside /models, create a data file named fruits.js
  3. 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
        }
    ];    


  1. 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
  2. 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 in server.js (the result of the require() statment)?
    • We must tell javascript which variable we want to be the result of the require() statement in server.js

      //at the bottom of /models/fruits.js
      module.exports = fruits;



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

  1. 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
  2. Create a views directory inside our app directory
  3. Inside /views, create a file called show.ejs

    • this will be the html for our show route
  4. 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>    
  5. Now, instead of res.send('some text'), we can call res.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');
      });        

Now lets mix our data into our HTML

  1. 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]
        });
    });    
  2. 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>
  3. 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>



References