Wszystkie wpisy, których autorem jest admin

Working Towards Better Naming

Post pobrano z: Working Towards Better Naming

There is a quote that I bet every one of you has heard many times. You know the one. The one that reminds you how hard naming is.

Let’s talk names.

We talk often about how hard naming is, but it’s less common see people talk about how to get better at it. Even naming philosophies lend structure to naming, but don’t pick names for you. Names are more than just some hard thing we get needlessly caught up in. They’re essential to good code. Good names can make a code base easy to pick up and work with. Bad names are hard to understand, or worse yet, prone to error.

Naming Examples

Let’s look at some examples in JavaScript.

function processData(data) {
  var result = JSON.parse(data);
  return result;
}

Reading only the function name, parameter name, and returned variable, we see that processData gets data and returns a result. These names have added nearly zero information to the reader. Code like this is easy to write when you just want to get it working or you’re trying to stay flexible to changes, and that’s okay. It’s always a good idea to go over your code with fresh eyes to fix things, and names should be on your quality checklist.

Here’s a more descriptive way we could have written the last example:

function parseJson(string) {
  var jsonObject = JSON.parse(string);
  return jsonObject;
}

Technology is one of the most abbreviation and acronym heavy fields there are, and they are key to great names. FTP is easier to read and understand than „File Transfer Protocol.” In some cases though, the reader can be left out.

Here’s an example where the abbreviations are convenient for the developer writing the code, but not so handy for anyone else who needs to read or contribute to it:

function cts(con, ack) {
  if (con && ack) {
    return true;
  }
  else {
    return false;
  }
}

Often I’ll read code with an acronym and have to switch to my web browser to do a search, only to find results for car models. A perfect example of that is cts, which returns a lot of Cadillac results. ack does show up on a search, but I’d rather not leave it my text editor. con can be misunderstood many ways. Is it a connection? A count? A container? Maybe it’s a scam. These things may be obvious if you are familiar with the code base, but it adds a learning curve to those joining the project. A few extra seconds can save several minutes for readers over years.

Here’s the previous example written without abbreviations:

function clearToSend(connectionExists, acknowledgementStatus) {
  if (connectionExists && acknowledgementStatus) {
    return true;
  }
  else {
    return false;
  }
}

Let’s turn to some HTML examples because HTML is perhaps the most name heavy language of them all.

<section class="new-promotion-parent">
  <img class="logo" src="small-square-logo-monochrome.png"/>
  <div class="get-your-coupon">
    <p>Get Your Coupon</p>
  </div>
</section>

We can imagine that the word „new” was used here likely because a designer was told to update the promotion-parent element, but to also keep support for the existing class, maybe for old HTML floating about. The term „new” is an accurate description for the first few months, but over time it becomes more and more ironic. A better idea might be to add a separate class that describes what is new. For example, if a new flat design is being implemented, then a class name of flat-design might work. For an added bonus, you can let the CSS from the existing promotion-parent class cascade if you’d like to reuse some of the styles.

Similarly, logo seems like a sensible class name at first. Inevitably, however, a second logo will come along somewhere, which gets the name alt-logo. The logos keep coming, and so do the increasingly bad names. Most assets have several variations, such as different shapes, sizes, color schemes and more. That said, small-square-logo-monochrome wouldn’t be a great class name either, because the image itself should be able to be swapped without the class name becoming obsolete. A better idea might be a name that describes the role of the asset rather than the type or appearance.

Here, the language of the div has been used to name the div get-your-coupon. The content of an HTML document is meant to continually evolve; names are not. A coupon code today might be an email signup in the future, while keeping the same styles and functionality. HTML is one place where names are often too specific instead of too vague.

Here’s that same HTML code taking the suggestions into consideration:

<section class="flat-design promotion-parent">
  <img class="promotion-branding-image" src="small-square-logo-monochrome.png"/>
  <div class="primary-promotion-text">
    <p>Get Your Coupon</p>
  </div>
</section>

We can even look at the names in a database for better naming. Tables often get used countless times across an application in several very different contexts.

Here’s a simplified database table:

