100 days of Angular 2 - Day 8: Make the web page look less ugly

Today I'm going to turn this eye sore of a website into something beautiful. Here's what it looks like currently

Bring in Bootstrap

I went over to Bootstrap's website and downloaded the files. Currently I just want the minified CSS, so I added that to my public/ folder in Express -- because I treat the following two directories as static directories in my app.js

app.use(express.static(path.join(__dirname, '../dist')));
app.use(express.static(path.join(__dirname, '../public')));

and added that to the index.html

<link href="bootstrap.min.css" rel="stylesheet">

Done! Err, almost.

This will work in my production environment where I have Express serve up the Angular builds (in the dist/ folder as well as anything in the public/ folder.

But in my dev environment I use webpack-dev-server to serve up most of my HTML/CSS/JavaScript, so I need to add a proxy setting for that so webpack knows to route the request to Express:

devServer: {
    proxy: {
        '/api': {
            target: 'http://localhost:3000',
            secure: false
        },
        '/bootstrap.min.css': {
            target: 'http://localhost:3000',
            secure: false
        }
    }
}

Ok! That did the trick. Already the app looks a little different.

Next I need to do wrap some parts of the page in <div class="container">, use the class="form-control" on forms, and add the class="btn" to any buttons. While I'm doing this I'll change the <input type="text"> to a <textarea>. How are we doing?

Hey! Looking better! What else can we do real quick? Maybe change some of the font colors so the actual Message of the Moment stands out some more. And we'll make the button real big, but also disabled until the user enters a new Message of the Moment.

It's pretty simple with Bootstrap and Angular 2 to conditionally toggle the button's state on/off. The code looks as follows:

<button type="button" class="btn" [disabled]="!newMessage">Declare this message...</button>

where newMessage is the ngModel for the text area and the disabled attribute comes from Bootstrap.

Okay, almost done. Now I just need to add something to handle the...

Server side validation

Right now the user can enter in bad data. Two things that come to mind are:

  • Really long messages. Like 100,000 characters or more.
  • HTML or <script> tags

Remember, one of my goals is to deploy my code to the world wide web every single day (at this address if you're curious). But I couldn't deploy code that had vulnerabilities like cross site scripting!

So I added a quick check when accepting user input. Same as yesterday, it looks like this on the server:

if(req.body.message && req.body.message.length < 500) {
    messageOfTheMoment = req.sanitize(req.body.message);
    res.json({'message': sanitizedMessage});
} else {
    res.json({'error': 'message not set'});
}

The problem is that I don't actually do anything with the error. In other words, the user can type a lengthy message, hit the submit button, but not get a result.

I need a way to show the error message to the user.

Fortunately Bootstrap has the perfect component for this, called Alerts:

So I'll add that above my button, and display it conditionally:

<div *ngIf="validationResponse" class="alert alert-danger" role="alert">{{validationResponse}}</div>

I then add the check to my component, either setting the validationResponse to the error message, or setting it to null so the alert goes away once the user submits a proper Message of the Moment

I did change the API response a little on the server side, to give some more information

router.post('/post-message', function(req, res, next) {
  if(req.body.message && req.body.message.length < 500) {
    let sanitizedMessage = req.sanitize(req.body.message);
    messageOfTheMoment = sanitizedMessage;
    res.json({'message': sanitizedMessage});
  } else {
    res.json({'error': 'message not set', 'length': req.body.message.length});
  }
});

This way the user knows how many characters the current message is and can adjust accordingly.

Here's what it looks like:

Looks good. Now I'll just do a...

Quick check for mobile devices

One of the great things about Bootstrap is that it's responsive. What is responsive? It means that it'll resize and reorder the layout depending on the size of the screen. If you resize the window, the app should respond.

So an easy thing to do is grab the corner of the browser window, start shrinking the page, and see how the page adjusts itself.

I recommend doing this frequently (and making a habit out of it) if you care about mobile/tablet users.

This simulates the page on a big, desktop monitor, then something smaller like a tablet or a lower resolution monitor, and then finally mobile devices / phones.

You can see it does a pretty good job until the very end. The big button at the end gets cut off.

Another thing I'll do real quick is emulate a device's resolution and pixel density. This is found in Chrome's developer console, and probably other browsers as well. You can choose different device presets, such as the Nexus 5X or the iPhone 5, 6, etc.

Again, things look pretty well except for the button being cut off.

One option is to just shorten the message. Another option is to conditionally shorten the message for small screens.

Bootstrap has some neat responsive utility classes that allow you to toggle parts of the page on or off depending on the screen size.

So I just made two buttons, one with shorter text, and they have different classes that'll display or hide them. In essence:

<button class="btn hidden-xs">Declare this message to be the Message of the Moment</button>
<button class="btn visible-xs-block">Declare this message to be the MotM</button>

Which results in the following

This takes care of the button being too wide on mobile devices.

Okay! That's it for today. I think the current version is a good improvement from where we started.

As always, you can see the full code on GitHub here and the live website here.