Tuesday, August 16, 2016

The Definitive Ionic Starter Guide_part 2 (end)


Add the quotes state

It's time to jump into high gear. The quotes tab is able to display a list of stocks that you wish to follow, show details about the current bids, allow you to lookup new quotes and add them, and even sort the list. This is an awful lot of functionality, but only requires about 30 lines of HTML and about 70 lines of JavaScript.
You'll first add all of the code for this state, and then we'll review how each part works individually. Create a new file at www/views/quotes/quotes.html and add the following markup.
  1. <ion-view view-title="Market Quotes">
  2.   <!-- Add a nav button to the primary location -->
  3.   <ion-nav-buttons side="primary">
  4.     <button class="button button-clear" ng-click="state.reorder = !state.reorder">Reorder</button>
  5.   </ion-nav-buttons>
  6.   <!-- ionContent is used to wrap scrollable content -->
  7.   <ion-content>
  8.     <!-- ionRefresher activates when the user pulls down and calls getQuotes() -->
  9.     <ion-refresher on-refresh="getQuotes()"></ion-refresher>
  10.     <!-- ionList allows us to make a complex list with swipe buttons, reordering, and more -->
  11.     <ion-list show-reorder="state.reorder">
  12.       <!-- Repeat over each quote, to display the current details and name -->
  13.       <ion-item ng-repeat="stock in quotes" class="item-dark">
  14.         <div class="quote" ng-class="quoteClass(stock)">
  15.           <div class="quote-price">{{stock.LastTradePriceOnly | currency:'$'}}</div>
  16.           <div class="quote-change">{{stock.Change}}</div>
  17.         </div>
  18.         {{stock.symbol}}
  19.         <!-- Option and reorder button for list items -->
  20.         <ion-option-button class="button-assertive" ng-click="remove($index)">Remove</ion-option-button>
  21.         <ion-reorder-button class="ion-navicon" on-reorder="reorder(stock, $fromIndex, $toIndex)">
  22.       </ion-item>
  23.     </ion-list>
  24.   </ion-content>
  25.   <!-- Footer sits above the tabs and sticks -->
  26.   <ion-footer-bar class="bar-search">
  27.     <!-- Form to input a quote to add to the list -->
  28.     <form ng-submit="add()" class="list">
  29.       <div class="item item-input-inset">
  30.           <label class="item-input-wrapper">
  31.             <input type="search" placeholder="Symbol" ng-model="form.query">
  32.           </label>
  33.           <input type="submit" class="button button-small button-positive" value="Add" />
  34.       </div>
  35.     </form>
  36.   </ion-footer-bar>
  37. </ion-view>