CREATE TABLE `book` (
  `id` int(12) NOT NULL,
  `title` varchar(50) NOT NULL,
  `author` varchar(50) NOT NULL,
  `type` bit(1) NOT NULL,
  `sort` int(12) NOT NULL,
  `order` varchar(25) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

What does type mean in the context of books? Does it mean fiction or non-fiction? Does it mean paperback or hardcover? Maybe it means physical or digital?

The sort column is equally confusing. Is it representing ASC or DESC? Does it represent which column is being used to sort? Maybe it decides if sorting is active? Or maybe it decides show the books in some other alternate order?

And then there’s order. Aside from being equally ambiguous, order is a reserved word in MySQL and many other languages. You can work around this using backticks (`) for MySQL, but it’s probably a better idea to avoid using reserved words altogether.

Here’s how the table could be written in a more descriptive way:

CREATE TABLE `book` (
  `id` int(12) NOT NULL,
  `title` varchar(50) NOT NULL,
  `author` varchar(50) NOT NULL,
  `cover_type` bit(1) NOT NULL,
  `sort_order` int(12) NOT NULL,
  `purchase_order_number` varchar(25) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Naming Conventions

Let’s talk naming conventions.

if (oldmanshaven) {
  return true;
}

Did you read that as Old Mans Haven or Old Man Shaven? Either way, it forces you to slow down and think which adds up and might one day lead to a misunderstanding. PascalCase, camelCase, snake_case, kebab-case are all excellent choices. Use them, and just as important, be consistent.

Here’s that same code in snake_case, which is less likely to be misread:

if (old_man_shaven) {
  return true;
}

One more example:

if (!isNaN(number)) {
  alert('not a number')
}
else if (!number > 50) {
  alert('number too large')
}
else if (!number < 10) {
  alert('number too small')
}
else {
  // code here
}

I looked at some of my first lines of code for inspiration writing this post. I didn’t see many bad names because I wrote code in a way that didn’t use names. I used very few functions, rarely used assignments, and would abuse variables by making them do a dozen different things. Having plenty of names in your code is often a sign that you’re abstracting things properly.

Here’s one example from my code:

function validateNumber(number) {
  var maximumValue = 50;
  var minimumValue = 10;
  if (isNaN(number)) {
    alert('not a number')
    return false;
  }
  if (number > maximumValue) {
    alert('number too large')
    return false;
  }
  if (number < minimumValue) {
    alert('number too small')
    return false;
  }
}

if (validateNumber(number)) {
  // code here
}

Caveats

Naming things is an art, not a science. There’s some things outside the name to consider when evaluating if a name is good or bad.

Context

Context can give generic terms much more meaning. For example, „item” is a vague name but, in the context of a getCustomerSalesOrder() function, we can tell it likely refers to a product that was purchased. A function that is short, focused, and takes context into account can reduce the need for verbose names. I still prefer a good name. Context can disappear easily over time as functions get longer or re-factored. Names are more permanent markers of meaning.

Comments

Code comments are important to readable code, but they can’t do it all by themselves. Comments should pick up where names leave off, giving details you can’t cram into a name, noting the reason for a particular way of doing things, or ranting about a broken library.

/* This refers to a product that was purchased and relates to the customer-sales-order class. */
.product-item {
  display: block;
  text-transform: uppercase;
  width: 100vw;
}

Reading Length

Longer names create more to read and wider lines. It can especially be problematic when accessing deep into an array, such as:

$order_details['customer']['ship_to_address']['default']['street_address']['line_1']

That said, even that straw man example I just gave, while verbose, is crystal clear and gives me no reason to stop reading to think or look over the rest of the function to understand the context.

Names are everywhere in Code

Most of the characters of a code file probably aren’t brackets or syntax, but names. It might be variable names, function names, HTML tags or attributes, database tables or columns, or any of the countless things that we give names to in any given project.

I still struggle with naming things. I often find myself sitting frozen at my text editor, trying to name some minor variable. I’ve learned that when that happens, it’s likely because I’m dealing with something difficult to conceptualize, which makes it all the more important to find the right name for it.


Working Towards Better Naming is a post from CSS-Tricks

Designing for Smartphones? Here’s What you Need to Know

Post pobrano z: Designing for Smartphones? Here’s What you Need to Know

If you are making anything that will be consumed by end users in some way, then you have to be designing for smartphones. Everyone has a smartphone. The government gives out smartphones to welfare recipients. So even people who can’t afford to buy and maintain a data plan for smartphones have a smartphone. Practically everyone you want to read with your product or service will be doing so on a smartphone.

That means that designing for smartphones has to be the priority for whatever you are making. That includes hardware. If you want to build a great sounding speaker for music playback, you have to recognize that most of that music will be coming from a smartphone or streaming service triggered by a smartphone. No one wants to physically tether their phone to a speaker. So you have to consider various wireless standards that are smartphone friendly.

If you are making clothes, you have to consider the smartphone. Do you have a pocket that can comfortably hold the large smartphones that are popular today? Do you have a place that makes routing the wire convenient? Is there a pocket that can hold a charger?

So if you are designing anything, you are designing for smartphones. Here is what you need to know that will pay dividends for the final product:

Design to Minimize Smartphone Weaknesses

As great as smartphones are, they have some built-in weaknesses that are going to present problems to the user. You can be a hero to the end user by designing around those weaknesses and making them less pronounced. One example is the camera bump so prevalent on modern smartphones. While smartphones are getting thinner, cameras are not. They still need physical space to be any good.

The best iPhone X cases are a testimony to this principle. iPhones are among the most egregious examples of camera bumps. But a good case completely eliminates the bump.

That is not the only thing a good case does. Phones are getting more fragile as they are being made with glass on both the front and the back. A good case offers more protection from scratches and impact. Design with smartphone weaknesses in mind. And you will make the world a better place for smartphone users.

Design for Unique Smartphone Distinctives

Although it might look like it from a distance, not all smartphones are the same. The iPhone X is an example of a smartphone with a design distinctive that makes it materially different from other smartphones. The Essential Phone is the same way. They both have notches at the top of the phone instead of traditional bezels.

Immediately following the launch of the iPhone X, the most popular apps were those that were redesigned to fit the new, curved contours of the screen, and used the notch for all it was worth. If some manufacturer completely loses their mind and designs a rounded smartphone, you need to be prepared to design round apps so that you find yourself at the top of the sales charts for the people with that device.

Even people without that device will note that you are a developer that stays on top of the latest trends. They are more likely to trust you over other developers that never update their apps to reflect the newest smartphones.

Design for Humans

Even the biggest smartphone screens are tiny compared to laptops and desktops. So you have to be sure your apps and websites have fonts that are readable on small screens. You also have to account for information density. Humans need a certain amount of information at one time without being overwhelmed. You can’t cram the same amount of information on a smartphone screen as you can on a desktop or laptop screen. You have to design for humans using small screens.

If you are making a case, you have to design for the human hand. The case needs to be right-sized and somewhat grippy, as humans tend to drop phones. If you are making a charging dock, it has to be easy for humans to install the phone and not have to waste time fumbling around.

When designing for smartphones, you have to design for weaknesses of the product. Design for unique distinctions. And design for the people who will be using them.

How to Design Your Own Website?

Post pobrano z: How to Design Your Own Website?

You want to create your own website? Good for you! This article will give you a complete guideline on how you should go about the process, step by step using the latest information. Even if you a beginner, worry not because the information will not be technical, but as easy as A, B, C!

The Steps of Designing a Website

Have a Domain Name

A domain name is the name you will choose to name your website. For example, ‘thepagewizard.com’ . You must pay a fee every year to a registrar to acquire the rights of your name.

Select a Web Host and Sign Up for an Account

A web host is an organization that has several computers that are connected to the internet. After you select a web host, your web page is placed on any of the company’s computers and this allows everybody to view your website worldwide. Signing up an account with a web host, allows your website to have a home. You have to consider several factors when choosing a web host such as cost, experience and if the host is licensed. Immediately after signing up for a web host, you should then place your domain name on the account of your web host.

Design the Website Pages

You could choose to design your website on your own or hire a web design company in Las Vegas like Platinum Web Marketing, but if you are designing the website page on your own, the following is the procedure you should follow.

  1. Find something out on the web.
  2. You can use a ‘what you see is what you get’ web editor, because the editor enables you to design your site without dealing with the technical part.
  3. These editors are similar to a word processor.
  4. There are also commercial editors, for example, Microsoft Expression WEB.
  5. This editor is best if you are using windows.
  6. It is recommended you design your website to be a mobile friendly site, meaning it can work on desktops, laptops and also mobile phones.

Test The Website

After designing the site, test it on some of the huge browsers such as Chrome, Firefox, Internet Explorer. You can get these browsers for free. You can also try the website using your phone.However, testing it directly is the best way since it is the only way you can make sure that the site is working the exact way you want it to, on someone else’s device.

Get The Credit Card Information

In case you are selling products or services, you have to acquire the credit card information. There are several advertisers and integrated programs that can be found in online affiliate programs and sponsors. The companies search for new publishers to showcase their advertisements.

Have Your Site Noticed

After you are done with the above procedures, submit your site to the search engines such as Google, Yahoo and Bling. You can also use other ways to promote your site. For example, you can advise your website on newspapers, use press releases using the help of internet companies such as PRWeb. Your website can then be noticed by blogs and news sites.

In cessation, if you follow the procedure above, you will be able to create your own website easily. After creating the website, do not stop there, you should keep on improving it every now and then.

Dacia: DACIA Unnecessories

Post pobrano z: Dacia: DACIA Unnecessories

Film
Dacia

DACIA cars are the smart choice. They have everything a person really needs – such as the Media Nav multimedia system, the rear-view camera, generous interior spaces, robustness, and much more, at a fair price.

But how do we convince people to buy a DACIA, when other brands are constantly luring them with extras that they will never use?

Creating a new line of accessories specially made to satisfy the desire of those who really insist on having unnecessary equipment in the car &ndash; The DACIA Unnecessories.

Advertising Agency:Publicis, Lisbon, Portugal
Executive Creative Directors:Steve Colmar, Nuno Salvaterra
Creative Supervisor:José Picka
Art Directors:David Pires, Marta Carvalho
Copywriter:Freddie Brando
Design Director:António Silva
Designers:Joana Carvalho, Rui Lousão
Motion Designer:António Segurado
General Manager:Tiago Strecht
Account Executive:João Ruas, Duarte Rato
Brand Supervisor:Jorge Pais
Head of Audiovisual Production:Cristina Almeida
Video Editor:Inês Correia
Head Of Graphic Production:António Junior
Art Finisher:Rui Caracol
Head Of Digital Production:Edgar Meira
Digital Producer:Diogo Malheiro
Producer Company:Molotov Filmes

Kintsugi: Pieces in Harmony

Post pobrano z: Kintsugi: Pieces in Harmony
Outdoor, Print
Kintsugi

PROBLEM: When someone breaks a piece of pottery they love, they will try to repair it rather than throw it away. Kintsugi is the traditional Japanese craft of restoring broken pottery with metal. Rather than repairing the damages with an adhesive, it embellishes the crack with metal, treasuring the history of that damaged pottery. But the wonderful philosophy of Kintsugi has not passed onto modern-day people who prefer to buy a replacement when something breaks.

IDEA: Used for a theme appealing to modern-day people, new life has been breathed into this traditional Japanese craft. Representing historically-feuding neighboring countries,two dishes have been combined with Kintsugi with the cracks resembling the national border. We cannot forget cultural differences or things that happened in the past, but we appealed for mutual understanding through Kintsugi by producing a new harmonious shape in a single dish.

EXECUTION: Their special dishes are promoted via exhibitions and posters as well as images, so they got the opportunity to come into contact with mote people than usual exhibitions. By seeing the real thing with their own eyes (beautifully harmonious dish divided by a crack embellished with metal),one can understand Kintsugi&rsquo;s philosophy of treasuring history.

Advertising Agency:I&S Bbdo, Tokyo, Japan
Creative Director:Shinichi Ikeda
Idea:Risa Taoka
Art Director:Risa Taoka
Photographer:Akira Sakamoto, Doable
Photo Retouch:Keigo Masaki, Rizing
Cameraman:Rakuda
Director:Kazuhiro Yamamoto, Sponge
Producers:Kazuhide Kumada, Tomoaki Watanabe, TCJ, Chisako Yoshizaki, Amana
Managers:Tatuya Ikeda, Masatoshi Tunoda, TCJ
Music:Kaito Sakuma, Apples & Oranges
Coordinator:Hanako Nagai, Incite Japan Tutoring

Rokujigen: Kintsugi Pieces in Harmony

Post pobrano z: Rokujigen: Kintsugi Pieces in Harmony

Print
Rokujigen

PROBLEM: When someone breaks a piece of pottery they love, they will try to repair it rather than throw it away. Kintsugi is the traditional Japanese craft of restoring broken pottery with metal. Rather than repairing the damages with an adhesive, it embellishes the crack with metal, treasuring the history of that damaged pottery. But the wonderful philosophy of Kintsugi has not passed onto modern-day people who prefer to buy a replacement when something breaks.

IDEA: Used for a theme appealing to modern-day people, new life has been breathed into this traditional Japanese craft. Representing historically-feuding neighboring countries,two dishes have been combined with Kintsugi with the cracks resembling the national border. We cannot forget cultural differences or things that happened in the past, but we appealed for mutual understanding through Kintsugi by producing a new harmonious shape in a single dish.

EXECUTION: Their special dishes are promoted via exhibitions and posters as well as images, so they got the opportunity to come into contact with mote people than usual exhibitions. By seeing the real thing with their own eyes (beautifully harmonious dish divided by a crack embellished with metal),one can understand Kintsugi&rsquo;s philosophy of treasuring history.

Advertising Agency:I&S Bbdo, Tokyo, Japan
Creative Director:Shinichi Ikeda
Idea:Risa Taoka
Art Director:Risa Taoka
Photographer:Akira Sakamoto, Doable
Photo Retouch:Keigo Masaki, Rizing
Cameraman:Rakuda
Director:Kazuhiro Yamamoto, Sponge
Producers:Kazuhide Kumada, Tomoaki Watanabe, TCJ, Chisako Yoshizaki, Amana
Managers:Tatuya Ikeda, Masatoshi Tunoda, TCJ
Music:Kaito Sakuma, Apples & Oranges
Coordinator:Hanako Nagai, Incite Japan Tutoring

Everything you need to know about CSS Variables

Post pobrano z: Everything you need to know about CSS Variables

This is by far the biggest deep dive I’ve seen on CSS Variables posted to the web and it’s merely Chapter One of complete e-book on the topic.

Truth is, I’m still on the thick of reading through this myself, but had to stop somewhere in the middle to write this up and share it because it’s just that gosh-darned useful. For example, the post goes into great detail on three specific use cases for CSS Variables and breaks the code down to give a better understanding of what it does, in true tutorial fashion.

Scoping, inheritance, resolving multiple declarations, little gotchas—there’s plenty in here for beginners and advanced developers alike.

OK, back to reading. 🤓

Direct Link to Article — Permalink


Everything you need to know about CSS Variables is a post from CSS-Tricks

Let’s Build a Custom Vue Router

Post pobrano z: Let’s Build a Custom Vue Router

Plenty of tutorials exist that do a great job in explaining how Vue’s official routing library, vue-router, can be integrated into an existing Vue application. vue-router does a fantastic job by providing us with the items needed to map an application’s components to different browser URL routes.

But, simple applications often don’t need a fully fledged routing library like vue-router. In this article, we’ll build a simple custom client-side router with Vue. By doing so, we’ll gather an understanding of what needs to be handled to construct client-side routing as well as where potential shortcomings can exist.

Though this article assumes basic knowledge in Vue.js; we’ll be explaining things thoroughly as we start to write code!

Routing

First and foremost: let’s define routing for those who may be new to the concept.

In web development, routing often refers to splitting an application’s UI based on rules derived from the browser URL. Imagine clicking a link and having the URL go from https://website.com to https://website.com/article/. That’s routing.

Routing is often categorized in two main buckets:

  • Server-side routing: the client (i.e. the browser) makes a request to the server on every URL change.
  • Client-side routing: the client only makes a request to the server upon initial-page load. Any changes to the application UI based on URL routes are then handled on the client.

Client-side routing is where the term single-page application (or SPA for short) comes in. SPAs are web apps that load only once and are dynamically updated with user interaction without the need to make subsequent requests to the server. With routing in SPAs, JavaScript is the driving force that dynamically renders different UI.

Now that we have a brief understanding of client-side routing and SPAs, let’s get an overview of what we’ll be working on!

Case Study: Pokémon

The app we aim to construct is a simple Pokémon app that displays details of a particular Pokémon based on the URL route.

The application will have three unique URL routes: /charizard, /blastoise, and /venusaur. Based on the URL route entered, a different Pokémon will be shown:

In addition, footer links exist at the bottom of the application to direct the user to each respective route upon click:

Do We Even Need Routing for This?

For simple applications like this, we don’t necessarily need a client-side router to make our app functional. This particular app could be composed of a simple parent-child component hierarchy that uses Vue props to dictate the information that should be displayed. Here’s a Pen that shows just this:

See the Pen Vue Pokemon by Hassan Dj (@itslit) on CodePen.

Though the app would functionally work, it misses a substantial feature that’s expected from most web applications—responding to browser navigation events. We’d want our Pokémon app to be accessible and to show different details for different pathnames: /charizard, /blastoise, and /venusaur. This would allow users to refresh different pages and keep their location in the app, bookmark the URLs to come back to later, and potentially share the URL with others. These are some of the main benefits of creating routes within an application.

Now that we have an idea of what we’ll be working on, let’s start building!

Preparing the App

The easiest way to follow along step-by-step (if you wish to do so) is to clone the GitHub repo I’ve set up.

Download on GitHub

When cloned, install the project dependencies with:

npm install

Let’s take a brief look within the project directory.

$ ls
README.md
index.html
node_modules/
package.json
public/
src/
static/
webpack.config.js

There also exists the hidden files, .babelrc and .gitignore within the project scaffold.

This project is a simple webpack-configured application scaffolded with vue-cli, the Vue command line interface.

index.html is where we declare the DOM element—#app— with which we’ll use to mount our Vue application:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.5.3/css/bulma.css">
    <link rel="stylesheet"
      href="../public/styles.css" />
    <title>Pokémon - Routing</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="/dist/build.js"></script>
  </body>
</html>

In the <head> tag of the index.html file, we introduce Bulma as our application’s CSS framework and our own styles.css file that lives in the public/ folder.

Since our focus is on the usage of Vue.js, the application already has all the custom CSS laid out.

The src/ folder is where we’ll be working directly from:

$ ls src/
app/
main.js

src/main.js represents the starting point of our Vue application. It’s where our Vue instance is instantiated, where we declare the parent component that is to be rendered, and the DOM element #app with which our app is to be mounted to:

import Vue from 'vue';
import App from './app/app';

new Vue({
  el: '#app',
  render: h => h(App)
});

We’re specifying the App component, from the src/app/app.js file, to be the main parent component of our application.

In the src/app directory, there exists two other files – app-custom.js and app-vue-router.js:

$ ls src/app/
app-custom.js
app-vue-router.js
app.js

app-custom.js denotes the completed implementation of the application with a custom Vue router (i.e. what we’ll be building in this article). app-vue-router.js is a completed routing implementation using the vue-router library.

For the entire article, we’ll only be introducing code to the src/app/app.js file. With that said, let’s take a look at the starting code within src/app/app.js:

const CharizardCard = {
  name: 'charizard-card',
  template: `
    <div class="card card--charizard has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/charizard.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Charizard</div>
          <div class="hp">hp 78</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">🔥<br>
            <span class="tag is-warning">Type</span>
          </div>
          <div class="column center-column">199 lbs<br>
            <span class="tag is-warning">Weight</span>
          </div>
          <div class="column">1.7 m <br>
            <span class="tag is-warning">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <pokemon-card></pokemon-card>
      </div>
    </div>
  `,
  components: {
    'pokemon-card': CharizardCard
  }
};

export default App;

Currently, two components exist: CharizardCard and App. The CharizardCard component is a simple template that displays details of the Charizard Pokémon. The App component declares the CharizardCard component in its components property and renders it as <pokemon-card></pokemon-card> within its template.

We currently only have static content with which we’ll be able to see if we run our application:

npm run dev

And launch localhost:8080:

To get things started, let’s introduce two new components: BlastoiseCard and VenusaurCard that contains details of the Blastoise and Venusaur Pokémon respectively. We can lay out these components right after CharizardCard:

const CharizardCard = { 
  // ... 
};

const BlastoiseCard = {
  name: 'blastoise-card',
  template: `
    <div class="card card--blastoise has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/blastoise.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Blastoise</div>
          <div class="hp">hp 79</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">💧<br>
            <span class="tag is-light">Type</span>
          </div>
          <div class="column center-column">223 lbs<br>
            <span class="tag is-light">Weight</span>
          </div>
          <div class="column">1.6 m<br>
            <span class="tag is-light">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const VenusaurCard = {
  name: 'venusaur-card',
  template: `
    <div class="card card--venusaur has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/venusaur.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Venusaur</div>
          <div class="hp hp-venusaur">hp 80</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">🍃<br>
            <span class="tag is-danger">Type</span>
          </div>
          <div class="column center-column">220 lbs<br>
            <span class="tag is-danger">Weight</span>
          </div>
          <div class="column">2.0 m<br>
            <span class="tag is-danger">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const App = { 
  // ... 
};

export default App;

With our application components established, we can now begin to think how we’ll create routing between these components.

router-view

To establish routing, we’ll start by buiding a new component that holds the responsibility to render a specified component based on the app’s location. We’ll create this component in a constant variable named View.

Before we create this component, let’s see how we might use it. In the template of the App component, we’ll remove the declaration of <pokemon-card> and instead render the upcoming router-view component. In the components property; we’ll register the View component constant as <router-view> to be declared in the template.

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <router-view></router-view>
      </div>
    </div> 
  `,
  components: {
    'router-view': View
  }
};

export default App;

The router-view component will match the correct Pokémon component based on the URL route. This matching will be dictated in a routes array that we’ll create. We’ll create this array right above the App component:

const CharizardCard = { 
  // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [
  {path: '/', component: CharizardCard},
  {path: '/charizard', component: CharizardCard},
  {path: '/blastoise', component: BlastoiseCard},
  {path: '/venusaur', component: VenusaurCard}
];

const App = { 
  // ... 
};

export default App;

We’ve set each Pokémon path to their own respective component (e.g. /blastoise will render the BlastoiseCard component). We’ve also set the root path / to the CharizardCard component.

Let’s now begin to create our router-view component.

The router-view component will essentially be a mounting point to dynamically switch between components. One way we can do this in Vue is by using the reserved <component> element to establish Dynamic Components.

Let’s create a starting point for router-view to get an understanding of how this works. As mentioned earlier; we’ll create router-view within a constant variable named View. So with that said, let’s set up View right after our routes declaration:

const CharizardCard = { 
  // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [
  // ...
];

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: CharizardCard  
    }
  }
}; 

