Monday, August 15, 2016

The Definitive Ionic Starter Guide_part1


Ionic is a powerful tool for building mobile apps using HTML, CSS, and JavaScript. This starter guide focuses on getting up and running with a realistic mobile app and learning about the primary features of Ionic. You will see many features of Ionic with a complete app example. You will end this guide with a strong command of Ionic and how it enables you to build beautiful, functional mobile apps.

Ionic is build on Angular and I will assume you are at least moderately familiar with Angular and the basics of web applications. If you need some help with Angular, I recommend reading up from Todd Motto's post AngularJS Tutorial: A Comprehensive 10,000 Word Guide. It is also assumed you have NodeJS installed.

During this guide you will learn how to build a stock tracking app. You can preview the completed app here and see the whole project on GitHub at gnomeontherun/ionic-definitive-guide. You can resize the browser to see how it would appear on mobile, or if you are using Chrome you can use the device emulator feature.

Ionic, the missing hybrid app SDK

Ionic is built for hybrid apps, which are mobile apps that are written with HTML, CSS, and JavaScript instead of the native platform languages (Java for Android, Swift for iOS). When building a native app, you have access to the SDK which includes interface components such as tabs and complex lists. These are the interface controls that you are familiar with from using mobile apps, and Ionic provides a comprehensive set of components for building hybrid apps.

However, Ionic is really more than just interface components. It also:
  • provides a fantastic CLI utility for managing projects.
  • leverages SASS to easily customize components.
  • is built and maintained by a professional team, with a strong community behind it.
  • incorporates a pluggable architecture for including 'ions' (additional components and features).
  • has a large set of icons.
In addition, Ionic has a whole platform of services to support your apps, such as Creator for a visual drag/drop design experience, View for sharing a preview/beta version of your app with anyone, and Push for easily setting up push notifications. Recently added were Deploy and Analytics which are currently in alpha. You can expect Ionic to expand into a complete platform to serve the needs of app developers.

Setup for Ionic

First things first, we need to get Ionic setup. For this tutorial we will be previewing in a browser, not on a mobile device (though you could if you follow the Ionic guide for details on emulating and loading to a device). You need to have Node installed on your system before you can install Ionic (Note: io.js may not work properly). Run this command in the terminal/command line prompt:
  1. $ npm install -g ionic
Here the Node Package Manager (NPM) will download and install the Ionic CLI. This is essential for building Ionic apps, and we'll use it to setup, preview, and build our app. Let's cover the primary types of features in Ionic.

Ionic components & services

Before we jump into building our app, I wanted to give you a quick overview of Ionic's primary features. Ionic provides two primary features: components and services.

Ionic Components

Components are the user interface elements you declare using markup and CSS classes such as tabs, headers, slideshows, side menus, and more. These components either just CSS classes (like CSS frameworks like Bootstrap) or Angular directives. Some of the CSS components (inputcardbutton) don't provide additional features, but Ionic provides nicer styling that works well on mobile. The directive components (sidemenulistslidebox) are available as HTML tags.
  1. <!-- Card: CSS Component Example -->
  2. <div class="list card">
  3.   <div class="item">Basic card!</div>
  4. </div>
  5. <!-- SlideBox: Directive Component Example -->
  6. <ion-slide-box slide-interval="10000" does-continue="true">
  7.   <ion-slide>Slide 1</ion-slide>
  8.   <ion-slide>Slide 2</ion-slide>
  9. </ion-slide-box>
In the two examples above, the first is a visual card like you might see in many apps like Google Now. It is created simply by using the CSS classes. The second is a slide box, which is a directive and declared using HTML tags. The slide box example could also include attributes, like slide-interval which provide configuration to the slide box (in this case sets the length of time for each slide to display).

Ionic Services

Services are programmatic user interface elements that are declared in JavaScript, and are provided using Angular's services architecture. These are typically used in your controllers, and provide interface elements that have a limited display time (such as modals, popups, loaders). Just like Angular services, Ionic services all start with a $ and are very clearly named like you see in this example.
  1. function Controller($scope, $ionicSlideBoxDelegate) {
  2.   $scope.next = function() {
  3.     $ionicSlideBoxDelegate.next();
  4.   }
  5.   $scope.previous = function() {
  6.     $ionicSlideBoxDelegate.previous();
  7.   }
  8. }