Now create another file at www/views/quotes/quotes.js and add the following JavaScript. Also be sure to add the script tag to this file in the www/index.html file.
  1. angular.module('App')

  2. .config(function($stateProvider) {
  3.   // Declare the state for the quotes, with the template and controller
  4.   $stateProvider
  5.     .state('tabs.quotes', {
  6.       url: '/quotes',
  7.       views: {
  8.         quotes: {
  9.           controller: 'QuotesController',
  10.           templateUrl: 'views/quotes/quotes.html'
  11.         }
  12.       }
  13.     });
  14. })

  15. .controller('QuotesController', function($scope, $ionicPopup, $ionicLoading, LocalStorageService, QuotesService) {

  16.   // Get symbols from localstorage, set default values
  17.   $scope.symbols = LocalStorageService.get('quotes', ['YHOO', 'AAPL', 'GOOG', 'MSFT', 'FB', 'TWTR']);
  18.   $scope.form = {
  19.     query: ''
  20.   };
  21.   $scope.state = {
  22.     reorder: false
  23.   };
  24.   // Function to update the symbols in localstorage
  25.   function updateSymbols() {
  26.     var symbols = [];
  27.     angular.forEach($scope.quotes, function(stock) {
  28.       symbols.push(stock.Symbol);
  29.     });
  30.     $scope.symbols = symbols;
  31.     LocalStorageService.update('quotes', symbols);
  32.   }
  33.   // Method to handle reordering of items in the list
  34.   $scope.reorder = function(stock, $fromIndex, $toIndex) {
  35.     $scope.quotes.splice($fromIndex, 1);
  36.     $scope.quotes.splice($toIndex, 0, stock);
  37.     updateSymbols();
  38.   };
  39.   // Method to load quotes, or show an alert on error, and finally close the loader
  40.   $scope.getQuotes = function() {
  41.     QuotesService.get($scope.symbols).then(function(quotes) {
  42.       $scope.quotes = quotes;
  43.     }, function(error) {
  44.       $ionicPopup.alert({
  45.         template: 'Could not load quotes right now. Please try again later.'
  46.       });
  47.     }).finally(function() {
  48.       $ionicLoading.hide();
  49.       $scope.$broadcast('scroll.refreshComplete');
  50.     });
  51.   };
  52.   // Method to load a quote's data and add it to the list, or show alert for not found
  53.   $scope.add = function() {
  54.     if ($scope.form.query) {
  55.       QuotesService.get([$scope.form.query]).then(function(results) {
  56.         if (results[0].Name) {
  57.           $scope.symbols.push($scope.form.query);
  58.           $scope.quotes.push(results[0]);
  59.           $scope.form.query = '';
  60.           updateSymbols();
  61.         } else {
  62.           $ionicPopup.alert({
  63.             title: 'Could not locate symbol.'
  64.           });
  65.         }
  66.       });
  67.     }
  68.   };
  69.   // Method to remove a quote from the list
  70.   $scope.remove = function($index) {
  71.     $scope.symbols.splice($index, 1);
  72.     $scope.quotes.splice($index, 1);
  73.     updateSymbols();
  74.   };
  75.   // Method to give a class based on the quote price vs closing
  76.   $scope.quoteClass = function(quote) {
  77.     if (quote.PreviousClose < quote.LastTradePriceOnly) {
  78.       return 'positive';
  79.     }
  80.     if (quote.PreviousClose > quote.LastTradePriceOnly) {
  81.       return 'negative';
  82.     }
  83.     return '';
  84.   };
  85.   // Start by showing the loader the first time, and request the quotes
  86.   $ionicLoading.show();
  87.   $scope.getQuotes();

  88. });
At this point, if ionic serve is still running your app should be loaded in the browser. Go to http://localhost:8100/#/tabs/quotes and this new view will appear with the list of current stock quotes.

If you look at the controller, you will see that there are a number of methods that you might see in any Angular app, such as the quoteClass() method which determines if the quote box should be green or red or getQuotes() which handles the loading of data. Several methods will be called by Ionic components, such as reorder() and remove() by the Ionic List component.

Now let's take a look at the Ionic components and services that make this view work.
Ionic View, Nav Buttons, and Content Components

The foundation of our view is the ionView component, which is used to wrap a template. The view-title attribute allows the view to set the title in the ionNavBar, and other attributes are available to control other aspects of the navbar (such as if the view should be cached or if it should show the back button). Every view will have the ionView component wrapping the rest of the content.

Inside of theionView is the ionNavButtons component. This will add buttons to the navbar when this view is active, and you are able to declare which side they appear. In this example, it uses side="primary" which allows the buttons to be placed on the primary location for buttons based on the platform. In iOS that is on the left, and for Android that is right, and demonstrates how Ionic has many features that are 'platform aware'. This button uses the ngClick directive to run an expression, which will be covered in the list component.

Then you see the ionContent component. Think of this as the content wrapper, and it has a number of benefits.
  • It sizes the content area to the available space.
  • It automatically ensures content will scroll vertically if it is taller than the viewport.
  • It is aware of other components, such as the navbar, tabs, and footer, and will resize to allow room for those components.
  • It allows the Ionic Refresher component to work seemlessly with your content.
  • It is very configurable, and allows you to set values for features such as padding, scrolling direction, scroll locking.
