Programming Tutorials

  • View all tutorials
  • Build an Instant Search Feature with AngularJS
    AngularJS is a popular JavaScript web framework that is used to aid developers overcome common issues when building single-page applications. It's aim is to simplify web development through its two-way data binding and the model-view-controller (MVC) architecture it provides. In this tutorial we'll build a module that updates search results in real-time depending on what keyword has been entered.

    Installing AngularJS

    Installing AngularJS is as simple as including a script tag in your HTML page. Below we'll create a base HTML file where our content will go and where we include the AngularJS code.
    <!DOCTYPE html>
    <html>
    <head> 
      <meta charset="utf-8" />
      <title> Angular Search Feature </title>    
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>         
    </head>
    <body>
    
      <!-- code goes here... -->
    
    </body>
    </html>

    Gathering data

    For this search feature we'll be building, we'll be filtering through a set of art pieces found on Etsy. I created an array of objects for use in this tutorial. Save the code below into a file called data.js.
    var data = [
      {
        image: 'https://img1.etsystatic.com/053/1/7725562/il_570xN.768673249_tydk.jpg',
        url: 'http://etsy.me/1WJRVyk',
        title: 'Arctic Wolf watercolor painting print',
        artist: 'SlaviART',
        materials: ['watercolor', 'paper', 'paint', 'pencil', 'giclee print']
      },
      {
        image: 'https://img1.etsystatic.com/055/2/9019569/il_570xN.766250917_76pj.jpg',
        url: 'http://etsy.me/25h3Gl0',
        title: 'Animal Bull Painting 72" Abstract Painting on canvas',
        artist: 'KobyFeldmos',
        materials: ['oil', 'canvas']
      },
      {
        image: 'https://img1.etsystatic.com/068/1/8470287/il_570xN.797157695_i042.jpg',
        url: 'http://etsy.me/1Rj9XQ3',
        title: 'Black Cat Art Print',
        artist: 'ColorWatercolor',
        materials: ['archival', 'canon lucia pigment inks', 'chroma optimizer', 'true color prints', 'fine art', 'watercolor']
      },
      {
        image: 'https://img1.etsystatic.com/025/0/7412974/il_570xN.648442321_hctd.jpg',
        url: 'http://etsy.me/1U6UBzN',
        title: 'Lieutenant Hare: Military Print, Rabbit print Wall Art Wall Decor',
        artist: 'FabFunky',
        materials: ['dictionary', 'page', 'paper', 'ink', 'book', 'vintage']
      },
      {
        image: 'https://img1.etsystatic.com/058/0/5941978/il_570xN.736849659_io0c.jpg',
        url: 'http://etsy.me/1OJ6FFS',
        title: 'White Gold Brown Blue Flower Abstract Tree painting',
        artist: 'tjenkinsarts',
        materials: ['acrylic', 'mixed media', 'canvas']
      },
      {
        image: 'https://img0.etsystatic.com/019/2/6406241/il_570xN.567597748_e5os.jpg',
        url: 'http://etsy.me/1XrTQa1',
        title: 'Abstract painting print, GICLEE PRINT, pink and white painting, Landscape print',
        artist: 'LolaDonoghue',
        materials: ['paper', 'archival inks']
      },
      {
        image: 'https://img1.etsystatic.com/131/1/13027005/il_570xN.1020433741_kfwt.jpg',
        url: 'http://etsy.me/1YS8Ywc',
        title: 'IN FULL BLOOM Giclee',
        artist: 'BuffaloBoutinFineArt',
        materials: ['acrylic', 'print', 'giclee', 'palette knife', 'paint', 'canvas', 'happy', 'impasto', 'field', 'landscape']
      }
    ];
    

    App mockup

    Now create a blank app.js file which is where our AngularJS/JavaScript code will go. Finally, create a style.css file where our app styles will go. Add all of these new JavaScript and CSS files to our HTML page like below:
    <!DOCTYPE html>
    <html>
    <head> 
      <meta charset="utf-8" />
      <title> Angular Search Feature </title>    
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>  
      <link type="text/css" rel="stylesheet" href="style.css">        
    </head>
    <body>
    
      <!-- code goes here... -->
    
    <script src="data.js"></script>
    <script src="app.js"></script>
    </body>
    </html>
    
    Now we can get started writing AngularJS code. We'll start off by creating the app module where our app will live, and controller that will control the data and view for our app.
    <!DOCTYPE html>
    <html>
    <head> 
      <meta charset="utf-8" />
      <title> Angular Search Feature </title>    
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>  
      <link type="text/css" rel="stylesheet" href="style.css">        
    </head>
    <body>
    
      <div ng-app="app" ng-controller="ctrl" id="app">
      </div>
    
    <script src="data.js"></script>
    <script src="app.js"></script>
    </body>
    </html>
    
    And we'll hook this up to some AngularJS code in our app.js fie:
    var app = angular.module('app', []);
    
    app.controller('ctrl', function($scope, $window) {
      $scope.pieces = $window.data;
    });
    
    In this controller portion of the code above, we pass in the variable $scope which will contain the variables and properties we need for this search feature, and the $window variable which will allow us to get the data that lives in the data.js file. We'll now be able to use the pieces variable in our HTML, as you'll see below.

    Building out the search feature

    Before we move along to more JavaScript code, add the following styles into your style.css file.
    * {
      margin: 0;
      padding: 0;
    }
    
    #app {
      width: 600px;
      margin: 30px auto;
      background: #4991de;
      padding: 25px;
      border-radius: 5px;
    }
    
    #app p:first-child { 
      background: #d6eaff;
      border-radius: 5px;
      padding: 10px 10px;
    }
    
    #app p:first-child input {
      outline: none;
      font-size: 18px;
      width: 96%;
      border: 0;
      border-radius: 3px;
      background: #d6eaff;
      padding: 8px 5px;
      font-family: Helvetica;
    }
    
    #app ul {
      margin-top: 20px;
      background: white;
      list-style-type: none;
      overflow: auto;
      border-radius: 5px;
    }
    
    #app ul li {
      border-bottom: 1px solid #EFEFEF;
      padding: 10px 20px;
      overflow: auto;
    }
    
    #app ul li img,
    #app ul li h4 {
      float: left;
    }
    
    #app ul li h4 {
      width: 80%;
      font-family: Helvetica;
      margin-bottom: 8px;
    }
    
    #app ul li h4 a { 
      color: #3A3A3A;
    }
    
    #app ul li h4 a:hover {
      color: #4991de;
    }
    
    #app ul li img { 
      width: 90px;
      height: 90px;
      background-size: cover;
      border-radius: 5px;
      margin-right: 15px;
    }
    
    #app ul li p {
      color: #9A9A9A;
      font-family: Helvetica;
      font-size: 13px;
    }
    
    In our controller code before, we added a variable called pieces onto the scope object which contains all of the art data. Now in our HTML, we can simply display the data using AngularJS's data binding feature:
    <div ng-app="app" ng-controller="ctrl" id="app">
      {{ pieces }}
    </div>
    
    And if you reload your page you should now see this: Now that we know we have access to the data object with all the art pieces, let's actually properly style our search feature. We'll use several AngularJS directives, which add functionality to our app, in our HTML to display the data. You can see below that for the most part we are using plain HTML, along with the double brackets for data binding and the ng- prefix which allows us to connect the AngularJS model to our view.
    <!DOCTYPE html>
    <html>
    <head> 
      <meta charset="utf-8" />
      <title> Angular Search Feature </title>    
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>  
      <link type="text/css" rel="stylesheet" href="style.css">        
    </head>
    <body>
    
      <div ng-app="app" ng-controller="ctrl" id="app">
        <!-- 'keyword' will serve as the model for what the user enters -->
        <p><input type="text" ng-model="keyword" placeholder="search for..."></p>
        <ul>
          <!-- display each art object using ng-repeat directive -->
          <li ng-repeat="x in pieces">
            <img src="{{ x.image }}">
            <h4><a href="{{ x.url }}" target="_blank">{{ x.title }}</a></h4>
            <p>{{ x.artist }}</p>
            <p><span ng-repeat="m in x.materials">{{ m }}</span></p>
          </li>
        </ul>
      </div>
    
    <script src="data.js"></script>
    <script src="app.js"></script>
    </body>
    </html>
    
    Because you copied our styles for the app, if you reload your page now you should see the following: We have our app styled and ready to go, we now just need to filter the art pieces depending on what the user enters. To connect the input text and our view, we'll use the keyword variable in our AngularJS code which we declared in the input text area via ng-model in our HTML. Since we're going to be filtering elements, we'll create our own AngularJS filter. This filter function will return a subset of art objects that contain the keyword entered by the user. For example, if the user enters "abstract" then only the art objects that contain that keyword somewhere should be displayed. We'll name our filter function search and create it in our app.js file like so:
    app.filter('search', function() {
      return function(items, keyword) {
        // if no keyword is entered, just display all the items
        if (!keyword) { 
          return items; 
        } 
        // TODO
        // return subset of new items here
        else {
          return [items[0], items[1]];
        }
      };
    });
    
    Then to hook up this filter function to our HTML page, we modify the ng-repeat line to be the following:
    <li ng-repeat="x in pieces | search: keyword">
    
    The keyword variable, which is coming from the input text area, is being passed as an argument to the search filter. Now if you reload the page, you should see all the art pieces, but once you start typing something to search for, only the first two elements appear because we are returning a new array with only those elements in our filter function. This was just to provide a simple example of how the filter function works, but now we need to modify it so that it returns the proper subset of items that contain the keyword. The filter function should now contain this code to properly filter:
    app.filter('search', function() {
      return function(items, keyword) {
        // if no keyword is entered, just display all the items
        if (!keyword) { 
          return items; 
        } 
        // return subset of new items 
        else {
          var newItems = [];
          var keyword = keyword.toLowerCase();
          // create new set of items where 'keyword' exists in object data
          for (var i of items) {
            if (i.title.toLowerCase().indexOf(keyword) > -1 || 
                i.artist.toLowerCase().indexOf(keyword) > -1 || 
                checkMaterials(i.materials, keyword)) { newItems.push(i); }
          }
          // loop through materials checking if 'keyword' exists
          function checkMaterials(mat, keyword) {
            for (var m of mat) {
              if (m.toLowerCase().indexOf(keyword) > -1) {
                return true;
              }
            }
            return false;
          }
          return newItems;
        }
      };
    });
    
    We now have a properly working instant search feature built using AngularJS! You can check out a live demo here. You can search by entering any text now that exists in the artwork title, artist name, or materials. Live Demo Below are some useful resources for those of you new to AngularJS: Custom filters in AngularJS Scotch.io tutorials Official AngularJS tutorial
    mrdaniel wrote this tutorial on 5/23/16 | javascript, angularjs
    Comments
    Log in to submit a comment.