Creating a content filter with Ionic components

December 15, 2017, 9:00 am Categories:

Categories

Content rich applications can, if their developers are not careful, overwhelm the user by presenting too much data in one screen which, if not remedied, often results in a poor user experience and a subsequent lack of engagement.

There are a variety of approaches that developers could take to prevent or mitigate this problem from occurring such as through lazy loading the content, splitting that over different screens with an intuitive or user friendly navigation structure or maybe providing filtering mechanisms for the user to 'drill down' into that content and only display what they want.

It's this latter approach that we're going to explore over the following tutorial with help from the following:

  • Ionic Searchbar and Ionic Radio components
  • Array filter method

Combining these together we'll create an application that allows the user to filter a list of technologies based on keywords that they're entered or categories that they've selected.

What we'll be developing

Our application will consist of a single page that allows the user to enter keyword searches into the ion-searchbar component as well as selecting technologies to be displayed based on a specific category that they've selected.

The component TypeScript logic will then use the array filter method to iterate through the list of technologies to find matches based on the user's key entries or selections.

Both approaches will, if a match is found, filter the display of technologies on the page in realtime.

By the end of this tutorial you should end up with an application akin to the following (although it's important to note, that you WILL have to supply your own technology logos - Google Image search is your friend here!):

Ionic application displaying a list of images and their descriptions with radio buttons and a search field to filter this content

The list of displayed technologies is able to be filtered with any of the following radio button categories:

  • Browser
  • Language
  • Library
  • Database
  • Operating System
  • Platform

As well as providing an option to clear any current filters and display all technologies (effectively resetting the application to its default state by removing any previous filters that may have been applied by the user).

With such options available to them the user could, for example, choose to filter the display of technologies, solely by Browser:

Ionic application displaying a list of images and their descriptions filtered by browser selection

Or filter the technology list by search input courtesy of the Ionic Searchbar component:

Ionic application displaying a list of images and their descriptions filtered by keyboard input selection

Which filters the list content in realtime by key input:

Ionic application displaying a list of images and their descriptions further filtered by keyboard input selection

Now you know what to expect let's start developing the application.

Setting the foundation

Open your system CLI, navigate to where your digital projects are stored and create the following Ionic project named ionic-search:

ionic start ionic-search blank

Once created change into the project root directory and, believe it or not, that's all you'll need as far as setting up the project is concerned.

Now you can move straight onto the coding!

Crafting the logic

As stated earlier we'll be making use of the following to provide the filtering functionality for our application:

We'll capture the user keyboard input (if using the Ionic Searchbar component) or category selection (if using the Ionic Radio component) with event handlers placed on those respective components (which we'll implement when adding the markup for the HomePage component template).

This input will then be parsed using the Array Filter method to determine if any matches have been found. If matches are found the technologies list is subsequently filtered to only display those items that match the user input/selection.

The technologies list is built from the following array which is hard coded into the application:

this.technologies = [
   {
      name : 'Angular',
      description: 'Front-end development framework',
      image: '/assets/imgs/angular-logo.png',
      type : 'framework'
   },
   {
      name : 'Apache Cordova',
      description: 'Hybrid application mobile development framework',
      image: '/assets/imgs/apache-cordova-logo.png',
      type : 'framework'
   },
   {
      name : 'Firefox',
      description: 'standards compliant browser',
      image: '/assets/imgs/firefox-logo.png',
      type : 'browser'
   },
   {
      name : 'Chrome',
      description: 'Google’s market dominant browser',
      image: '/assets/imgs/chrome-logo.png',
      type : 'browser'
   },
   {
      name : 'Internet Explorer',
      description: 'Microsoft’s original flagship browser',
      image: '/assets/imgs/ie-logo.png',
      type : 'browser'
   },
   {
      name : 'HTML5',
      description: 'Next generation upgrade for HTML language',
      image: '/assets/imgs/html5-logo.png',
      type : 'language'
   },
   {
      name : 'CSS 3',
      description: 'Stylesheet language featuring animations and transitions',
      image: '/assets/imgs/css3-logo.png',
      type : 'language'
   },
   {
      name : 'Sass',
      description: 'CSS pre-processor library',
      image: '/assets/imgs/sass-logo.png',
      type : 'library'
   },
   {
      name : 'TypeScript',
      description: 'Superset of JavaScript',
      image: '/assets/imgs/typescript-logo.png',
      type : 'language'
   },
   {
      name : 'Ionic Native',
      description: 'Ionic compatible plugin library',
      image: '/assets/imgs/ionic-native-logo.png',
      type : 'library'
   },
   {
      name : 'iOS',
      description: 'Apple mobile operating system',
      image: '/assets/imgs/apple-logo.png',
      type : 'OS'
   },
   {
      name : 'Android',
      description: 'Popular mobile operating system',
      image: '/assets/imgs/android-logo.png',
      type : 'OS'
   },
   {
      name : 'Windows',
      description: 'Microsoft’s operating system',
      image: '/assets/imgs/windows-logo.png',
      type : 'OS'
   },
   {
      name : 'PHP',
      description: 'Server side scripting language',
      image: '/assets/imgs/php-logo.png',
      type : 'language'
   },
   {
      name : 'MySQL',
      description: 'Popular open-source database',
      image: '/assets/imgs/mysql-logo.png',
      type : 'database'
   },
   {
      name : 'Mongo DB',
      description: 'Popular NoSQL Database solution',
      image: '/assets/imgs/mongodb-logo.png',
      type : 'database'
   },
   {
      name : 'Firebase',
      description: 'Popular backend-as-a-service platform',
      image: '/assets/imgs/firebase-logo.png',
      type : 'platform'
   },
   {
      name : 'Safari',
      description: 'Apple web browser',
      image: '/assets/imgs/safari-logo.png',
      type : 'browser'
   },
   {
      name : 'Opera',
      description: 'Nimble web browser',
      image: '/assets/imgs/opera-logo.png',
      type : 'browser'
   },
   {
      name : 'Web Components',
      description: 'Bundled page assets',
      image: '/assets/imgs/web-components-logo.png',
      type : 'library'
   }];

Here we opt for an array of objects, essentially an associative array, which defines the content for each respective technology that will be rendered to and displayed in the HomePage template.

The images, as explained earlier, are sourced from Google Images but copied to the following directory in the application: ionic-search/src/assets/imgs.

We then define 2 separate methods for filtering the user input - depending on which filter they've chosen:

  • filterTechnologies (for keyboard input received from the Ionic Searchbar component)
  • onFilter (for input received from individual Ionic Radio components)

The filterTechnologies method receives the keyboard input (in realtime) passing this to the Array Filter method which searches for potential matches on the name and description keys of the technologies array.

If any matches are found the contents of the technologies array is reset to those matches:

filterTechnologies(param : any) : void
{
   this.declareTechnologies();

   let val : string 	= param;

   // DON'T filter the technologies IF the supplied input is an empty string
   if (val.trim() !== '') 
   {
      this.technologies = this.technologies.filter((item) => 
      {
        return item.name.toLowerCase().indexOf(val.toLowerCase()) > -1 || item.description.toLowerCase().indexOf(val.toLowerCase()) > -1;
      })
   } 
}

Similarly the onFilter method receives the value from the Ionic Radio component selection and also passes this to the Array Filter method which then searches for potential matches on the type key of the technologies array.

If any matches are found the contents of the technologies array is reset to those matches:

onFilter(category : string) : void
{
   this.declareTechnologies();

   // Only filter the technologies array IF the selection is NOT equal to value of all
   if (category.trim() !== 'all') 
   {
      this.technologies = this.technologies.filter((item) => 
      {
         return item.type.toLowerCase().indexOf(category.toLowerCase()) > -1;
      })
   }
}