You will use ionContent to wrap your content in most of your views, and most of the time with only the default settings.
These several components work together to provide the primary container structure for our view, and you'll see them again in the next view since they are quite common.

Ionic Loading Service

The Ionic Loading service overlays the screen with a configurable loading message until the content has loaded, so it prevents the user from interacting with the view until its ready. From a usability perspective, this should be reserved for when the interface can only work once data has loaded. In this example, it only will appear the first time the app has to load the data.

When the controller is first loaded, the $ionicLoading.show() method is called. This triggers the loading indicator to appear, and it will remain until the $ionicLoading.hide() method is called. Right after the show() method, the controller calls $scope.getQuotes() which handles loading the data. You can see the hide() is called in the finally() promise callback to hide the loader after the data request has finished.

You might think the loader could auto hide when the data has loaded, but the loader requires you to call the hide() method because it cannot know exactly when everything is ready for the view. The loader is also like a singleton, meaning there is only ever one loader on the screen. If you call show() multiple times, it will still only take one call to hide() to hide it.

Ionic Refresher Component

The Ionic Refresher is a component you put inside of a view that allows the user to pull down to refresh the view. As the user pulls down, an icon slides down and if they pull far enough and let go it triggers the refresh. You've likely seen this in many apps that allow you to reload the data, such as an app showing sports scores or (like this example) stock quotes. It is a common pattern that uses the pull down gesture instead of a button.

The component is just a directive called ionRefresher, and has a single attribute on-refresh that accepts an expression to evaluate when the user releases the pull. In this case, it calls the getQuotes() method, which reloads the data and update the view. Similarly to the Loading service, we use the finally() callback to broadcast an event $scope.$broadcast('scroll.refreshComplete');; that will tell the Refresher the reload is complete and to hide itself.

The primary key to making the Refresher component work is to ensure that you have a single scope method that (re)loads the data in the view. Since the Refresher is a component and not a service (like the Loader), it listens for the scroll.refreshComplete event to know when to hide. If you forget to call this, the Refresher will display forever.

Ionic Popup Service

The Ionic Popup service is used to display an overlay for the user to acknowledge or interact with. It will block the current view and overlay a box with a message and button. There are several built in types of popups and you can also build your own.
  • Alert: Shows a simple message and button to clear. Useful to inform users of something such as an error.
  • Confirm: Shows a simple message and two buttons to either confirm or cancel. Useful to confirm an action such as deleting an item.
  • Prompt: Shows a simple message, an input field, and an OK and Cancel button. Useful when you need additional details, such as a password.
The Popup service is $ionicPopup and when you create one of the types of a popup it is returned as a promise. When you create a new popup, it will appear and you use the promise API to handle the callback when a button is selected. It is also possible to programmatically close the popup using the close() method.

In this view, the Popup service is used to help alert to errors in loading data. In the getQuotes() method, if the request promise is resolved with an error it will alert that it could not load the quotes. Likewise, when the user tries to add a quote that doesn't exist, it will alert that the symbol was not found. In this example you are not waiting for the popup promise to be resolved (with the alert is closed), it simply just closes and allows the user to continue using the app.

Popups can be easily abused from a usability standpoint. Much like an alert/confirm window you see in JavaScript, it blocks the interface and requires the user to interact to continue. Using Popups should be limited to situations when the user needs to acknowledge or respond to the Popup to continue. You could argue that this example could use a different method to give feedback to the user.

Ionic List Component

The Ionic List component is a powerful user interface component, which is really a combination of several different directives that work together. Lists are a very common and clean way to display content, as mobile content has limited space. Android and iOS have introduced many features to lists that users have become accustomed to using, such as the ability to reorder items, swiping to show additional buttons, and deleting items. So much of the data shown in apps are really just lists, such as lists of news articles, emails, locations visited, and more.