const App = {
// ... 
};

export default App;

The reserved <component> element will render whatever component the is attribute is bound to. Above, we’ve attached the is attribute to a currentView data property that simply maps to the CharizardCard component. As of now, our application resembles the starting point by displaying CharizardCard regardless of what the URL route is.

Though router-view is now appropriately rendered within App, it’s not currently dynamic. We need router-view to display the correct component based on the URL pathname upon page load. To do this, we’ll use the created() hook to filter the routes array and return the component that has a path that matches the URL path. This would make View look something like this:

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: {}  
    }
  },
  created() {
    this.currentView = routes.find(
      route => route.path === window.location.pathname
    ).component;
  }
};

In the data function, we’re now instantiating currentView with an empty object. In the created() hook, we’re using JavaScript’s native find() method to return the first object from routes that matches route.path === window.location.pathname. We can then get the component with object.component (where object is the returned object from find()).

Inside a browser environment, window.location is a special object containing the properties of the browser’s current location. We grab the pathname from this object which is the path of the URL.

At this stage; we’ll be able to see the different Pokémon Card components based on the state of our browser URL!

The BlastoiseCard component now renders at the /blastoise route.

There’s something else we should consider. If a random URL pathname is entered, our app will currently error and present nothing to the view.

To avoid this, let’s introduce a simple check to display a „Not Found” template if the URL pathnamedoesn’t match any path existing in the routes array. We’ll separate out the find() method to a component method named getRouteObject() to avoid repetition. This updates the View object to:

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: {}  
    }
  },
  created() {  
    if (this.getRouteObject() === undefined) {
      this.currentView = {
        template: `
          <h3 class="subtitle has-text-white">
            Not Found :(. Pick a Pokémon from the list below!
          </h3>
        `
      };
    } else {
      this.currentView = this.getRouteObject().component;
    } 
  },
  methods: {
    getRouteObject() {
      return routes.find(
        route => route.path === window.location.pathname
      );
    }
  }
};