Bringing all of this together then the completed code for our ionic-search/src/pages/home/home.ts component class looks like this:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {


   
   /**
    * @name technologies
    * @type {Array} 
    * @public
    * @description     Array for holding individual object data of development technologies
    */
   public technologies : Array<any>;



   constructor(public navCtrl: NavController) {  }


   

   /**
    * Triggered when template view has completed loading
    *
    * @public
    * @method ionViewDidLoad 
    * @return {None}
    */
   ionViewDidLoad()
   {
      this.declareTechnologies();
   }




   /**
    * Populates the technologies array with different technologies
    *
    * @public
    * @method declareTechnologies 
    * @return {None}
    */   
   declareTechnologies() : void
   {
       this.technologies = [
          {
            name : 'Angular',
            description: 'Front-end development framework',
            image: '/assets/imgs/angular-logo.png',
            type : 'framework'
          },
          {
            name : 'Apache Cordova',
            description: 'Hybrid application mobile development framework',
            image: '/assets/imgs/apache-cordova-logo.png',
            type : 'framework'
          },
          {
            name : 'Firefox',
            description: 'standards compliant browser',
            image: '/assets/imgs/firefox-logo.png',
            type : 'browser'
          },
          {
            name : 'Chrome',
            description: 'Google&rsquo;s market dominant browser',
            image: '/assets/imgs/chrome-logo.png',
            type : 'browser'
          },
          {
            name : 'Internet Explorer',
            description: 'Microsoft&rsquo;s original flagship browser',
            image: '/assets/imgs/ie-logo.png',
            type : 'browser'
          },
          {
            name : 'HTML5',
            description: 'Next generation upgrade for HTML language',
            image: '/assets/imgs/html5-logo.png',
            type : 'language'
          },
          {
            name : 'CSS 3',
            description: 'Stylesheet language featuring animations and transitions',
            image: '/assets/imgs/css3-logo.png',
            type : 'language'
          },
          {
            name : 'Sass',
            description: 'CSS pre-processor library',
            image: '/assets/imgs/sass-logo.png',
            type : 'library'
          },
          {
            name : 'TypeScript',
            description: 'Superset of JavaScript',
            image: '/assets/imgs/typescript-logo.png',
            type : 'language'
          },
          {
            name : 'Ionic Native',
            description: 'Ionic compatible plugin library',
            image: '/assets/imgs/ionic-native-logo.png',
            type : 'library'
          },
          {
            name : 'iOS',
            description: 'Apple mobile operating system',
            image: '/assets/imgs/apple-logo.png',
            type : 'OS'
          },
          {
            name : 'Android',
            description: 'Popular mobile operating system',
            image: '/assets/imgs/android-logo.png',
            type : 'OS'
          },
          {
            name : 'Windows',
            description: 'Microsoft&rsquo;s operating system',
            image: '/assets/imgs/windows-logo.png',
            type : 'OS'
          },
          {
            name : 'PHP',
            description: 'Server side scripting language',
            image: '/assets/imgs/php-logo.png',
            type : 'language'
          },
          {
            name : 'MySQL',
            description: 'Popular open-source database',
            image: '/assets/imgs/mysql-logo.png',
            type : 'database'
          },
          {
            name : 'Mongo DB',
            description: 'Popular NoSQL Database solution',
            image: '/assets/imgs/mongodb-logo.png',
            type : 'database'
          },
          {
            name : 'Firebase',
            description: 'Popular backend-as-a-service platform',
            image: '/assets/imgs/firebase-logo.png',
            type : 'platform'
          },
          {
            name : 'Safari',
            description: 'Apple web browser',
            image: '/assets/imgs/safari-logo.png',
            type : 'browser'
          },
          {
            name : 'Opera',
            description: 'Nimble web browser',
            image: '/assets/imgs/opera-logo.png',
            type : 'browser'
          },
          {
            name : 'Web Components',
            description: 'Bundled page assets',
            image: '/assets/imgs/web-components-logo.png',
            type : 'library'
          }];
    }




   /**
    * Filter technologies array by keyword/letter
    *
    * @public
    * @method filtertechnologies 
    @ param event     {Object}		The event object emitted by the <ion-searchbar> when input is entered
    * @return {None}
    */   
   filterTechnologies(param : any) : void
   {
      this.declareTechnologies();


      let val : string 	= param;

      // DON'T filter the technologies IF the supplied input is an empty string
      if (val.trim() !== '') 
      {
         this.technologies = this.technologies.filter((item) => 
         {
           return item.name.toLowerCase().indexOf(val.toLowerCase()) > -1 || item.description.toLowerCase().indexOf(val.toLowerCase()) > -1;
         })
      } 
   }




   /**
    * Filter technologies array by type selected
    *
    * @public
    * @method onFilter 
    @ param val     {String}		The string value supplied by the <ion-radio> when selected
    * @return {None}
    */   
   onFilter(category : string) : void
   {
      this.declareTechnologies();

      // Only filter the technologies array IF the selection is NOT equal to value of all
      if (category.trim() !== 'all') 
      {
         this.technologies = this.technologies.filter((item) => 
         {
           return item.type.toLowerCase().indexOf(category.toLowerCase()) > -1;
         })
      }
   }

}