In this app, the List component supports reordering and deleting of items. The ionList component is used to wrap the ionItem components. The ionItem have an ngRepeat so it will display the entire list of quotes that are stored (or the default list from the localStorage service). Then, each ionItem displays the quote and price.

The ionList has several attributes that control when the list is in a 'reorder' mode, which is a boolean that is evaluated. The ionItem contains an ionReorderButton to power this feature. When the state.reorder model is true, the reorder button (which is a stacked three lines icon) will slide into view and allow you to tap and drag the list items. When the item is released, it will call the reorder() method that was declared by the on-reorder attribute. It passes three items, the item, the index value of the item originally, and the new index after it was released. The reorder() method takes these values and moves the item in the $scope.quotes array.

The last feature is the ionOptionButton, which is a button that appears when the user swipes left on an item. This option button is designed to act like a delete button, so if the user taps on the button it will call the remove() method to remove that item from the list. You could make buttons for other purposes, such as to edit or share an item.

Ionic Lists are quite powerful, and very intuitive for users to manage lists. They are used so often, I would even suggest you can't use it too often. Anything that is a collection of items is probably ideal for a list. Ionic Lists can also be styled in many ways with default Ionic CSS classes, found in the documentation. Some common styles include lists with an avatar or icon to the side, large images like cover art, or cards style that modifies the entire list to have a similar card feel like you see in Google Now or Tinder style apps.

Ionic Footer Bar and Form

The Ionic Footer Bar is a way to display text or simple content at the bottom of the view. It automatically positions based on the other components, was discussed earlier with ionContent. It does need to be outside of the ionContent to position correctly, just like the ionNavButtons.

The Footer Bar in this app also has a simple form, which has some Ionic styling (plus a little extra custom styling in the Sass file). Form styles are not fully designed to work in the Footer Bar, but it only took a few lines of styling to clean it up. This form is just a simple search input and button, and on submit the form will call the add() method to attempt to lookup and add a stock symbol to the current list.

Add the portfolio state

The last major step for your app will be to add another view to keep track of your portfolio. The idea is you can specify how many stocks you purchased at a given price, and see a current rate of return or loss for that purchase. This whole state has about 60 lines of markup and 100 lines of JavaScript.

Create a new file at www/views/portfolio/portfolio.html and add the contents below.
  1. <ion-view view-title="My Portfolio">
  2.   <!-- Add buttons to both primary and secondary sides of the navbar -->
  3.   <ion-nav-buttons side="primary">
  4.     <button class="button button-clear" ng-click="openModal()">Add</button>
  5.   </ion-nav-buttons>
  6.   <ion-nav-buttons side="secondary">
  7.     <button class="button button-clear" ng-click="state.remove = !state.remove">Edit</button>
  8.   </ion-nav-buttons>
  9.   <ion-content>
  10.     <!-- Use a list to display the list of stocks in portfolio -->
  11.     <ion-list show-delete="state.remove">
  12.       <!-- Repeat over each stock in the portfolio and display relevant data -->
  13.       <ion-item ng-repeat="stock in portfolio" class="item-dark item-text-wrap">
  14.         {{stock.symbol}} ({{stock.quantity}} @ {{stock.price | currency}})
  15.         <div class="quote" ng-class="quoteClass(stock)" ng-if="quotes[stock.symbol]">
  16.           <!-- These bindings calculate the current value and gain/loss of the stock -->
  17.           <div class="quote-price">{{getCurrentValue(stock) | currency:'$'}}</div>
  18.           <div class="quote-change">{{getChange(stock) | currency}}</div>
  19.         </div>
  20.         <!-- Use an ionSpinner to display while the stock price is loaded -->
  21.         <div class="quote" ng-if="!quotes[stock.symbol]">
  22.           <ion-spinner icon="lines"></ion-spinner>
  23.         </div>
  24.         <!-- Delete button allows the item to be removed -->
  25.         <ion-delete-button class="ion-minus-circled" ng-click="remove($index)"></ion-delete-button>
  26.       </ion-item>
  27.     </ion-list>
  28.   </ion-content>
  29. </ion-view>