In this controller, there are two scope methods that control the slide box using the service (any services that manage a component are delegate services). This would allow any custom button to change the slide, such as these two buttons.
  1. <button ng-click="next()">Next</button>
  2. <button ng-click="previous()">Previous</button>
Other services create a new visual experience, such as the loader. These will inject content into the current view as needed to create the desired effect, in this case a loading screen will overlay with a message, and after 2 seconds it will automatically hide.
  1. function Controller($timeout, $ionicLoading) {
  2.   $ionicLoading.show({
  3.     template: 'Loading'
  4.   });
  5.   $timeout(function() {
  6.     $ionicLoading.hide();
  7.   }, 2000);
  8. }
Now let's get a new project started and see these things in action. If at any point you want to see the entire codebase, check out the gnomeontherun/ionic-definitive-guide GitHub project.

Starting the Ionic project

Let the fun begin! The first thing is to generate a new project. The Ionic CLI we installed before will help us do this.
  1. $ ionic start stocks https://github.com/ionic-in-action/starter
  2. $ cd stocks
  3. $ ionic serve
This will create a new blank app called stocks based on the starter app I created for my book Ionic in Action. This starter app is blank, and is ideal for new projects. The ionic serve command should have opened up the new app in your browser, and it will be just a blank page. Have no fear, we shall fix that now.

Setting up Sass for styling

Ionic comes with a very helpful feature for customizing the default components and color presets using Sass. It is also recommended that you write any custom styles in the same way to take advantage of the variables and auto-generation provided by Ionic.

Sass support is not enabled by default in a new project. The following command will setup your project with Sass support.
  1. $ ionic setup sass
This command will generate a new CSS file based on the the scss/ionic.app.scss file, and output it to css/ionic.app.css. Then it will update the index.html file to load the new CSS file instead. Lastly, it enables Ionic commands to automatically regenerate the styles when you build the app, so you can't forget.

This app needs some styling, so you'll need to replace the contents of scss/ionic.app.scss file with the following
  1. // Override variables
  2. $light: #eee;
  3. $lighter: #fff;
  4. $darker: #363636;
  5. $assertive: #B33F33;
  6. $balanced: #70AB23;
  7. $positive: #366091;

  8. // The path for our ionicons font files, relative to the built CSS in www/css
  9. $ionicons-font-path: "../lib/ionic/fonts" !default;

  10. // Include all of Ionic
  11. @import "www/lib/ionic/scss/ionic";

  12. // Dark theme for backgrounds.
  13. .view, .pane, .modal {
  14.   background: $darker;
  15. }

  16. // Style the form inside of the footer bar
  17. .bar-search {
  18.   padding: 0;

  19.   form {
  20.     display: block;
  21.     width: 100%;
  22.   }

  23.   .item {
  24.     padding: 3.75px 10px;
  25.   }
  26. }

  27. // Make the item-dark style default by extending it back on top of item
  28. .item {
  29.   @extend .item-dark;
  30. }

  31. //
  32. .item-reorder .button.icon {
  33.   color: $light;
  34. }

  35. // Make inputs nicer on dark
  36. .item-input {

  37.   input {
  38.     margin-right: 30px;
  39.     padding-left: 5px;
  40.     background: $darker;
  41.     color: $light;
  42.   }
  43.   .input-label {
  44.     color: $light;
  45.   }
  46. }
  47. .item-input-wrapper {
  48.   background: $darker;

  49.   input {
  50.     color: $lighter;
  51.   }
  52. }

  53. // Make toggler nicer on dark
  54. .toggle .track {
  55.   background-color: $dark;
  56.   border-color: $darker;
  57. }
  58. .toggle input:checked + .track {
  59.   background-color: $positive;
  60.   border-color: $positive;
  61. }

  62. // Remove a bottom border
  63. .tabs-striped .tabs {
  64.   border-bottom: 0;
  65. }

  66. // Allow the tabs to be as wide as needed
  67. .tab-item {
  68.   max-width: none;
  69. }

  70. // Styles for the quote component
  71. .quote {
  72.   background: $darker;
  73.   padding: 5px;
  74.   border-radius: 4px;
  75.   display: block;
  76.   position: absolute;
  77.   top: 1px;
  78.   right: 16px;
  79.   text-align: center;
  80.   width: 90px;
  81.   height: 50px;
  82.   color: $lighter;

  83.   .spinner svg {
  84.     margin-top: 6px;
  85.   }

  86.   &.positive {
  87.     background: $balanced;
  88.     color: $light;
  89.   }

  90.   &.negative {
  91.     background: $assertive;
  92.     color: $light;
  93.   }

  94.   .quote-change {
  95.     font-size: 0.8em;
  96.     color: $light;
  97.   }
  98. }