If the getRouteObject() method returns undefined, we display a „Not Found” template. If getRouteObject()returns an object from routes, we bind currentView to the component of that object. Now if a random URL is entered, the user will be notified:

The „Not Found” view is rendered if the URL pathname does not match any of the values in the routes array.

The „Not Found” template tells the user to pick a Pokémon from a list. This list will be the links we’ll create to allow the user to navigate to different URL routes.

Awesome! Our app is now responding to some external state, the location of the browser. router-view determines which component should be displayed based on the app’s location. Now, we need to construct links that will change the location of the browser without making a web request. With the location updated, we want to re-render our Vue app and rely on router-view to appropriately determine which component to render.

We’ll label these links as router-link components.

router-link

In web interfaces, we use HTML <a> tags to create links. What we want here is a special type of <a> tag. When the user clicks on this tag, we’ll want the browser to skip its default routine of making a web request to fetch the next page. Instead, we just want to manually update the browser’s location.

Let’s compose a router-link component that produces an <a> tag with a special click binding. When the user clicks on the router-link component, we’ll use the browser’s history API to update the browser’s location.

Just like we did with router-view, let’s see how we’ll use this component before we build it.

In the template of the App component, let’s create three <router-link> elements within a parent <div class="pokemon-links"></div> element. Rather than using the href attribute in <router-link>, we’ll specify the desired location of the link using a to attribute. We’ll also register the upcoming router-link component (from a Link constant variable) in the App components property:

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <router-view></router-view>
  
        <div class="pokemon-links has-text-centered">
          <router-link to="/charizard"></router-link>
          <router-link to="/blastoise"></router-link>
          <router-link to="/venusaur"></router-link>
        </div>
      </div>
    </div>
  `,
  components: {
    'router-view': View,
    'router-link': Link
  }
};

We’ll create the Link object that represents router-link right above the App component. We’ve established the router-link component should always be given a to attribute (i.e. prop) that has a value of the target location. We can enforce this prop validation requirement like so:

const CharizardCard = { 
 // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [ 
  // ... 
];

const View = { 
  // ... 
};

const Link = {
  name: 'router-link',
  props: {
    to: {
      type: String,
      required: true
    }
  }
};

const App = { 
  // ... 
};

export default App;

We can create the template of router-link to consist of an <a> tag with an @click handler attribute. Upon trigger, the @click handler will call a component method, labeled navigate(), that navigates the browser to the desired location. This navigation will occur with the use of the history.pushState() method. With that said, the Link constant object will be updated to:

const Link = {
  name: 'router-link',
  props: {
    to: {
      type: String,
      required: true
    }
  },
  template: `<a @click="navigate" :href="to">{{ to }}</a>`,
  methods: {  
    navigate(evt) {  
      evt.preventDefault();  
      window.history.pushState(null, null, this.to);  
    }
  }
};

Within the <a> tag, we’ve bound the value of the to prop to the element text content with {{ to }}.

When navigate() is triggered, it first calls preventDefault() on the event object to prevent the browser from making a web request for the new location. The history.pushState() method is then called to direct the user to the desired route location. history.pushState() takes three arguments:

  • a state object to pass serialized state information
  • a title
  • the target URL

In our case, there is no state information that’s needed to be passed, so we’ve left the first argument as null. Some browsers (e.g. Firefox) currently ignore the second parameter, title, hence we’ve left that as null as well.

The target location, the to prop, is passed in to the third and last parameter. Since the to prop contains the target location in a relative state, it will be resolved relative to the current URL. In our case, /blastoise will resolve to http://localhost:8080/blastoise.

If we click any of the links now, we’ll notice our browser updates to the correct location without a full page reload. However, our app will not update and render the correct component.

This unexpected behaviour happens because when router-link is updating the location of the browser, our Vue app is not alerted of the change. We’ll need to trigger our app (or simply just the router-view component) to re-render whenever the location changes.

Though there’s a few ways to accomplish this behaviour, we’ll do this by using a custom EventBus. An EventBus is a Vue instance responsible in allowing isolated components to subscribe and publish custom events between each other.

At the beginning of the file, we’ll import the vue library and create an EventBus with a new Vue() instance:

import Vue from 'vue';

const EventBus = new Vue();

When a link has been clicked, we need to notify the necessary part of the application (i.e. router-view) that the user is navigating to a particular route. The first step is to create an event emitter using the EventBus’s events interface in the navigate() method of router-link. We’ll give this custom event a name of navigate:

const Link = {
  // ...,
  methods: {
    navigate(evt) {
      evt.preventDefault();
      window.history.pushState(null, null, this.to);
      EventBus.$emit('navigate'); 
    }
  }
};

We can now set the event listener/trigger in the created() hook of router-view. By setting the custom event listener outside of the if/else statement, the created() hook of View will be updated to:

const View = {
  // ...,
  created() {  
    if (this.getRouteObject() === undefined) {
      this.currentView = {
        template: `
          <h3 class="subtitle has-text-white">
            Not Found :(. Pick a Pokémon from the list below!
          </h3>
        `
      };
    } else {
      this.currentView = this.getRouteObject().component;
    }

    // Event listener for link navigation
    EventBus.$on('navigate', () => {
      this.currentView = this.getRouteObject().component;
    });
  },
  // ...
};

When the browser’s location changes by clicking a <router-link> element, this listening function will be invoked, re-rendering router-view to match against the latest URL!

Great! Our app now navigates appropriately as we click each of the links.

There’s one last thing we need to consider. If we try to use the browser back/forward buttons to navigate through the browser history, our application will not currently re-render correctly. Although unexpected, this occurs because no event notifier is emitted when the user clicks browser back or browser forward.

To make this work, we’ll use the onpopstate event handler.

The onpopstate event is fired each time the active history entry changes. A history change is invoked by clicking the browser back or browser forward buttons, or calling history.back() or history.forward() programmatically.

Right after our EventBus creation, let’s set up the onpopstate event listener to emit the navigate event when a history change is invoked:

window.addEventListener('popstate', () => {  
  EventBus.$emit('navigate');  
});

Our application will now respond appropriately even when the browser navigation buttons are used!

And there we have it! We’ve just built a custom Vue router using an EventBus and dynamic components. Even with the tiny size of our app we can enjoy a noticeable performance improvement. Avoiding a full page load also saves hundreds of milliseconds and prevents our app from „blinking” during the page change.

Conclusion

I love Vue. One reason as to why – it’s incredibly easy to use and manipulate Vue components just like we saw in this article.

In the introduction, we mentioned how Vue provides the vue-router library as the official routing library of the framework. We’ve just created simple versions of the same main items that are used in vue-router:

  • routes: the array responsible in mapping components to respective URL pathnames.
  • router-view: the component that renders a specified app component based on the app’s location
  • router-link: the component that allows the user to change the location of the browser without making a web request.

For very simple applications, the routing we’ve built (or a variation thereof like this one built by Chris Fritz) can do the minimal amount of work needed to route our applications.

The vue-router library, on the other hand, is built in a more complicated manner and introduces incredibly useful capabilities, often needed in larger applications like:

Though the vue-router library does come with additional boilerplate, it’s fairly easy to integrate once your application is composed of well isolated and distinct components. If you’re interested, you can see the components of vue-router being used to enable routing in this application here.

Hopefully this was as enjoyable to you as it was for me in compiling this post! Thanks for reading!


This article is an adapted (and summarized) segment from the upcoming book, Fullstack Vue, that I’m working on with the Fullstack.io team! Having the opportunity to work with the folks at Fullstack has been nothing short of being a blast. In true Fullstack fashion, the book covers numerous facets of Vue including but not restricted to routing, simple state management, form handling, Vuex, server persistence, and testing. If this is something that piques your interest or if you have any questions at all, follow (or message) me on twitter (@djirdehh)! If the above doesn’t pique your interest, you can still follow me anyway. 😛


Let’s Build a Custom Vue Router is a post from CSS-Tricks