Create another file at www/views/portfolio/add-modal.html and add the following markup.
  1. <!-- Modals require a special ionModalView wrapper -->
  2. <ion-modal-view>
  3.   <!-- Use Angular form to have automatic validation -->
  4.   <form name="addQuote">
  5.     <!-- Add an ionHeaderBar with buttons and title -->
  6.     <ion-header-bar class="bar-balanced">
  7.       <button class="button button-clear" ng-click="closeModal()">Cancel</button>
  8.       <h1 class="title">Add Stock</h1>
  9.       <button class="button button-clear" ng-click="addStock(item)" ng-disabled="addQuote.$invalid">Save</button>
  10.     </ion-header-bar>
  11.     <ion-content>
  12.       <!-- Use Ionic's CSS list and form classes to format forms -->
  13.       <div class="list">
  14.         <label class="item item-input">
  15.           <span class="input-label">Symbol</span>
  16.           <input type="text" autocorrect="off" autocapitalize="off" ng-model="item.symbol" required />
  17.         </label>
  18.         <label class="item item-input">
  19.           <span class="input-label">Quantity</span>
  20.           <input type="number" autocorrect="off" autocapitalize="off" ng-model="item.quantity" required />
  21.         </label>
  22.         <label class="item item-input">
  23.           <span class="input-label">Price</span>
  24.           <input type="number" autocorrect="off" autocapitalize="off" ng-model="item.price" required />
  25.         </label>
  26.       </div>
  27.     </ion-content>
  28.   </form>
  29. </ion-modal-view>
Lastly, create a file at www/views/portfolio/portfolio.js and include the code below. Also be sure to create a new script tag to load this into the app in www/index.html.
  1. angular.module('App')

  2. .config(function($stateProvider) {
  3.   // Declare the state for the portfolio, with the template and controller
  4.   $stateProvider
  5.     .state('tabs.portfolio', {
  6.       url: '/portfolio',
  7.       views: {
  8.         portfolio: {
  9.           controller: 'PortfolioController',
  10.           templateUrl: 'views/portfolio/portfolio.html'
  11.         }
  12.       }
  13.     });
  14. })

  15. .controller('PortfolioController', function($scope, $ionicModal, $ionicPopup, LocalStorageService, QuotesService) {
  16.   // Create the portfolio model from localstorage, and other models
  17.   $scope.portfolio = LocalStorageService.get('portfolio', []);
  18.   $scope.item = {};
  19.   $scope.state = {
  20.     remove: false
  21.   };
  22.   // Private method to update the portfolio
  23.   function updatePortfolio() {
  24.     LocalStorageService.update('portfolio', $scope.portfolio);
  25.   }
  26.   // Method to get the latest quotes
  27.   $scope.getQuotes = function() {
  28.     var symbols = [];
  29.     angular.forEach($scope.portfolio, function(stock) {
  30.       if (symbols.indexOf(stock.symbol) < 0) {
  31.         symbols.push(stock.symbol);
  32.       }
  33.     });

  34.     if (symbols.length) {
  35.       QuotesService.get(symbols).then(function(quotes) {
  36.         var items = {};
  37.         angular.forEach(quotes, function(quote) {
  38.           items[quote.Symbol] = quote;
  39.         });
  40.         $scope.quotes = items;
  41.       });
  42.     }
  43.   };
  44.   // Method to calculate the current value of the stocks
  45.   $scope.getCurrentValue = function(stock) {
  46.     return parseFloat($scope.quotes[stock.symbol].LastTradePriceOnly) * stock.quantity;
  47.   };
  48.   // Method to calculate the change in value
  49.   $scope.getChange = function(stock) {
  50.     return $scope.getCurrentValue(stock) - stock.price * stock.quantity;
  51.   };
  52.   // Method to determine if the stock has positive or negative return for background color
  53.   $scope.quoteClass = function(stock) {
  54.     if (!stock) {
  55.       return '';
  56.     }
  57.     var className = '';
  58.     var currentValue = $scope.getCurrentValue(stock);
  59.     if (currentValue && currentValue > stock.price) {
  60.       className = 'positive';
  61.     } else if (currentValue && currentValue < stock.price) {
  62.       className = 'negative';
  63.     }

  64.     return className;
  65.   }
  66.   // Create an Ionic modal instance for adding a new stock
  67.   $ionicModal.fromTemplateUrl('views/portfolio/add-modal.html', {
  68.     scope: $scope
  69.   }).then(function(modal) {
  70.     $scope.modal = modal;
  71.   });
  72.   // Open the modal
  73.   $scope.openModal = function() {
  74.     $scope.modal.show();
  75.   };
  76.   // Close the modal and reset the model
  77.   $scope.closeModal = function() {
  78.     $scope.item = {};
  79.     $scope.modal.hide();
  80.   };
  81.   // Ensure the modal is completely destroyed after the scope is destroyed
  82.   $scope.$on('$destroy', function() {
  83.     $scope.modal.remove();
  84.   });
  85.   // Method to add a new stock purchase
  86.   $scope.addStock = function(item) {
  87.     $scope.state.remove = false;
  88.     QuotesService.get([item.symbol]).then(function(quote) {
  89.       if (quote[0].Name) {
  90.         item.symbol = item.symbol.toUpperCase();
  91.         $scope.portfolio.push(item);
  92.         updatePortfolio();
  93.         $scope.closeModal();
  94.         $scope.getQuotes();
  95.       } else {
  96.         $ionicPopup.alert({
  97.           title: 'Could not find symbol.'
  98.         });
  99.       }
  100.     });
  101.   };
  102.   // Method to remove an item from the portfolio
  103.   $scope.remove = function($index) {
  104.     $scope.portfolio.splice($index, 1);
  105.     updatePortfolio();
  106.   };
  107.   // Get the quotes on load
  108.   $scope.getQuotes();

  109. });
