Finishing YelpCamp and Lessons Learned

So I have finished The Web Developer Bootcamp and the final project, YelpCamp, a full-stack Yelp clone built with Node, Express, Mongo, Mongoose, Passport.js, and Bootstrap.

It took me four months and some change to completely go through the 45 hour course and finish YelpCamp. Here are some of my thoughts on the process.

Reviewing the Basics

A lot of what I learned in the beginning was a refresher on topics I have already learned. I did it anyway, just to make sure I was completely solid on my understanding of the basics.

I thought this was a very important step: there were some things I wasn’t exactly clear on, like DOM manipulation and CSS classes, etc, things I should have mastered before taking the course. It was evident right from the beginning I should continue to go over these introductory parts, as I really needed it.

Meat and Potatoes

Eventually we started going over things like Node, Express, etc. I found that, while these are intermediate topics, these libraries make working with JavaScript much, much easier. They abstract away so much of tediousness of writing JavaScript that I wished I had learned them first which is never a good idea 1.

These sections were the longest and the most hastily explained. For newcomers, this might be a turnoff but Colt has one of the highest rated courses on Udemy 2 so I am sure newcomers won’t be too scared of these sections.

Building YelpCamp

First, let me say: I am somewhat happy with it. It is my first full-stack app, I built it right alongside Colt. I have recently added modifications and with Ian Schroover, I am going to add even more modifications. It is also helping me in my other full-stack app, Check Yo Self as I can apply what I learned in YelpCamp to that app.

The problem is, the course came out almost three years ago. Web dev changes at a breakneck pace. Everything was out of date. Take this snippet for example:

//INDEX - show all campgrounds
router.get("/", function(req, res) {
  if (req.query.search && req.xhr) {
    const regex = new RegExp(escapeRegex(req.query.search), 'gi');
    // Get all campgrounds from DB
    Campground.find({
      name: regex
    }, function(err, allCampgrounds) {
      if (err) {
        console.log(err);
      } else {
        res.status(200).json(allCampgrounds);
      }
    });
  } else {
    // Get all campgrounds from DB
    Campground.find({}, function(err, allCampgrounds) {
      if (err) {
        console.log(err);
      } else {
        if (req.xhr) {
          res.json(allCampgrounds);
        } else {
          res.render("campgrounds/index", {
            campgrounds: allCampgrounds,
            page: 'campgrounds'
          });
        }
      }
    });
  }
});

This is a mess of callback hell that doesn’t 3 exist anymore in 2017. There are promises in ES6, and async/await in ES7. I am sure Colt knows this now and has references to these features in his new course. However, this app is probably over a thousand lines of JavaScript over several modules. I don’t have the time, or the want, to refactor this. I didn’t come up with this idea but it does look good on my portfolio.

End Game

My mission in all this was to learn the basics of full-stack web dev in a pace and learning style I could be successful in. I have done that. Now, it is taking what I learned and working it into Check Yo Self. Pop on over to YelpCamp and give it a look. Tell me what you think.


  1. Some people think you can learn libraries right away without learning the basics. This is erroneous thinking. If you are a junior, like I am, learning the basics will get you hired. There are concepts you need to fully understand before calling yourself a professional JavaScript developer. It’s that simple. 
  2. His newest course, The Advanced Web Developer Bootcamp has a similarly high rating though it isn’t as well-thought out, and it shows in ratings from his previous course’s students. The course uses several teachers but is more up to date and uses React, ES6 and so much more. I plan on buying it when it is on sale again. 
  3. And shouldn’t 

Mission DRY: Accomplished

When working with multiple levels of conditionals, it helps to DRY things up a bit: not repeating yourself can give performance gains as well as make your code more readable and elegant.

Here is one of the monstrosities I had before:

if (currentIcon === "clear-day")   {
  $("body").css("background-image", "url(https://i.imgur.com/voece1h.jpg)");
  }   else if (currentIcon === "partly-cloudy-night")   {
  $("body").css("background-image", "url(https://i.imgur.com/r8haFIj.jpg)");
  }   else if (currentIcon === "clear-night")   {
  $("body").css("background-image", "url(https://i.imgur.com/K6Bazrl.jpg)");
  }   else if (currentIcon === "partly-cloudy-day").  {
  $("body").css("background-image", "url(https://i.imgur.com/dUS9u9b.jpg)");
  }   else if (currentIcon === "cloudy")   {
  $("body").css("background-image", "url(https://i.imgur.com/Kx3ku27.jpg)");
  }   else if (currentIcon === "rain")   {
  $("body").css("background-image", "url(https://i.imgur.com/g4afvja.jpg)");
  }   else if (currentIcon === sleet)   {
  $("body").css("background-image", "url(https://i.imgur.com/pjq3VPO.jpg)");
  }   else if (currentIcon === snow)   {
  $("body").css("background-image", "url(https://i.imgur.com/vH9cyKD.jpg)");
  }   else if (currentIcon === wind)   {
  $("body").css("background-image", "url(https://i.imgur.com/ZtSl66b.jpg)");
  }   else if (currentIcon === fog)   {
  $("body").css("background-image", "url(https://i.imgur.com/5z0CXkZ.jpg)");
}

Really gross, right?

Consulting LinkedIn and Slack proved to be fruitful.

Changing if/else Chains Into Map Objects

A hash map is an object that you can iterate over like an array. The definition of a Map object can be found on the MDN.

Adam Recvlohe, a fellow freeCodeCamp Camper on LinkedIn recommended I use a Map for changing the background of my freeCodeCamp Weather App dynamically. He showed me some code and I eventually settled on this:

const iconMap = {
  "clear-day": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/sunny.jpg)",
  "partly-cloudy-night": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/fineas-anton-136459+copy.jpg)",
  "clear-night": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/sam-mcjunkin-38078.jpg)",
  "partly-cloudy-day": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/jeff-nafura-294909.jpg)",
 "cloudy": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/jonatan-pie-260835.jpg)",
 "rain": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/3opt\_rain.jpeg)",
 "sleet": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/jonatan-pie-190398.jpg)",
 "snow": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/snow.jpg)",
 "wind": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/jon-flobrant-2845.jpg)",
 "fog": "url(https://s3.us-east-2.amazonaws.com/weatherappfcc/elaine-li-416.jpg)"
};

(function() {
  $("body").css("background-image", iconMap[currentIcon]);
})();

Here, we take a Map object and use an anonymous function calls the .css jQuery method on the body which will change the background image by injecting that css into the body. Also as an argument to the css method is an iteration over the iconMap Map object that maps each image to the currently displayed Skycon.

Next: Cleaning Up The if/else Mess of an Icon Display

Up above you probably observed my conditional hell. It was the same for the icons where I called the jQuery show()/hide() methods in if/else statements for every. Icon. Pure insanity.

I went to the Code Newbie Slack and asked Joseph Rex for help as he has been guiding me through a few of the Express and other JavaScript problems I have been having. After some bugs and error handling we came up with a nifty ES6 solution that is much cleaner, using Template Literals to clean up the constant calls to each icon.

// Write a function that takes two parameters
let iconDisplay = (iconName, current) => {
   //Assign a template literal to a constant that will
//represent each icon
   const jqObj = $(`#${iconName}`);
   // Use the ternary operator to determine with the //iconName is the current icon being shown for the condition
//and based on that, show or hide the appropriate icon
   iconName === current ? jqObj.show() : jqObj.hide();
};

 // call the function and compare it to the Skycon for each 
 // Weather condition.
 iconDisplay("clear-day", currentIcon);
 iconDisplay("clear-night", currentIcon);
 iconDisplay("partly-cloudy-day", currentIcon);
 iconDisplay("partly-cloudy-night", currentIcon);
 iconDisplay("cloudy", currentIcon);
 iconDisplay("fog", currentIcon);
 iconDisplay("rain", currentIcon);
 iconDisplay("sleet", currentIcon);
 iconDisplay("snow", currentIcon);
 iconDisplay("wind", currentIcon);

Pretty cool.

Learning Express with The Web Developer Bootcamp

Pretty soon I’ll be diving deep into how much I am learning about Express with The Web Developer Bootcamp. To get a sense of where I was a couple days ago, read this.

Background Image Hacks in CSS

Yesterday 1 I found myself in a situation where the background image in my freeCodeCamp Weather App on mobile was cut off at the bottom. Needed some background image hacks in css to fix it.

For context

My code for switching up the background depending on your weather conditions is as follows:

  if (currentIcon === "clear-day")   {
    $("body").css("background-image", "url(https://i.imgur.com/voece1h.jpg)");
  }   else if (currentIcon === "partly-cloudy-night")   {
    $("body").css("background-image", "url(https://i.imgur.com/r8haFIj.jpg)");
  }   else if (currentIcon === "clear-night")   {
    $("body").css("background-image", "url(https://i.imgur.com/K6Bazrl.jpg)");
  }   else if (currentIcon === "partly-cloudy-day").  {
    $("body").css("background-image", "url(https://i.imgur.com/dUS9u9b.jpg)");
  }   else if (currentIcon === "cloudy")   {
    $("body").css("background-image", "url(https://i.imgur.com/Kx3ku27.jpg)");
  }   else if (currentIcon === "rain")   {
    $("body").css("background-image", "url(https://i.imgur.com/g4afvja.jpg)");
  }   else if (currentIcon === sleet)   {
    $("body").css("background-image", "url(https://i.imgur.com/pjq3VPO.jpg)");
  }   else if (currentIcon === snow)   {
    $("body").css("background-image", "url(https://i.imgur.com/vH9cyKD.jpg)");
  }   else if (currentIcon === wind)   {
    $("body").css("background-image", "url(https://i.imgur.com/ZtSl66b.jpg)");
  }   else if (currentIcon === fog)   {
    $("body").css("background-image", "url(https://i.imgur.com/5z0CXkZ.jpg)");
}


This bug had been bothering me for a week or so. I searched on Stack Overflow for an appropriate solution and found that I could use a div wrapper and add:

body {
   background-size: cover;
   background-repeat: no-repeat;
}

I added the wrapper but nothing happened.

I also already had my main content wrapped in a div:

  <body>
    <div class="wrapper">
      <div class="col-md-12">
        <header>
          <h1 class="h1-title">Local Weather App </h1>
          <h3></h3>
        </header>

Object-fit, etc

You can usually object-fit on an image with the properties: fill, cover, contain, scale-down, or none:

fill

fill

cover

cover

contain

contain

scale-down

scale-down

none

none

I tried object-fit: cover on the body. Didn’t work. Same with contain, scale-down, and fill.

I searched some more and found the answer on a Treehouse forum.

html {
   min-height: 100%;
}

I tried height: 100% on the body but that didn’t work either.

Since the html element is actually at the root of the document and body descends from the html element, applying the global style to the html element actually makes sense.

Also, because I am specifying a minimum height that happens to be a percentage, it makes it responsive because I am not specifying a fixed size in the viewport.

Now, I have a mobile app that looks like this:

Still, I need to fix the loading issue. Thats for another day.

You can find the weather app at https://twhite96.github.io/Weather_App.