The Model-View-Controller (also known as MVC) in many ways is the cornerstone of modern web application development. Through seperation of these three major aspects of an application we are able to ensure that our product is not only a solid user experience but a structured development experience as well. Before we get into what MVC is and how we can facilitate it in modern Web Application development, we need to ensure that we're up to scratch with our basic web technologies.
The Hyper Text Markup Language, HTML in layman's terms, provides the means of structuring our
web pages. Web Browsers will render an HTML document as a web page, the .html
file acting
as blueprints for the browser's rendering engine.
The best part is that HTML is also incredibly simple to write up; a simple page with the words "Hello World" on it looking like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document Title</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
There are two types of major HTML elements:
- Structure Elements
- Elements which define the major containers and layout of the page are considered to be structure elements
- Structure elements will often contain one, possibly many other structure and content elements
- Content Elements
- Elements which take in attributes to produce an output are content elements.
- Text and control elements are examples of content elements
- Content elements usually need to be contained within a structure element
Examples of Structure and Content Elements
Structure Elements | Content Elements |
---|---|
<div> |
<h1>, <h2>, <h3> ... |
<section> |
<button> |
<table> |
<input> |
<form> |
<p> |
<aside> |
<a> |
<header>,<main> & <footer> |
<b>,<i> & <u> |
When developing web applications it's good to ensure you try to make the website as accessible as possible so that you can reach the broadest audience. The W3 organisation has created a set of guidelines known as the Web Content Accessibility Guidelines (WCAG).
Currently at revision 2, these guidelines relate to:
- Non-Text Content
- All non-text content should have a text alternative that serves the equivalent purpose, excluding some situations.
- Audio/Video-Only Content
- Audio/Video content should have captions unless said content is an alternative to text content.
- Adaptable Content
- Content must be presented in different ways without losing information or structure
- Relationships between information must be conveyed through presentation
- Content operation should not rely solely on sensory characteristics of the components such as shape, size, visual location, orientation or sound.
- Distinguishability
- Users need to have an easy time distinguish content from visuals
- Use of Color must not only be used for visual affect but functionality too
- Audio longer than 3 seconds needs a stop button
- Text needs to be easy to read and resizeable
- Contrast needs to play a large part in distinguishing content
- Operation
- Keyboard accessibility
- Timing components on the page
- Proper usage of HTML elements to encourage navigation
- Predictability
- Consistency
- Input Assistance
- Error identification and suggestions
- Labelling of inputs and forms
- Robustness
- Browser compatibility
With the creation of HTML5, form elements now provide a whole new level of validation out of the box without the need for additional JavaScript. This includes a whole new slew of input elements including:
Number
- Allows for number only input
Date
- Allows for an easy to use date picker
Email
- Ensures the input is an email address
Tel
- Ensures the input is in a telephone number format
This can be expanded upon even further, with the usage of the pattern
attribute on input
elements.
Using patterns, web browsers can assert an input against a Regular Expression without requiring any extra JS validation.
Say we wanted an input that only took in alphabetical characters between 1 and 15 characters long:
<input
id="userinput"
type="text"
title="Usernames can only contain numbers and be between 1 and 15 characters" pattern="[a-z]{1,15}"/>
Attempting to put invalid data into this field would prompt the user like so:
As you've hopefully realized, this is all part of defining our View in our Model-View-Controller pattern. The View represents what we see, what the user interacts with.
The View itself in most MVC frameworks is comprised of data from the Model and the Controller. In Angular, the view is marked up in HTML. This means that if you have the knowledge to write up static web pages; you have the knowledge to write up dynamic Angular views.
As the View is what user is, well, using; it needs to look good.
Whilst vanilla CSS will help make your page look decent, time can be saved by using a framework instead.
Twitter's Bootstrap is a UI framework for "Mobile First" website development. The idea behind Bootstrap is that you target the mobile device size and then scale up to desktop and tablet screen sizes using their "responsive" layouts.
Bootstrap's most notable feature is that of the grid system. Using Bootstrap, web developers can divide a page into rows and columns; defining specific rulesets for 4 different screen sizes.
These screen sizes are split into small (sm
), medium (md
), large (lg
) and extra large (xl
) and using the CSS rule style of .col-xx-ww
we are able to set the width of our columns for the specific screen sizes.
Bootstrap's column widths need to add up to 12, no matter the screen size. This can be done in anyway, but the golden rule is that your column's add up to twelve.
For example, if you wanted a 3 column site for medium sized screens your Bootstrap would look like:
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4"></div>
<div class="col-md-4"></div>
</div>
Multiple rules can be applied to a single element; so if we wanted the grid to be split into quarters with the first 2 divs being larger than the last on an XL screen it may look like this:
<div class="row">
<div class="col-md-3 col-xl-5"></div>
<div class="col-md-3 col-xl-5"></div>
<div class="col-md-3 col-xl-2"></div>
</div>
The proportional nature of the Grid is the very reason for it being so powerful.
Bootstrap also includes a range of components and styles to make your webpage look better from an aesthetic point of view.
Content elements such as headings, paragraphs and general text elements have a consistent font rendering system and on top of that will default to system fonts where available.
Forms, tables and a lot of structural elements have been redesigned with more modern looking styling.
AngularJS is the provider of the Controller and the Model for our MVC application.
In terms of MVC, AngularJS provides us an application wide scope for defining an our Model.
The Model is the data-related logic of the application, literally modelling the objects and
entities that we will be using. Using a module, we initialize our application which is referenced to using ng-app
in our HTML file.
var app = angular.module("myApp", []);
This is an example of a module declaration, using the app
variable we can create controllers,
filters, directives and all the other parts of our Angular application.
Any form of AngularJS interactivity is facilitated by a controller, as the name implies the controller handles the controller aspects of the MVC design pattern.
The actual interactions between the View and the Model are handled in the Controller. In AngularJS the controller is special as it can be used to define the Model of the application as well as work with it. This is not the case with most MVC frameworks, but Angular is an exception.
Using the $scope
variable, Angular provides an easy way to define controller wide variables and objects that could be used as the model. The following variable:
$scope.name = "Alex";
Could be displayed in an associated HTML file like so:
<p>{{name}}</p>
The structure of a controller is very simple, like a module you need to name the controller and using the parameters you can make use of features such as scope, routing and more:
app.controller("controllerName", function ($scope) {
// implement JS code
});
As I mentioned, the Model itself is defined using Angular's $scope
variable.
Defining a model is often done using a JavaScript object, as this means it can be passed between functions easily. Modelling a person with a first name, last name and age would like:
{
"firstName": "Alex",
"lastName": "Billson",
"age": 19
}
If you wanted to assign this model to the angular scope, it's just as if you're assigning to a variable:
$scope.personObj = {
"firstName": "Alex",
"lastName": "Billson",
"age": 19
};
The model can be reflected quite easily in your view, using Angular's
handlebar syntax ({{}}
), say we wanted to bind the values of the model to paragaph elements, it would look like so:
<div>
<p>{{personObj.firstName}}</p>
<p>{{personObj.lastName}}</p>
<p>{{personObj.age}}</p>
</div>
The final HTML output the same as:
<div>
<p>Alex</p>
<p>Billson</p>
<p>19</p>
</div>
Angular uses directives in its Views to provide dynamic behaviour for our HTML.
Directives such as a ng-if
, ng-show
and ng-hide
allow us to modify the DOM structure
depending fon conditions and expressions. For example, the following paragraph would never show:
<p data-ng-show="3 > 5">Goodbye</p>
but the following would show
<p data-ng-show="100 > 5">Hello</p>
Using directives such as ng-repeat
allow for collections to be translated into multiple elements.
This is especially helpful for working with ordered and unordered lists:
$scope.food = ["Apple", "Orange", "Banana"];
<ul data-ng-repeat="f in food">
<li>{{f}}</li>
</ul>
The following producing this HTML:
<ul data-ng-repeat="f in food">
<li>Apple</li>
<li>Orange</li>
<li>Banana</li>
</ul>
Keep in mind there are many Angular directives built into the framework, custom directives being created with the app.Directive
syntax:
app.directive('ngDirective', function($parse) {
...
AngularJS is known for being a provider of the tools to create great Single Page Applications (SPAs).
Using the additional angular.route
file, you can define the URLs of your website
as well as provide the means for passing in route paramaters to your controllers.
app.config(['$routeProvider', function ($routeProvider, $locationProvider) {
$locationProvider.hashPrefix('');
$routeProvider.when('/post/:postID',
{
templateUrl: '/templates/post.html',
controller: 'postCtrl'
});
$routeProvider.when('/group/:groupID',
{
templateUrl: '/templates/group.html',
controller: 'groupCtrl'
});
}]);
The contents of the template URL are placed in an ng-view
within your index.html.
This means that your index.html essentially becomes a container for the entirety of
your site; the main content injected into the ng-view
with the related controller.