Once all of these changes are made, ensure ionic serve is still running and go to http://localhost:8100/#/tabs/portfolio to see this new tab. You could also tap on the Portfolio icon in the tabs to navigate.

There are a few features of Ionic used here again, such as the Ionic Popup. However, in addition there are some new features such as the Ionic Modal, Ionic Header Bar, Ionic Spinner, and another feature for the Ionic List component.

Ionic Modal Service

The Ionic Modal service is a way to overlay an entire view on the app, and can typically be thought of as a temporary state. They are used to provide related, contextual content without cluttering the original view. In traditional desktop websites, modals have gotten a bad rap from usability professionals, but in a mobile context they are often more functional and user friendly. A modal is a completely new view, so it can contain anything from a form, to a scrolling list of content, to a video.

In this example, the $ionicModal service creates a modal based on a loaded template, which points to the www/views/portfolio/add-modal.html file (you can also use fromTemplate() instead to pass a template as a string, but I don't recommend it). The modal is created and loaded when the controller first executes, but it does not immediately open. Here is the section that creates a new modal.
  1. $ionicModal.fromTemplateUrl('views/portfolio/add-modal.html', {
  2.   scope: $scope
  3. }).then(function(modal) {
  4.   $scope.modal = modal;
  5. });
The $ionicModal service generates the modal, which is very similar to registering a new state except in this case the modal is not part of the app routing. You also pass an object with some configuration, and in this case you have {scope: $scope} which will use the current state's scope as the modal's scope. Creating a modal from a template returns a promise, and when it resolves the loading of the template it returns a modal instance which can be used to control the modal (such as open and close).

The app then has an openModal() and closeModal() which handle the opening and closing of the modal. The portfolio view contains a navbar button with ngClick that calls openModal(), and inside of the modal view there is a cancel button that calls closeModal(). If a user submits the form to add a stock quote, if the stock is found it will also call the closeModal() method to hide the modal and return to the portfolio.
Ionic Modals also require that you also add a listener for the scope destroy event, so you can manually remove the modal as well. Since modals are created manually and not registered with the state provider, Ionic doesn't know when they are safe to be deleted from memory. This is easy to do, as you see here.
  1. $scope.$on('$destroy', function() {
  2.   $scope.modal.remove();
  3. });
I find the Ionic Modal to be a very useful tool given the size of most mobile devices. Instead of trying to show lots of content on one long scrolling screen, the modals are able to provide one way to break that content up and show it only when it is relevant to the user action. If the add form was in the portfolio view instead of a modal, it would clutter the view, so the modal provides a better experience to only show it when the user is about to add a new item. They do take some design consideration since the modal will show until it is dismissed. It is also not possible to directly navigate to a modal (at least not without some additional custom logic to handle this), so anything that a user might directly navigate to is probably not a candidate for a modal.

Ionic Header Bar Component

The Ionic Header Bar is essentially the same as the Footer Bar, except it sits in the header as you might expect. There are several different color presets that can be used as CSS classes, and in this case it uses the bar-balanced class, which is modified from the default by the app Sass stylings. Since the modal is a blank slate that overlays the app, the navbar does not appear and requires you to add a Header Bar to place buttons along the top.

Ionic Spinner Component

The Ionic Spinner is a helpful component to display an animated SVG to indicate your app is doing something that the user has to wait for to complete. With animated SVG the indicators are be more flexible than with just rotating an icon with CSS. These spinners (which not all spin, so it is a bit of a misnomer) are possible to style and Ionic comes with 10 different animations.
In this app, the lines animation is used in place of the quote price while the quotes are loaded. The ngIf controls when to show the spinner.

Ionic List Component Continued

The Ionic List component also has a delete mode, which is similar to the reorder mode you saw in the quotes state but instead of moving items it will delete them. You can use both delete and reorder modes on the same list, depending on your app design and needs. The delete mode slides an icon from the left to allow users to quickly delete items.

To toggle the delete mode, the ionList has a show-delete attribute that should be true or false to toggle the delete mode. Then each of the ionItem components have an ionDeleteButton component, which have an icon declared and use an ngClick to call the remove() method in the controller.

Finishing touches

There is one last thing that our app needs, a default route. Right now if you go to http://localhost:8100/ it will not load the tabs and content. This is an easy remedy, but needed to be implemented after the states were added. The following snippet should be placed into your www/js/app.js file, and it uses the $urlRouterProvider.otherwise() method to define where the app should go when it can't find a route (in this case the default / route is not registered).
  1. angular.module('App', ['ionic'])

  2. .config(function($urlRouterProvider) {
  3.   $urlRouterProvider.otherwise('/tabs/quotes');
  4. })
Now when you go to the app without any path in the URL, it will load up the quotes view by default for you. Congratulations, you now have a fairly feature rich mobile app, with around 120 lines of HTML and 200 lines of JavaScript! Who knew you could build so many features so easily?

Digging deeper into Ionic

We've flown through the example app, and learned a lot about how Ionic components work together to create a beautiful and functional mobile app using just HTML, CSS, and JavaScript. You've seen how to use many components and services such as Ionic Lists, Popups, Modals, Navigation, Content, Refresher, and others. This foundation should be great for you to build from to learn the rest of the components and dive deeper into other ways they can be leveraged.

The Ionic documentation is really good and the best place to look up detailed information about how components and services work. It also provides some primers on how to get your environment setup to build and deploy the app to an emulator or to a real device. For that, you will be using Cordova and will want to spend some time understanding how it works. You can also spend time on the Ionic Forum to find answers or ask your own questions.
Written by Jeremy Wilken

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

Ionic 2 Tutorial with Two Complete Apps

Ionic by Example: Create Mobile Apps in HTML5

Build an Ebay Classified Clone using Stamplay and Ionic

The Complete Android & Java Course - Build 21 Android Apps

Android Application Programming - Build 20+ Android Apps



No comments:

Post a Comment