{"id":2748,"date":"2016-07-14T19:33:15","date_gmt":"2016-07-14T19:33:15","guid":{"rendered":"http:\/\/www.nikola-breznjak.com\/blog\/?p=2748"},"modified":"2016-07-14T19:55:35","modified_gmt":"2016-07-14T19:55:35","slug":"build-ionic-app-searching-gifs-using-giphy-api","status":"publish","type":"post","link":"https:\/\/nikola-breznjak.com\/blog\/codeproject\/build-ionic-app-searching-gifs-using-giphy-api\/","title":{"rendered":"Build an Ionic app for searching gifs using Giphy API"},"content":{"rendered":"<p>Last week I held the first Ionic framework meetup in \u010cakovec. Hereby I would like to thank Goran Leva\u010di\u0107, the leader of incubation and education in <a href=\"http:\/\/ticm.hr\/\">TICM<\/a>, for securing us the place for this meetup.<\/p>\n<p>In case you&#8217;re interested about next events, be sure to check out the <a href=\"http:\/\/www.meetup.com\/Ionic-Cakovec\/\">meetup page<\/a> and join the discussion there.<\/p>\n<h2>What was it about?<\/h2>\n<p>First, we&#8217;ve shown how to set up the Ionic framework environment for those who didn&#8217;t yet have it and then we went through a typical application step by step.<\/p>\n<p>You can see the reactions from the first meetup <a href=\"http:\/\/www.meetup.com\/Ionic-Cakovec\/events\/231961699\/\">here<\/a>, and some pictures are below. Also, TICM made a blog post about it on <a href=\"http:\/\/ticm.hr\/ionic-framework-meetup\/\">their site<\/a> so check it out if you want (attention: only Croatian version).<\/p>\n<p><img decoding=\"async\" class=\"ngg_displayed_gallery mceItem\" src=\"http:\/\/www.nikola-breznjak.com\/blog\/nextgen-attach_to_post\/preview\/id--2740\" data-mce-placeholder=\"1\" \/><\/p>\n<h2>Demo app<\/h2>\n<p>We made a simple application for searching (and showing) gifs from the <a href=\"http:\/\/giphy.com\/\">Giphy<\/a> website by using <a href=\"https:\/\/github.com\/Giphy\/GiphyAPI\">their API<\/a>. Most apps fall into this category today; you have a service &#8216;somewhere&#8217;, and you call it within your app and show its data. Following the same principle, you could make an app for Youtube, IMDB, etc&#8230;<\/p>\n<p>The source code for the app is on <a href=\"https:\/\/github.com\/Hitman666\/GiphySearch\">Github<\/a>, and you can <a href=\"http:\/\/hitman666.github.io\/giphy-search-ionic\/\">try it live<\/a> as well.<\/p>\n<blockquote><p>\n  Those of you who are already very familiar with Ionic may find the following pace too slow. If so, you can just take a look at the <a href=\"https:\/\/github.com\/Hitman666\/GiphySearch\">source code<\/a>.\n<\/p><\/blockquote>\n<h3>Starting the project<\/h3>\n<p>First, let&#8217;s start a new Ionic project with the following command (executed from your terminal):<\/p>\n<p><code>ionic start giphyApp<\/code><\/p>\n<p>When the command finishes, enter the new directory:<\/p>\n<p><code>cd giphyApp<\/code><\/p>\n<p>Just for testing purposes, let&#8217;s run the app to see if everything is OK:<\/p>\n<p><code>ionic serve --lab<\/code><\/p>\n<p>You should see something like this:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/nJ8gme0l.png\" alt=\"\" \/><\/p>\n<p>The <code>--lab<\/code> switch will give you a nice side by side view of how the app would look like on iOS and Android device.<\/p>\n<h3>Folder structure<\/h3>\n<p>Now, open up this folder in your editor and you should see something like this (I&#8217;m using Sublime Text 3):<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/p2Y057cl.png\" alt=\"\" \/><\/p>\n<p>When developing Ionic applications, you&#8217;ll be spending most of the time in the <code>www<\/code> folder.<\/p>\n<p>Just a quick TL;DR of other folders and files that we have:<\/p>\n<ul>\n<li><strong>hooks<\/strong> &#8211; contains so-called Cordova hooks, which execute some code when Cordova is building your project. From my experience, I didn&#8217;t have to set this up yet<\/li>\n<li><strong>platforms<\/strong> &#8211; contains the platform specific files upon building the project<\/li>\n<li><strong>plugins<\/strong> &#8211; contains Cordova plugins which have been added (or will be) to the project<\/li>\n<li><strong>scss<\/strong> &#8211; contains SASS files<\/li>\n<li><a href=\"https:\/\/bower.io\/\">Bower<\/a> is a front-end package manager that allows you to search, install and update your front-end libraries. You can learn more in this <a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/how-to-manage-front-end-javascript-and-css-dependencies-with-bower-on-ubuntu-14-04\">comprehensive tutorial<\/a>. Bower saves downloaded modules defined in the <code>.bowerrc<\/code> file<\/li>\n<li><strong>config.xml<\/strong> &#8211; Cordova configuration file<\/li>\n<li><strong>gulpfile.js<\/strong> &#8211; <a href=\"\">Gulp<\/a> configuration file. You can learn more in this <a href=\"https:\/\/github.com\/gulpjs\/gulp\/blob\/master\/docs\/getting-started.md\">getting started tutorial<\/a>, but shortly; Gulp is a so-called JavaScript task runner which helps with tasks like minification, uglification, running unit tests, etc.<\/li>\n<li><strong>ionic.project<\/strong> &#8211; <a href=\"http:\/\/ionic.io\/\">Ionic.io<\/a> configuration file<\/li>\n<li><strong>package.json<\/strong> &#8211; contains the information about Node.js packages that are required in this project<\/li>\n<li><strong>.gitignore<\/strong> &#8211; defines which files are to be ignored when pushing to <a href=\"https:\/\/github.com\/\">Github<\/a><\/li>\n<li><strong>README.md<\/strong> &#8211; projet information document written in <a href=\"https:\/\/daringfireball.net\/projects\/markdown\/\">Markdown<\/a> that automatically shows as a landing page on your Github project<\/li>\n<\/ul>\n<h3>Let&#8217;s start writing some code<\/h3>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/PxpH624.jpg\" alt=\"\" \/><\/p>\n<p>OK Batman, enough with the theory, let&#8217;s write some code!<\/p>\n<p>First, let&#8217;s try to change some text on the first tab.<\/p>\n<p>Sure, but, how should we know in which file is that first tab defined?<\/p>\n<p>Well, as with every app, let&#8217;s start searching in the <code>index.html<\/code><\/p>\n<p>The content of that file is shown below for reference:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Hitman666\/59bd724a9926ae46beeb26674a70e26d.js\"><\/script><\/p>\n<p>We see that we have a simple HTML file which in its <code>head<\/code> section has some <code>meta<\/code> tags, then we import some CSS, and finally some <code>js<\/code> files.<\/p>\n<p>In the <code>body<\/code> tag we see that it has a <code>ng-app=\"starter\"<\/code> attribute attached to it, which tells us that in some JavaScript file there is a module named <code>starter<\/code>.<\/p>\n<p>If we take a look at the JavaScript files located in the <code>js<\/code> folder, we will find this <code>starter<\/code> module in the <code>app.js<\/code> file.<\/p>\n<p>Ok, sure, that&#8217;s all nice, but we still don&#8217;t know which file to change!<\/p>\n<p>Well, if we take a look at the <code>templates<\/code> folder (of course, Search functionality of your editor comes handy in situations like this ;)) we&#8217;ll see that the <code>tabs-dash.html<\/code> file contains the text <code>Welcome to Ionic<\/code>.<\/p>\n<p>Now, remove all the code from this file except <code>h2<\/code>, and write something like <code>Welcome to GiphySearch<\/code>. Also, change the text <code>Dashboard<\/code> to <code>GiphySearch<\/code>.<\/p>\n<p>Just for reference, the contents of the <code>tab-dash.html<\/code> file should now be this:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Hitman666\/36de87857f0e161badfd244d3de65023.js\"><\/script><\/p>\n<h3>Tab text<\/h3>\n<p>Currently, you should have a screen that looks like this:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/popb71Zl.png\" alt=\"\" \/><\/p>\n<p>Those tabs don&#8217;t quite represent what we would like to have there, right?<\/p>\n<p>Sure, but where would we change that?<\/p>\n<p>Well, if you open up the <code>templates\/tabs.html<\/code> file you&#8217;ll see where you can make such a change. So, change the <code>title<\/code> to <code>Home<\/code>.<\/p>\n<p>Voila! You now have a tab named <code>Home<\/code>.<\/p>\n<h3>Icons<\/h3>\n<p>However, the icon is a bit &#8216;wrong&#8217; here, don&#8217;t you think?<\/p>\n<p>By looking at the HTML:<\/p>\n<p>&#8220;<\/p>\n<p>we can see some interesting attributes like <code>icon-off<\/code> and <code>icon-on<\/code>.<\/p>\n<p>Yes, this is where you can define how our icons will look like.<\/p>\n<p>Great, but, where do you find the exact class which you would put here?<\/p>\n<p>Enter <a href=\"http:\/\/ionicons.com\/\">Ionic icons<\/a>:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/gdcwCJwl.png\" alt=\"\" \/><\/p>\n<p>Search for any icon you wish by name, click on it, copy the string and place it in your <code>icon-on<\/code> and <code>icon-off<\/code> attributes.<\/p>\n<p>In our case, this is what we will use:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Hitman666\/8ecd052298ac2858b7ff1cf949994ab4.js\"><\/script><\/p>\n<h3>Buttons<\/h3>\n<p>It&#8217;s true that we can just click the tab and move between them, but since we&#8217;re building an <em>enterprise xD<\/em> application here, let&#8217;s add a new button in the <code>tab-dash.html<\/code> file:<\/p>\n<p><code>&lt;a class=\"button button-block button-royal\"&gt;Go to search&lt;\/a&gt;<\/code><\/p>\n<p>In case you&#8217;re wondering where I came up with all those classes, you can view all the various buttons in their (quite good) <a href=\"http:\/\/ionicframework.com\/docs\/components\/#buttons\">documentation<\/a>.<\/p>\n<p>The <code>ui-sref<\/code> is a part of Angular&#8217;s <a href=\"https:\/\/github.com\/angular-ui\/ui-router\">UI Router<\/a>, and it basically sets the link to which this button will take us once clicked.<\/p>\n<p>At this point you should have a screen that looks like this:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/A9OIcXs.png\" alt=\"\" \/><\/p>\n<p>and by clicking the button, you should be shown the second tab called <code>Chats<\/code>.<\/p>\n<h3>Some more tab modifications<\/h3>\n<p>OK, fine, so we click the button, and we&#8217;re shown the <code>Chats<\/code> tab. Big deal. But we don&#8217;t want the Chats tab! We&#8217;re making a <code>Search<\/code> app!<\/p>\n<p>OK, easy on the coffee partner. We&#8217;ll get to this now.<\/p>\n<p>So, armed with the knowledge from before we open the <code>templates\/tab-chats.html<\/code> and remove everything between the <code>ion-content<\/code> tag, and we change the title to <code>Search<\/code>.<\/p>\n<p>We also don&#8217;t like that icon and text on the tab, so let&#8217;s hop in the <code>templates\/tabs.html<\/code> file and change the Chats tab definition to this:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/Hitman666\/cdbd9fbbf2a3f9815c404e1ef89971d7.js\"><\/script><\/p>\n<p>What have we done? We literally changed the <code>Chats<\/code> text to <code>Search<\/code>. But, we also added different classes for the icons (again, using Ionic icons as explained before).<\/p>\n<p>This is fine, but say we&#8217;re meticulous about it, and we don&#8217;t want to have the <code>tab-chats.html<\/code>, but instead we want <code>tab-search.html<\/code>. No problem, just rename the file.<\/p>\n<h3>Route 66<\/h3>\n<p>But, now we have a problem. Our button on the first tab is not working anymore. That&#8217;s because we renamed the file, so we need to set the proper references. We do that in the <code>app.js<\/code> file. Just search the file for this code:<\/p>\n<pre><code>.state('tab.chats', {\nurl: '\/chats',\nviews: {\n'tab-chats': {\ntemplateUrl: 'templates\/tab-chats.html',\ncontroller: 'ChatsCtrl'\n}\n}\n})\n<\/code><\/pre>\n<p>and change it with this:<\/p>\n<pre><code>.state('tab.search', {\nurl: '\/search',\nviews: {\n'tab-search': {\ntemplateUrl: 'templates\/tab-search.html',\ncontroller: 'ChatsCtrl'\n}\n}\n})\n<\/code><\/pre>\n<p>OK, fine Sherlock, this works now if I click on the <code>Search<\/code> tab, but it does not work if I click the button on the first tab!?<\/p>\n<p>Yep, that&#8217;s right, and that&#8217;s because we have the wrong url set there. Set it to this now:<\/p>\n<p><code>&lt;a class=\"button button-block button-royal\"&gt;Go to search&lt;\/a&gt;<\/code><\/p>\n<p>Voila, we now have a working button on the first tab, and we have a nice, empty, ready to be awesome, <code>Search<\/code> page:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/EPe6tfwl.png\" alt=\"\" \/><\/p>\n<h3>Search tab mastery<\/h3>\n<p>So, we now have a blank screen, and at this point, we ask ourselves:<\/p>\n<blockquote><p>\n  Cool, what do we want to have here?\n<\/p><\/blockquote>\n<p>Well, since it&#8217;s a search app, what do you say about an input field? Great. But wait! Before you start typing those <code>input<\/code> tags, let&#8217;s first check out the <a href=\"\">Ionic docs<\/a> and scroll a bit around that <a href=\"http:\/\/ionicframework.com\/docs\/components\/#forms\"><code>Forms<\/code><\/a> section.<\/p>\n<p>I happen to like <a href=\"http:\/\/ionicframework.com\/docs\/components\/#input-icons\">this one<\/a>, so let&#8217;s copy the following code in our <code>tab-search.html<\/code> file (inside the <code>ion-content<\/code> tag):<\/p>\n<p><code>&lt;div class=\"list list-inset\"&gt;&lt;label class=\"item item-input\"&gt;<br \/>\n&lt;i class=\"icon ion-search placeholder-icon\"&gt;&lt;\/i&gt;<br \/>\n&lt;input type=\"text\" placeholder=\"Search\" \/&gt;<br \/>\n&lt;\/label&gt;&lt;\/div&gt;<\/code><\/p>\n<p>OK, we&#8217;re rockin&#8217; things by now, so let&#8217;s add some button as well (inside the div with <code>list<\/code> class):<\/p>\n<p><code>&lt;a class=\"button button-block button-royal\"&gt;Search&lt;\/a&gt;<\/code><\/p>\n<p>For reference, this should be the exact content of your <code>tab-search.html<\/code> now:<\/p>\n<p><code>&lt;div class=\"list list-inset\"&gt;&lt;label class=\"item item-input\"&gt;<br \/>\n&lt;i class=\"icon ion-search placeholder-icon\"&gt;&lt;\/i&gt;<br \/>\n&lt;input type=\"text\" placeholder=\"Search\" \/&gt;<br \/>\n&lt;\/label&gt;&lt;a class=\"button button-block button-royal\"&gt;Search&lt;\/a&gt;<br \/>\n&lt;\/div&gt;<\/code><\/p>\n<p>And this is how it should look like:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/ObT55jEl.png\" alt=\"\" \/><\/p>\n<h3>Search tab action<\/h3>\n<p>This is all nice now, but now we would probably want something to happen when we click this button, right? What about calling some function? Great, let&#8217;s write that now!<\/p>\n<p>On this button add the new attribute <code>ng-click<\/code>, which tells Angular that once this button is clicked call the function that&#8217;s written as the attribute&#8217;s value. Ok, sure, a lot of fluff here, this is how it looks like in the code:<\/p>\n<p><code>&lt;a class=\"button button-block button-royal\"&gt;Search&lt;\/a&gt;<\/code><\/p>\n<p>And, in plain English; once the button is clicked the function <code>performSearch<\/code> will be called.<\/p>\n<p>But, again, if you click the button, nothing happens!? Well, that&#8217;s because there&#8217;s no <code>performSearch<\/code> function defined anywhere. Let&#8217;s do that now.<\/p>\n<p>All the controllers are currently defined in the <code>controllers.js<\/code> file. But, how do you know which controller you have to change? Well, if you take a look at the route definitions in the <code>app.js<\/code> fille you will see remember we changed the <code>search<\/code> tab like this before:<\/p>\n<pre><code>.state('tab.search', {\nurl: '\/search',\nviews: {\n'tab-search': {\ntemplateUrl: 'templates\/tab-search.html',\ncontroller: 'ChatsCtrl'\n}\n}\n})\n<\/code><\/pre>\n<p>So, the answer would be: we need to change the <code>ChatsCtrl<\/code> controller in the <code>controllers.js<\/code> file. However, we&#8217;re meticulous, remember? So, we don&#8217;t want to have <code>ChatsCtrl<\/code>, instead, we want to have <code>SearchCtrl<\/code>. No problem, just change the line in the listing above to:<\/p>\n<p><code>controller: SearchCtrl<\/code><\/p>\n<h3>Controllers<\/h3>\n<p>In the <code>controllers.js<\/code> file remove the <code>ChatsCtrl<\/code> controller code completely, and instead write this:<\/p>\n<pre><code>.controller('SearchCtrl', function($scope) {\nconsole.log(\"Hello from the Search controller\");\n})\n<\/code><\/pre>\n<p>For reference, the contents of the whole <code>controllers.js<\/code> file should now be:<\/p>\n<pre><code>angular.module('starter.controllers', [])\n\n.controller('DashCtrl', function($scope) {})\n\n.controller('SearchCtrl', function($scope) {\nconsole.log(\"Hello from the Search controller\");\n})\n\n.controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {\n$scope.chat = Chats.get($stateParams.chatId);\n})\n\n.controller('AccountCtrl', function($scope) {\n$scope.settings = {\nenableFriends: true\n};\n});\n<\/code><\/pre>\n<p>Now when we load the app and go to the search tab, we will see the following message in the DevTools Console window (<em>this is in the Chrome browser, but I&#8217;m sure you know how to use this in the browser you use, right?<\/em>):<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/lEboDJc.png\" alt=\"\" \/><\/p>\n<h3>Adding the function<\/h3>\n<p>We&#8217;re outputting something to the browsers console, but we still get nothing when we click the button. To fix this add the following code to the <code>SearchCtrl<\/code> controller:<\/p>\n<pre><code>$scope.performSearch = function (){\nconsole.log(\"button click\");\n};\n<\/code><\/pre>\n<p>When you click the button, your browser console should look something like this:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/HPa7FYp.png\" alt=\"\" \/><\/p>\n<p><em>Oh man, you said this would be slow paced, but this is like watching a video at 0.25x speed. Yeah, I love you too \ud83d\ude42<\/em><\/p>\n<p>What would we like to do now when we click the button? Well, it would be logical at this point that we would &#8216;somehow&#8217; output to the console what the user entered in the input box. Here&#8217;s the easiest way to do this:<\/p>\n<p>Enter this code in the <code>SearchCtrl<\/code> controller:<\/p>\n<pre><code>$scope.search = {}\n$scope.search.term = 'cats';\n<\/code><\/pre>\n<p>and now, in the <code>tab-search.html<\/code> file, alter the input to this:<\/p>\n<p><code>&lt;input type=\"text\" placeholder=\"Search\" \/&gt;<\/code><\/p>\n<p>Note that we added<\/p>\n<p><code>ng-model=\"search.term\"<\/code><\/p>\n<p>which basically binds the Angular model to this input. In case you&#8217;re wondering why we haven&#8217;t just used the <code>ng-model=\"search\"<\/code> then you&#8217;re in for a treat with <a href=\"http:\/\/stackoverflow.com\/questions\/14049480\/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs\/14049482#14049482\">this answer<\/a>.<\/p>\n<p>To output the search term to your browser console just adjust the function like this:<\/p>\n<pre><code>$scope.performSearch = function (){\nconsole.log(\"search term: \" + $scope.search.term);\n};\n<\/code><\/pre>\n<p>When you load your app and click the <code>Search<\/code> button (without changing the input value), you should get this:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/2Mb1BIG.png\" alt=\"\" \/><\/p>\n<p>Note how the <code>cats<\/code> text has been automatically populated as the app loaded. That&#8217;s some powerful <a href=\"https:\/\/docs.angularjs.org\/tutorial\/step_04\">two-way<\/a> binding in Angular.<\/p>\n<h2>Giphy API<\/h2>\n<p>Finally, we come to the cool part, and that is to fetch some data from the service and to show it in our app (in our case, we&#8217;ll show images).<\/p>\n<p>So, how do we get this API? Well, if you do a simple <a href=\"https:\/\/www.google.com\/search?q=giphy+api\">google search<\/a> for <code>giphy api<\/code> and open the <a href=\"https:\/\/github.com\/Giphy\/GiphyAPI\">first link<\/a> you&#8217;ll get the documentation for their API.<\/p>\n<p>So, what do we need? Well, we need the search API. If you scroll a bit, you&#8217;ll find the following link:<\/p>\n<p><code>http:\/\/api.giphy.com\/v1\/gifs\/search?q=funny+cat&amp;amp;api_key=dc6zaTOxFJmzC<\/code><\/p>\n<p>Great, now we see what kind of a request we need to create to search Giphy&#8217;s gif database for a certain term.<\/p>\n<p>If you open this link in the browser, you&#8217;ll see what the service returns. Something like:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/skihplVl.png\" alt=\"\" \/><\/p>\n<p>Ok, and now what? So, now we want to fetch this data from within our app. Ok, but how do we do that?<\/p>\n<h2>Angular HTTP requests<\/h2>\n<p>Angular has an <a href=\"https:\/\/docs.angularjs.org\/api\/ng\/service\/$http\">$http service<\/a> for sending HTTP requests to some service API endpoint.<\/p>\n<p>Let&#8217;s jump a bit and change our <code>performSearch<\/code> function to this:<\/p>\n<pre><code>$scope.performSearch = function (){\nvar searchTerm = $scope.search.term.replace(\/ \/g, '+');\n\nconsole.log(\"search term: \" + searchTerm);\n\nvar link = 'http:\/\/api.giphy.com\/v1\/gifs\/search?api_key=dc6zaTOxFJmzC&amp;q=' + searchTerm;\n\n$http.get(link).then(function(result){\nconsole.log(result);\n});\n};\n<\/code><\/pre>\n<p>Line by line explanation of the new code:<\/p>\n<ul>\n<li>added a new <code>searchTerm<\/code> variable, and used the replace function on the <code>$scope.search.term<\/code> variable, with the regex for global matching (the <code>g<\/code> switch) that basically replaces all the spaces with +. We did this in case someone enters &#8216;cats and dogs&#8217;, for example, in our input box.<\/li>\n<li>output this new variable to the console<\/li>\n<li>added a new <code>link<\/code> variable and constructed it so that the search term is properly added to the link.<\/li>\n<li>used the <code>$http<\/code> service to get the data from the URL defined in the <code>link<\/code> variable and printed the result to the console<\/li>\n<\/ul>\n<h3>Dependency injection<\/h3>\n<p>Now, if you try to run the app you&#8217;ll get this in your console log:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/vGtkzde.png\" alt=\"\" \/><\/p>\n<p>So, we see <code>$http is not defined.<\/code><\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/5oLOdtst.jpg\" alt=\"\" \/><\/p>\n<p>In case you&#8217;re familiar with Angular from before, you&#8217;ll immediately know that the problem here is that we&#8217;re using the <code>$http<\/code> service, but we haven&#8217;t <a href=\"https:\/\/docs.angularjs.org\/guide\/di\">dependency injected<\/a> it in our controller. We do that simply by requiring it in the controller definition:<\/p>\n<pre><code>.controller('SearchCtrl', function($scope, $http) {\n<\/code><\/pre>\n<p>In case you&#8217;re not familiar with the Dependency injection concept, you can read a bit about it <a href=\"http:\/\/stackoverflow.com\/questions\/130794\/what-is-dependency-injection\">here<\/a>.<\/p>\n<p>Now, if you run the app and enter something in the search term and click the search button you&#8217;ll see something like this in your console log:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/N2Zs7Ch.png\" alt=\"\" \/><\/p>\n<h3>Saving the results for later use<\/h3>\n<p>Here you can see that we&#8217;re getting back the result object and that in it&#8217;s <code>data<\/code> property there are 25 objects, which hold information about the images that we want to show in our app.<\/p>\n<p>But, how do we show these images in our application?<\/p>\n<p>We see that the api call returns 25 images within the <code>data<\/code> object (which again is inside the <code>data<\/code> object), let&#8217;s save this in some variable for later use:<\/p>\n<p><code>$scope.giphies = [];<\/code><\/p>\n<p>And, let&#8217;s store the 25 objects from the api call to this variable:<\/p>\n<p><code>$scope.giphies = result.data.data;<\/code><\/p>\n<p>Just for reference, to put it all in one listing, the contents of the <code>SearchCtrl<\/code> controller should now be:<\/p>\n<pre><code>.controller('SearchCtrl', function($scope, $http) {\nconsole.log(\"Hello from the Search controller\");\n\n$scope.search = {};\n$scope.search.term = 'cats';\n$scope.giphies = [];\n\n$scope.performSearch = function (){\nvar searchTerm = $scope.search.term.replace(\/ \/g, '+');\n\nconsole.log(\"search term: \" + searchTerm);\n\nvar link = 'http:\/\/api.giphy.com\/v1\/gifs\/search?api_key=dc6zaTOxFJmzC&amp;q=' + searchTerm;\n\n$http.get(link).then(function(result){\n$scope.giphies = result.data.data;\nconsole.log($scope.giphies);\n});\n};\n})\n<\/code><\/pre>\n<h3>Showing the images<\/h3>\n<p>This is all great now, but we don&#8217;t want to be logging out our objects to the console, we want to show them in our app.<\/p>\n<p>After examining the result object for a while, we can conclude that to show the image, we need to position ourselves on the object <code>images<\/code>, then <code>original<\/code>, and finally on the <code>url<\/code> property.<\/p>\n<p>To show one image we can add an <code>img<\/code> tag in the <code>tab-search.html<\/code> file and position ourselves on the first element of the <code>giphies<\/code> array, in the object <code>images<\/code>, then <code>original<\/code>, and finally on the property <code>url<\/code>. Again, this long fluff is way nicer in code:<\/p>\n<p><code>&lt;img ng-src=\"{{giphies[0].images.original.url}}\"&gt;<\/code><\/p>\n<p>And sure, we do a search, and we get one image shown:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/hEwlEHV.gif\" alt=\"\" \/><\/p>\n<p>But, we want all GIFs, not just one!<\/p>\n<p>For that we will use Angular&#8217;s <code>ng-repeat<\/code>:<\/p>\n<p><code>&lt;img ng-repeat=\"g in giphies\" ng-src=\"{{g.images.original.url}}\"&gt;<\/code><\/p>\n<p>And, sure enough, all 25 images are here now. But, we would like to to be, you know, a bit nicer as it&#8217;s not every day that you get to work on an enterprise application like this!<\/p>\n<p>So, what do we do? We go in the <a href=\"http:\/\/ionicframework.com\/docs\/components\/\">Ionic documentation<\/a>, and we search for a bit&#8230; Finally, we settle for the <a href=\"http:\/\/ionicframework.com\/docs\/components\/#card-headers-footers\">Card component<\/a>.<\/p>\n<p>Let&#8217;s copy it&#8217;s code to our <code>tab-search.html<\/code> but without the footer part, and let&#8217;s adjust it a bit by moving our <code>img<\/code> inside it:<\/p>\n<p><code>&lt;div class=\"card\"&gt;<br \/>\n&lt;div class=\"item item-divider\"&gt;{{g.id}}&lt;\/div&gt;<br \/>\n&lt;div class=\"item item-text-wrap\"&gt;&lt;img \/&gt;&lt;\/div&gt;<br \/>\n&lt;\/div&gt;<\/code><\/p>\n<p>By now you&#8217;re a pro at this, but let&#8217;s just note that we moved the <code>ng-repeat<\/code> from the <code>img<\/code> tag to the <code>div<\/code> tag with the <code>card<\/code> class, so that we get this nice Card component repeated for every new GIF. Oh, and the <code>{{g.id}}<\/code> is there so that we write something (the GIFs id in this case).<\/p>\n<h2>Styling<\/h2>\n<p>At this moment we&#8217;re super happy, but the designer in us notices that our images are not quite right. We&#8217;re rocking the design stuff and all that CSS thingies, so we know we just need to add the following CSS rule to the image:<\/p>\n<p><code>width: 100%;<\/code><\/p>\n<h3>SASS<\/h3>\n<p>But, writing plain old CSS is soo 2013 (we&#8217;re in 2016, remember? ;)), and I want to show you how to set up your Ionic to work with SASS.<\/p>\n<p><em>I won&#8217;t go into the details, but TL;DR would be that SASS is CSS on steroids which basically allows you to have functions, variable, mixins, etc&#8230; Learn more <a href=\"http:\/\/sass-lang.com\/\">here<\/a>.<\/em><\/p>\n<p>Go back to the terminal where you have <code>ionic serve --lab<\/code> running from before and break the process (<code>CTRL + C<\/code>). The, execute the following command:<\/p>\n<p><code>ionic setup sass<\/code><\/p>\n<p>And, next step is. Oh, there&#8217;s no next step! All is set up for you! To not go into details; Gulp tasks, proper <code>index.html<\/code> includes, etc&#8230;<\/p>\n<p>Now, you should write your SASS code in the <code>scss<\/code> folder. Let&#8217;s create a new file <code>_custom.scss<\/code> (the underscore is important!) here with the following code:<\/p>\n<pre><code>.card img {\nwidth: 100%;\n}\n\n.centerText {\ntext-align: center;\n}\n<\/code><\/pre>\n<p>And, do not forget to import it by appending this to the <code>ionic.app.scss<\/code> file (contained in the <code>scss<\/code> folder):<\/p>\n<p><code>@import \"custom\";<\/code><\/p>\n<p>Yes, you&#8217;re importing here without the underscore in the name.<\/p>\n<p>If you want to center your text (where we display the id of the GIf), just add the class like this:<\/p>\n<p><code>&lt;div class=\"item item-divider centerText\"&gt;{{g.id}}&lt;\/div&gt;<\/code><\/p>\n<p>Now just run <code>ionic serve --lab<\/code> again and admire you&#8217;re app with nicely positioned title and nicely set up images:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i.imgur.com\/G6N7WQtl.png\" alt=\"\" \/><\/p>\n<h2>Student becomes a master<\/h2>\n<p>Sure enough, you should congratulate yourself now; you have a working app! But, let&#8217;s be honest, putting all that code inside the controller seems a bit dirty, doesn&#8217;t it? Besides, we&#8217;re making an enterprise app here, and we want to have some structure and follow the proper practices, right?<\/p>\n<p>Great, I&#8217;m glad you&#8217;re with me on this.<\/p>\n<p>We&#8217;re going to create a service for fetching these GIFs. Our service (called <code>Giphy<\/code>) will look like this (yes, change the whole prior content of the <code>performSearch<\/code> function with this):<\/p>\n<pre><code>$scope.performSearch = function (){\nGiphy.search($scope.search.term).then(function(result){\n$scope.giphies = result;\n});\n};\n<\/code><\/pre>\n<p>Also, don&#8217;t forget to inject Giphy in the controller:<\/p>\n<p><code>.controller('SearchCtrl', function($scope, $http, Giphy) {<\/code><\/p>\n<h3>Lets&#8217; write a service<\/h3>\n<p>In the file <code>services.js<\/code> remove the <code>Chats<\/code> factory and add this instead:<\/p>\n<pre><code>.factory('Giphy', function($http) {\nreturn {\nsearch: function(term) {\nvar searchTerm = term.replace(\/ \/g, '+');\n\nvar link = 'http:\/\/api.giphy.com\/v1\/gifs\/search?api_key=dc6zaTOxFJmzC&amp;q=' + searchTerm;\n\nreturn $http.get(link).then(function(result) {\nreturn result.data.data;\n});\n}\n};\n});\n<\/code><\/pre>\n<p>Don&#8217;t be scared off by the strange code; it&#8217;s basically a boilerplate code for writing factories\/services. What&#8217;s important here is that we defined a factory named <code>Giphy<\/code> and that we&#8217;re exposing the function <code>search<\/code> which accepts the parameter <code>term<\/code>.<\/p>\n<p>You may notice that we basically copied the whole code from the controller to this factory.<\/p>\n<p>The only difference is that here we&#8217;re returning the result of the <code>$http.get<\/code> call, which basically returns the promise, upon which we can call <code>then<\/code> in the controller. In case you don&#8217;t know, promises work in such a way that once the promise <code>resolves<\/code> (finishes with whatever task it had) it activates the <code>then<\/code> part where we then do something with the data that was returned via this promise.<\/p>\n<p>Also, please note that we injected the <code>$http<\/code> service so that we could use it for our HTTP calls, just as we did in the controller before.<\/p>\n<h3>So what?!<\/h3>\n<p><code>rant<\/code><\/p>\n<blockquote><p>\n  You run the app, and it&#8217;s not faster, it&#8217;s not nicer, it&#8217;s basically the same as half an hour ago, so what gives??<\/p>\n<p>  Well, with this you modularized your code so that now you&#8217;ll be able to use the Giphy service in any other controller, just by injecting it where needed. In case you didn&#8217;t have this, you would have to copy\/paste the code through the controllers.<\/p>\n<p>  This would lead to code duplication, which would then lead to a maintenance nightmare, which again leads to compounded code debt, which in the end leads to a miserable life as a developer.<\/p>\n<p>  And, you don&#8217;t want this for yourself, as you&#8217;re an aspiring developer looking to get better each day. Forgive the cheesy metaphors, but really, these days I&#8217;ve seen too many people give up for smaller reasons than &#8220;I don&#8217;t know how to write a service\/factory&#8221;.<\/p>\n<p>  But, I&#8217;m happy for you! Because making it this far in the tutorial puts you far ahead the pack. Keep learning and growing and you&#8217;ll do just fine in life!\n<\/p><\/blockquote>\n<p><code>\/rant<\/code><\/p>\n<h2>Ionic.io and Ionic view<\/h2>\n<p>You can test the app in the emulator\/simulator; you can test it by running it on your physical device. But also, you can test your app on your mobile phone via the <a href=\"http:\/\/view.ionic.io\/\">Ionic View<\/a> application.<\/p>\n<p>Just download the app for your phone and create an account on <a href=\"http:\/\/ionic.io\/\">Ionic.io<\/a>.<\/p>\n<p>Once you have the account, login via your terminal by executing:<\/p>\n<p><code>ionic login<\/code><\/p>\n<p>and, finally, upload the app to the Ionic.io service with:<\/p>\n<p><code>ionic upload<\/code><\/p>\n<p>Once this is done, you&#8217;ll be able to see your app in the Ionic View app on your phone and you can run it from there.<\/p>\n<h2>Get the code on Github<\/h2>\n<p>This is just a short rundown of the commands that you need to run to get your project to Github:<\/p>\n<ul>\n<li>create a project on Github<\/li>\n<li>Execute <code>git init<\/code> in the root of your project<\/li>\n<li><code>git add .<\/code><\/li>\n<li><code>git commit -m \"my awesome app\"<\/code><\/li>\n<li><code>git remote add origin https:\/\/github.com\/Hitman666\/GiphySearch.git<\/code> &#8211; make sure this is the correct url to <strong>your<\/strong> project on Github<\/li>\n<li><code>git push -u origin master<\/code><\/li>\n<\/ul>\n<h2>Moar learning materials plz!<\/h2>\n<p>In case you&#8217;re interested in learning more, you can download a PDF version of unabridged 4 posts <a href=\"https:\/\/leanpub.com\/ionic-framework\">via Leanpub<\/a>, or you can read the abridged (but still 10000+ words long tutorial <a href=\"http:\/\/www.nikola-breznjak.com\/blog\/javascript\/ionic\/ionic-framework-a-definitive-10000-word-guide\/\">here<\/a>). Yes, you can choose zero as the amount and I promise I won&#8217;t take it against you \ud83d\ude09<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/s3.amazonaws.com\/titlepages.leanpub.com\/ionic-framework\/large?1450181256\" alt=\"\" \/><\/p>\n<h2>Conclusion<\/h2>\n<p>Our goal on these meetups is to &#8216;meet&#8217; each other, learn something new, help each other, and if nothing else to hang out with the people who hold similar interests.<\/p>\n<p>The theme for next meetup will be &#8216;Introduction to Test Driven Development in JavaScript and Ionic&#8217; (those inclined to get ready in advance can read <a href=\"http:\/\/www.nikola-breznjak.com\/blog\/javascript\/ionic\/introduction-tdd-ionic-framework\/\">this post<\/a>). The date is yet to be defined, but somewhere around the end of August.<\/p>\n<p>Ah, and finally, if you want to see how one would build the same exact application with Angular 2, you can check out the tutorial that I wrote for Pluralsight: <a href=\"http:\/\/tutorials.pluralsight.com\/front-end-javascript\/getting-started-with-angular-2-by-building-a-giphy-search-application#jebvOwk193YZZKbZ.99\">Getting started with Angular 2 by building a Giphy search application<\/a>.<\/p>\n<p>See you!<\/p>\n<blockquote class=\"twitter-tweet\" data-width=\"550\">\n<p lang=\"en\" dir=\"ltr\">Build an <a href=\"https:\/\/twitter.com\/hashtag\/Ionic?src=hash\">#Ionic<\/a> app for searching <a href=\"https:\/\/twitter.com\/hashtag\/gifs?src=hash\">#gifs<\/a> using <a href=\"https:\/\/twitter.com\/hashtag\/Giphy?src=hash\">#Giphy<\/a> API <a href=\"https:\/\/t.co\/aBzRBVNeE3\">https:\/\/t.co\/aBzRBVNeE3<\/a><\/p>\n<p>&mdash; Nikola Bre\u017enjak (@HitmanHR) <a href=\"https:\/\/twitter.com\/HitmanHR\/status\/753678720582418432\">July 14, 2016<\/a><\/p><\/blockquote>\n<p><script async src=\"\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week I held the first Ionic framework meetup in \u010cakovec. Hereby I would like to thank Goran Leva\u010di\u0107, the leader of incubation and education in TICM, for&hellip;<\/p>\n","protected":false},"author":1,"featured_media":2751,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,43],"tags":[],"class_list":["post-2748","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codeproject","category-ionic"],"_links":{"self":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/2748","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/comments?post=2748"}],"version-history":[{"count":10,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/2748\/revisions"}],"predecessor-version":[{"id":2761,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/2748\/revisions\/2761"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media\/2751"}],"wp:attachment":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media?parent=2748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/categories?post=2748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/tags?post=2748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}