How to transform a sidebar into an accordion!

Introduction:

I love front-end engineering, especially when the solution (which is not obvious) requires some sort of cross-disciplinary expertise.

I recently stumbled upon the following challenge: Turning a sidebar into an accordion on small screens and restore its original state on large screens. Sounds exciting? Watch the video below and read on.

 

 

First, let’s visualise the end result:

What is expected of us? What will the final result look like?

  • On a large viewport: the sidebar should be normally displayed with all its content
  • On a small viewport: the sidebar becomes an accordion which is initially closed (obviously to save some space); the user will have to manually expand it to consume the content
  • If the viewport’s width changes from small to large: the accordion should be deactivated and restored back to the sidebar’s initial state

 

Then, let’s consider the development environment and technologies used:

I believe any viable engineering solution should first consider the development environment, so let’s list the technologies used while specifying their importance:

  1. Twitter Bootstrap: for its excellent accordion plugin and famous grid system
  2. AngularJS directive: which will encapsulate all the logic and attach it as a behaviour to the sidebar
  3. Window matchMedia: for handling a specific breakpoint within the JavaScript code

The use of CSS in this case study is negligible (just a simple class to hide content).

 

Our methodology for solving the problem:

The methodology I’ve developed over years of experience is the following:

  1. Don’t force anything (unless there is no other way)
  2. Avoid reinventing the wheel (has this somehow been done before?)
  3. Craft your solution around powerful leverages (there must be something out there that can make your job easier and faster)

That being said, here is how we will …

Avoid reinventing the wheel:

  1. Turning our sidebar into an accordion: we’ll use Twitter Bootstrap’s collapse plugin (no need to engineer an accordion)
  2. Watching for a specific breakpoint on the JavaScript side: We’ll use matchMedia function (no need to constantly track the slightest change of the viewport’s width)

Craft our solution around powerful leverages:

We will encapsulate our logic inside an AngularJS directive that we’ll use as a decorator to attach the desired behaviour to our sidebar. Here are the basic steps of the solution (found as methods inside the directive)

  1. Handling the breakpoint change: We’ll track a specific breakpoint (using matchMedia). Each time that point is reached, we’ll turn the sidebar into an accordion or vice versa
  2. Deactivate or activate the accordion: The accordion will only operate on small screens, so we need to manually turn it off when necessary
  3. Expand the accordion: When returning the accordion back to a sidebar, we must make sure it isn’t collapsed, so we need a way to manually expand it
  4. Collapse the accordion: The accordion must be initially collapsed, so we need a manual way to do it

And we’re done! After putting everything together, things should work perfectly like in this special pen; the full code can be found in our CodePen profile.

 

In conclusion:

We’ve just seen how to solve the engineering problem of turning a sidebar into an accordion on small screens and vice versa. We based our approach on the following paradigms:

  • Clearly stating the problem
  • Identifying the solution’s great steps
  • Leveraging solid and powerful preexisting components

I hope this article had been insightful. Don’t hesitate to share your thoughts with me, I’ll be glad to answer. Thank you!

 

Resources:

 

Native JavaScript promises – part3 : Error Handling & Chaining

Error Handling:

Error handling can be done via the catch() method or as the second parameter of the then() method. Consider these equivalent chunks of code:

//Option 1  
getJSON('../data/file.json') //error happening here
.then(function(data){
  updateView(data);
  return get(data.thisUrl); //or error happening here
})
.catch(function(error){ //

 

In some cases, then() can be interpreted as a catch():

getJSON('../data/file.json')
//There is no resolve function here, only a rejection function
.then(undefined, rejectFunction)
//In the eventuality that the promise resolves, 
//the following then() that has a resolve function will be used
.then(resolveFunction);

 

In all cases, as soon as a promise rejects, the JavaScript engine skips to the next reject function in the chain:

//Option 1  
getJSON('../data/file.json') //error happening here
.then(function(data){
  updateView(data);
  return get(data.thisUrl); //or error happening here
})
.catch(function(error){ //

 

Important note on error handling:

It is strongly recommended to use catch() instead of then() when trying to handle errors for two reasons:

  1. Code readability: catch() are easy to spot in the code, using then() for both resolving and rejecting can be confusing
  2. Execution order: The resolve and rejection functions will never both be called if they are part of the same then() while they both can be called if the rejection function is part of a catch()

 

Performing asynchronous actions:  series vs parallel

Most asynchronous operations are not isolated, one request can lead to many others. In the case of multiple asynchronous actions, they all get performed in a chain (one promise generating another promise). The performance will then differ depending on wether actions are performed in series or in parallel.

/**
 * Chaining promises:
 * Two file requests must be performed because one resource leads to the other.
 * We assume: 
 * createThumbnail(data) receives an object, generates a thumbnail and place it on stage
 * get(url) : returns a promises (produced from fetch() of the fetch API)
 * getJSON(url) : performs an XHR for a JSON and returns a promise that passes the parsed JSON response
*/
//On page load: 
  getJSON('../data/file1.json')//Make the 1st request
  //If 1st request successful, return a promise of the 2nd request
  .then(function(resource){  
    return getJSON( resource.results[0]);
  })
  //Handling errors on the 1st request
  .catch(function(){
    throw Error('Search Request Error');
  })
  //If 2nd request is successful, create thumbnail
  .then(createThumbnail)
  //Handling errors on the 2nd request
  .catch(function(error){
    console.log('error = ', error); 
  });
//On page load: 

 

Actions in series:

Actions in series occur one after another, which means that the next resource is also fetched after the current one resolves.

/**
 * Situation where two file requests must be performed in order to 
 * get the information necessary to display a thumbnail on stage.
*/
getJSON('../data/file.json')//1st request
.then(function(response) {  
  //generate a promise object that will be reused to generate a sequential request
  let sequence  = Promise.resolve();
  //For each url in the array ...
  //chain a new promise that will be resolved only after the preceeding one 
  response.results.forEach(function(url){
    sequence.then(function(){
      return getJSON(url);
    })
    .then(createPlanetThumb)
    .catch(function(error){
      throw Error('Search Request Error = ', error);
    });
  }); 
});
//https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve

 

Actions in parallel:

Actions in parallel all occur simultaneously, which means that resources are fetched and probably resolve at the same time.

Actions in parallel using Array.prototype.map():

Promises can be resolved in parallel using the map() method of the Array object like in the following example (resolve order is not guaranteed):

/**
 * We use the map() on an array of url resources and generate 
 * a promise for each url resource of the array
 * (We assume errors are handled)
*/
getJSON('../data/file.json')//1st request
.then(function(resourse){  
  resourse.results.map(function(url){ 
    getJSON(url).then(createPlanetThumb);
  });
});

 

Actions in parallel using Promise.all():

Promises can also be resolved in parallel using Promise.all() method which will simultaneously resolve all promises provided in an iterative argument (or reject them all only one of them rejects).

/**
 * We use the map() on an array of url resources and generate 
 * a promise for each url resource of the array
 * createThumbnail(data) : received an object, generates a thumbnail and place it on stage
 * getJSON(url) : performs an XHR for a JSON and returns a promise that passes the parsed JSON 
*/
getJSON('../data/file.json')//request the array of urls
.then(function(response) { 
  //returns a promise that resolves all promises promises generated in the array
  return Promise.all(response.results.map(getJSON)); 
})
.then(function(arrayOfResources){
  //create a thumbnail for each object in the array
  arrayOfResources.forEach(function(res){
    createPlanetThumb(res);
  });
})
.catch(function(error){
  console.log(error);
});

 

Conclusion:

Today, we looked into error handling, promises chaining and we finished by studying two ways of  performing multiple asynchronous operations (series and parallel).

This concludes our three parts studies on Native JavaScript Promises. Thank you.

 

Native JavaScript promises – part2 : Effective use

Syntax

A promise can be seen as a constructor that wraps a “try-catch” around the asynchronous code. Here is the syntax of a basic promise (more syntax variation on MDN):

/**
 * Basic promise syntax with 3 states: pending, success and failure
*/
new Promise(function(resolve){
   console.log('Still in process (pending)');
   resolve();
}).then(function(){
   console.log('Resolved (success)');
}).catch(function(){ 
   console.log('An error happened (failure)');
   //Dealing with the error here!
}); 

 

Use case: Acting on the page before it fully loads

A promise can be used to “spy” on the document and create an action at a specific moment. Suppose we want something done on the page before sub resources are loaded (images, stylesheets, …), we can create a promise that resolves only when the page reaches a precise loading state and then call and action when that promise resolves.

/** 
 * Create a promise that resolves only when the document 'ready state' 
 * is not on "loading" and call an action when that promise resolves
 * We assume: 
 * doSomethingOnTheDOM() updates the DOM with whatever feedback we choose
*/ 
//Wrap an event listener for readystatechange in a Promise.
function ready() { 
  return new Promise(function(resolve){
    function checkState (){
      //Only resolves if document is not 'loading'
      if(document.readyState !== 'loading'){
        resolve(); 
      }
    }
    //Check ready state when 'readystatechange' event fires
    document.addEventListener('readystatechange', checkState);
    checkState();//also checks ready state immidiately
  });
};//ready()

//Update the DOM only when the promise resolves. 
ready().then(doSomethingOnTheDOM);

 

Fetch API, a real game changer:

The Fetch API makes the process of fetching resources a breeze by providing an elegant interface that encapsulates native JavaScript Promises and handle results and callbacks (checkout also David Walsh article).

In the following example, we won’t worry about writing the XHR request, nor  parsing the resulting resource ourselves.

//Outpout something on the DOM
//Uses fetch (fetch API) to make and XHR request and return a promise
function get(url) {
  return fetch(url); //fetch assumes the method is 'get'
}

//Performs an XHR request and returns a parsed JSON response.
function getJSON(url) { 
  return get(url).then(function(response){
    //Returns a promise that resolves with a JSON object.
    return response.json();
  });
}

//When document is ready ...
  getJSON('../data/file.json')
  .then(function(response){
    doSomethinOnTheDOM(response);
    return response; //can be reused for chaining
  });
//When document is ready ...

 

Conclusion:

We’ve just seen a basic syntax of Native JavaScript Promises and looked at one possible use case where a promise is used to target a precise loading stage of the page. We’ve finally looked at a simple use of the Fetch API.

Next time, we’ll look at native JavaScript promises’ chaining and error handling.

 

Native JavaScript promises – part1 : The concept

Many applications today are relying on network requests, threads, events or some kind of process that has an uncertain outcome. These types of operations which are called asynchronous are unpredictable and error prone. Promises are the recommended option for dealing with asynchronous operations because they are flexible, intuitive and make error handling easy.

Our goal in this first post, will be to explore the concept of native JavaScript promises and understand their use in modern web development.

 

A Promise represents a value which may be available now, or in the future, or never. The Promise object is used for asynchronous computations. – MDN –

 

Synchronous and Asynchronous operations:

Synchronous Operations: sequencial executions

The JavaScript threading model is synchronous, which means that the code runs in a single and unbroken timeline (one statement executes immediately after another one).

/**
 * Example of a synchronous code: One statement is executed
 * before the next one gets executed (guaranteed)  
*/
let soccer_player = "Samuel Eto'o"; //first executed
console.log("Player name is : ", soccer_player); //second executed (Samuel Eto'o)

 

Asynchronous Operation: uncertainty of outcome

Unlike synchronous code, asynchronous code is not guaranteed to execute in a single timeline. It is best to assume that the completion time of such operation is unknown.

/**
 * Example of an asynchronous code: Two files are requested 
 * and there is no way to know if "file1" will return before 
 * "file2" or if even any of them will return at all. 
*/
let file1 = get('file1.json'); //file1 is first requested
let file2 = get('file2.json'); //file2 is requested next
//File aren't yet available
console.log(file1); //undefined
console.log(file2); //undefined

 

Not knowing when a request ends is a serious issue for the proper running of an application and this is where Promises come to the rescue.

 

The promise: easy handling of asynchronous operations

 Definition: 

A promise is a try-catch wrapper around the code that will finish at an unpredictable time. It allows the programmer to instruct the application about how to deal with something that is expected to happen in the future without knowing exactly when.

Different states of promise:

A promise has four states which represent the possible outcomes of an asynchronous operation. The developer can then use these states to deal with the outcomes:

  1. Fulfilled (resolved): The operation was successful
  2. Rejected: The operation failed
  3. Pending: The operation is still in process
  4. Settled: The operation is done (either succeeded or failed)

What can we use promise for?

  • To turn incoming external data (JSON) into useful information in an app
  • To work with information from ajax requests (ajax is an asynchronous request)
  • To work with threading applications like messaging systems
  • To control an application’s flow (doing something when all resources of the page aren’t completely loaded)

 

Conclusion:

We’ve just seen that operations in JavaScript are not always synchronous (instructions executed in order in appearance), but can also be asynchronous (instructions executed in the future with an unpredictable timeline and outcome).  We have seen that promises deal well with asynchronous operations by wrapping them with a “try and catch” that allows the developer to prepare for the operation’s possible outcomes: “success”, “failure”, “in process” and “completion”.

Next time, we’ll look at the syntax and use cases of native JavaScript promises.

 

Sticky Footer with FlexBox

Introduction:

When a page has very little content or is seen on a very large monitor, chances are there might be not enough content to push the footer all the way to the bottom. This creates an often unpleasant empty space below the footer. Today, I would like to share my idea about creating a sticky footer with Flexbox (and make good use of the “flex-grow” property).

 

The flex-grow property specifies how much the item will grow relative to the rest of the flexible items inside the same container (w3schools).

 

The thought process:

We usually have three major components on the page, the header, main content, and footer. The process can be broken down in the following steps:

  1. We wrap these components with a flex container that occupies the entire layout’s height (min-height to 100vh)
  2. We place the flex container‘s children in a column (flex-direction tocolumn”)
  3. And finally, we set the main content to fill the page’s empty space (flex-grow to 1)

The final step will make the main content’s height grow and push the footer to the bottom, thus getting rid of that bottom empty space.

Here is some code sample:

 

.page-wrapper{
  display: flex;
  flex-direction: column; //place direct children in a column
  min-height: 100vh; //fill the entire layout
}

.main-content{
  flex-grow: 1; //grow to fill the layout empty space relative to the other components
}

 

Conclusion:

This wraps up today’s article. We talked about one possible way of creating a sticky footer with Flexbox and outlined the main steps of such a technique. The complete code and  live version are available for your reference, feel free to share your impressions with me about this article or any work you had to do in the past with sticky footers.

Thank you.

 

Split-screen Layout with FlexBox

From a UX perspective:

A split-screen layout is a full-screen web component that is segmented into two or more equal vertical columns. This type of layout is mostly used in minimalist designs for landing pages when we want users to easily focus on two or more selectable options.

From a development perspective:

A split-screen layout can be seen as a two-block layout. Both blocks varying on size and arrangement depending on the screen size.

On smaller screens: Both blocks tend to fill the entire screen and be stacked one on top of the other, forcing the user to see only one block at the time and intentionally pose an action to see the second block (scrolling or clicking an action button)

On larger screens: Both blocks tend to be visible at the same time, being side by side and occupying half of the viewport real estate.

Using Flexbox CSS module:

A split-screen is easily created in Flexbox by first creating a parent flex-container width two children blocks (split-layouts). Then, by playing with the parent flex-direction property to arrange the split layouts in a column (small screens) or in a row (large screens). Optionally, the split-screens can also be set as flex-containers in order to center their content vertically and horizontally, thus controlling the content’s presentation.

The code:

I’ve created a great pen that clearly details the process, you can see the demo right away or look at the code and preview for reference. Any of you had the opportunity to work with a split-screen layout? I would love to hear about it.

Thank you and happy coding!