At the top of these styles, several of the Ionic variables are overridden with some custom colors (so it doesn't appear with the same colors as default Ionic). The rest of the styles are commented, and it will be easier to review all of the styles when the app is completed.

This will setup all of the styles for the app. It is best to start a project setting up Sass in your project at the start, though you can do it anytime. Next you will start getting the base navigation setup.

Add Ionic's navigation components

Navigation is core to all apps, and Ionic provides several components that can be useful for navigation. In this example, you will use the ionTabs and ionNavView components to have tabs at the bottom to navigate between views. The ionSideMenus component is often used as well to expose a list of links for navigation.

Ionic is built using the popular ui-router project, which is an enhanced replacement for Angular's core ngRoute component. Ionic adds another layer of enhancements on top of ui-router, which is baked into the Ionic components and services. It leverages the idea of declaring states, which is a place in the app that describes the associated controller, view, template, and possibly other details. It will become more clear as we see some examples.

The ionNavView component is typically the center of an Ionic app's navigation, and works with several other components to allow you to craft intuitive navigation. Open up the www/index.html file, and update the body of the HTML file with the following.
  1. <body ng-app="App">
  2.   <!-- The ionNavBar updates the title and buttons as the application state changes -->
  3.   <ion-nav-bar class="bar-positive">
  4.     <!-- The ionNavBackButton knows when to show or hide based on current state -->
  5.     <ion-nav-back-button></ion-nav-back-button>
  6.   </ion-nav-bar>
  7.   <!-- Primary ionNavView which will load the views -->
  8.   <ion-nav-view></ion-nav-view>
  9. </body>
Here you see three components, ionNavViewionNavBar, and ionNavBackButton. The ionNavBar will contain our header content, such as the ionNavBackButton and a title of the state. Navbars are very common in apps, and it will automatically update the title as the user navigates between views, and conditionally show the ionNavBackButton when a user is allowed to go back in the history.

Now if you save these changes and look at the browser, you'll now see a blue navbar along the top. The ionNavBar is gray by default, but with the class bar-positive added it adopts a new color. There is a set of color presets that many components can adopt, and you'll see them sprinkled in throughout the example.

This app isn't very impressive yet, because we haven't defined any states to actually load (hence the blank screen). Let's get the first state setup.

Add the tabs state

It is time to add the tabs state's template. You will declare the template which will contain the tabs component with two tabs for the tabs.quotes and tabs.portfolio states. You'll need to create a new file at www/views/tabs/tabs.html and add the following markup.
  1. <!-- ionTabs wraps the ionTab directives -->
  2. <ion-tabs class="tabs-icon-top tabs-dark tabs-striped">
  3.   <!-- Quotes tab -->
  4.   <ion-tab title="Quotes" icon-on="ion-ios-pulse-strong" icon-off="ion-ios-pulse" ui-sref="tabs.quotes">
  5.     <!-- ionNavView for the quotes tab -->
  6.     <ion-nav-view name="quotes"></ion-nav-view>
  7.   </ion-tab>
  8.   <!-- Portfolio tab -->
  9.   <ion-tab title="Portfolio" icon-on="ion-ios-paper" icon-off="ion-ios-paper-outline" ui-sref="tabs.portfolio">
  10.     <!-- ionNavView for the portfolio tab -->
  11.     <ion-nav-view name="portfolio"></ion-nav-view>
  12.   </ion-tab>
  13. </ion-tabs>
Here the ionTabs component contains two ionTab components, which will display two tabs. The attributes declare icons for when the tab is active and inactive, as well as a link to a particular state using the ui-sref attribute. Inside of each ionTab are ionNavView components, which must have a name. You can only have one ionNavView that is unnamed, and that is in the index.html (which acts as the default). Later, when you create the tab states you will declare the states to match these specific ionNavViews. This is done so that each tab can have its own, independent navigation history, which will be demonstrated in depth later.

Now create www/views/tabs/tabs.js and add the following JavaScript that declares the 'tabs' state. Be sure to also add a script tag to the index.html file after the app.js file to load this file.
  1. angular.module('App')

  2. .config(function($stateProvider) {
  3.   $stateProvider
  4.     .state('tabs', {
  5.       abstract: true,
  6.       url: '/tabs',
  7.       templateUrl: 'views/tabs/tabs.html'
  8.     });
  9. });
The tabs view is abstract, which is unique to properly support nested ionNavView components like you see inside of the tabs. This simply means you will never go directly to just the tabs state, but in fact you will always go to a child state. Or in other words, it means you always go directly to one of the two tabs because it doesn't make sense to navigate to the tabs without one of them being selected.
Sadly, yet again, the screen is blank. Remember, the tabs view is abstract so you can only see it when you navigate to a child tab state. That means the next step is to create the first child tab state, so the tabs will appear and some very interesting things will start to happen.

Add the services

But wait! You will need some Angular services to help manage data for this app, and I don't want to spend a lot of time on them. You can look through the comments to see how they work, and they should be familiar to Angular developers. The first is a simple service to help manage data in localStorage, and the second is a service to load stock quotes from Yahoo! Finance. If you are not familiar with Angular and creating services, it is best to take a moment and review the Angular services documentation.

First create the file www/js/localstorage.js with the content in the code below. Be sure to add a script tag to index.html.
  1. angular.module('App')

  2. .factory('LocalStorageService', function() {

  3.   // Helper methods to manage an array of data through localstorage
  4.   return {
  5.     // This pulls out an item from localstorage and tries to parse it as JSON strings
  6.     get: function LocalStorageServiceGet(key, defaultValue) {
  7.       var stored = localStorage.getItem(key);
  8.       try {
  9.         stored = angular.fromJson(stored);
  10.       } catch(error) {
  11.         stored = null;
  12.       }
  13.       if (defaultValue && stored === null) {
  14.         stored = defaultValue;
  15.       }
  16.       return stored;
  17.     },
  18.     // This stores data into localstorage, but converts values to a JSON string first
  19.     update: function LocalStorageServiceUpdate(key, value) {
  20.       if (value) {
  21.         localStorage.setItem(key, angular.toJson(value));
  22.       }
  23.     },
  24.     // This will remove a key from localstorage
  25.     clear: function LocalStorageServiceClear(key) {
  26.       localStorage.removeItem(key);
  27.     }
  28.   };

  29. });
Now create another file at www/js/quotes.js with the following code. Again, make sure to add a script tag to the index.html.
  1. angular.module('App')

  2. .factory('QuotesService', function($q, $http) {

  3.   // Create a quotes service to simplify how to load data from Yahoo Finance
  4.   var QuotesService = {};

  5.   QuotesService.get = function(symbols) {
  6.     // Convert the symbols array into the format required for YQL
  7.     symbols = symbols.map(function(symbol) {
  8.       return "'" + symbol.toUpperCase() + "'";
  9.     });
  10.     // Create a new deferred object
  11.     var defer = $q.defer();
  12.     // Make the http request
  13.     $http.get('https://query.yahooapis.com/v1/public/yql?q=select * from yahoo.finance.quotes where symbol in (' + symbols.join(',') + ')&format=json&env=http://datatables.org/alltables.env').success(function(quotes) {
  14.       // The API is funny, if only one result is returned it is an object, multiple results are an array. This forces it to be an array for consistency
  15.       if (quotes.query.count === 1) {
  16.         quotes.query.results.quote = [quotes.query.results.quote];
  17.       }
  18.       // Resolve the promise with the data
  19.       defer.resolve(quotes.query.results.quote);
  20.     }).error(function(error) {
  21.       // If an error occurs, reject the promise with the error
  22.       defer.reject(error);
  23.     });
  24.     // Return the promise
  25.     return defer.promise;
  26.   };

  27.   return QuotesService;
  28. });
                                                              Ok, now it is time to create the quotes state, which leverages these two services.
                                                              (continue)

                                                              If you found this post interesting, follow and support us.
                                                              Suggest for you:

                                                              Android Application Programming - Build 20+ Android Apps

                                                              The Complete Android Developer Course: Beginner To Advanced!

                                                              Android: From Beginner to Paid Professional

                                                              The Complete Android Developer Course - Build 14 Apps

                                                              Python For Android Hacking Crash Course: Trojan Perspective

                                                              No comments:

                                                              Post a Comment