Adding the template mark-up

With the application logic in place for filtering the displayed content we now need to add the necessary markup to the HomePage component template.

Open the ionic-search/src/pages/home/home.html and structure the template content so that it resembles the following:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Search filter
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <ion-searchbar 
     (ionInput)="filterTechnologies($event.target.value)"></ion-searchbar>


  <ul class="filters" radio-group>
     <li>
       <ion-label>Browser</ion-label>
       <ion-radio 
          value="browser"
          (ionSelect)="onFilter($event)"></ion-radio>
     </li>
   
   
     <li>
       <ion-label>Language</ion-label>
       <ion-radio 
          value="language"
          (ionSelect)="onFilter($event)"></ion-radio>
     </li>
   
   
     <li>
       <ion-label>Library</ion-label>
       <ion-radio 
          value="library"
          (ionSelect)="onFilter($event)"></ion-radio>
     </li>
   
   
     <li>
       <ion-label>Database</ion-label>
       <ion-radio 
          value="database"
          (ionSelect)="onFilter($event)"></ion-radio>
     </li>
   
   
     <li>
       <ion-label>Operating System</ion-label>
       <ion-radio 
          value="OS"
          (ionSelect)="onFilter($event)"></ion-radio>
     </li>
   
   
     <li>
       <ion-label>Platform</ion-label>
       <ion-radio 
          value="platform"
          (ionSelect)="onFilter($event)"></ion-radio>
     </li>
   
   
     <li>
       <ion-label>All</ion-label>
       <ion-radio 
          value="all"
          checked 
          (ionSelect)="onFilter($event)"></ion-radio>
     </li>
  </ul>


  <ul class="technologies">
    <li *ngFor="let technology of technologies">
      <img src="{{ technology.image }}">
      <h2>{{ technology.name }}</h2>
      <div [innerHTML]="technology.description"></div>
    </li>
  </ul>
</ion-content>

As you can see this is a fairly simple markup structure consisting of a search input field (provided by the ionic Searchbar component - which triggers the filterTechnologies method of the component class on each key entry) and a list of radio buttons for filtering the displayed content by a specific category (courtesy of the component class's onFilter method).

We now complete the development of our application with the following style rules added to the component Sass file at ionic-search/src/pages/home/home.scss:

page-home {

   .filters {
      list-style: none;
      display: flex;
      flex-flow: row wrap;

      li {
         width: 12%;
      	 text-align: center;
      }
   }


   .technologies {
      list-style: none;
      display: flex;
      flex-flow: row wrap;

      li {
         background: rgba(230, 230, 230,1 );
         padding: 1em;
      	 width: 31.75%;
      	 margin: 0.25em;
      	 text-align: center;

      	 img {
      	    display: block;
      	    width: 25%;
      	    margin: auto;
      	 }
      }
   }

}

These simply layout both the radio buttons and the content displayed in the HomePage component making the interface more aesthetic and appealing.

With this final piece of development in place we can now test the application in our desktop browser by running the following Ionic CLI command, from the root of the ionic-search project directory:

ionic serve

Which, if all has gone smoothly, should run the application like so:

Ionic application displaying a list of images and their descriptions with radio buttons and a search field to filter this content

If you're seeing this then congratulations - you're able to start filtering content using the search field and/or radio buttons!

In summary

Although relatively simple the above tutorial nonetheless demonstrates just how quick and easy it is to filter content using a combination of Ionic UI components (including aspects of their respective API's) and the TypeScript/JavaScript array filter method.

This could of course be extended to filtering remote content, such as that drawn from a NoSQL solution like MongoDB or Firebase, or using more enhanced filtering options within the onFilter and filterTechnologies methods.

Even though there's scope for further development it's interesting to see just how simple and effective, yet deceptively powerful, the use of Ionic components and array methods can be for effective content filtering in your applications.

If you've enjoyed what you've read and/or found this helpful please feel free to share your comments, thoughts and suggestions in the comments area below.

I explore components and their usage within the Ionic framework within my e-book featured below and if you're interested in learning more about further articles and e-books please sign up to my FREE mailing list.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top