Construindo Aplicação do Zero com Ionic 1, WordPress, OneSignal e Disqus – Parte 3

Oi pessoal, vamos continuar com a nossa série sobre ionic 1 consumindo api do wordpress hoje criaremos nossos serviços para consumir as categorias do nosso blog, um serviço para buscar mais posts utilizando o scroll infinito do ionic e a ação de ao clicar na categoria, buscar somente as postagens relacionadas a mesma. Para isso estaremos utilizando os endpoints para acessar dados da nossa API e para conhecer melhor vocês podem consultar a documentação do plugin nesse link.

 

Vamos por a mão na massa, primeiro vamos modificar o arquivo posts.service.js, criando um método para pesquisar mais postagens para fazermos uma paginação utilizando o scroll, nosso código ficará assim:

 

 

angular.module('posts.service', [ ])

   .factory('postsService', postsService);



function postsService($http, $q) {

   // interface

   var service = {

       posts: [],

       getPosts: getPosts,

       getPostsPerPage: getPostsPerPage

   };

   return service;



   // implementacao

   function getPosts() {

       var def = $q.defer();

       var url = "http://localhost/appvila/wp-json/posts?filter[posts_per_page]=3&_embed&_jsonp=JSON_CALLBACK";



       $http.jsonp(url)

           .success(function (data) {

               service.posts = data;

               def.resolve(data);

           })

           .error(function () {

               def.reject("Falha ao buscar posts");

           });

       return def.promise;

   }



   function getPostsPerPage(pagina) {

       var def = $q.defer();



       $http.jsonp("http://localhost/appvila/wp-json/posts?filter[posts_per_page]=3&page=" + pagina + "&_embed&_jsonp=JSON_CALLBACK")

           .success(function (data) {

                   service.posts = data;

                   def.resolve(data);

           })

           .error(function () {

               def.reject("Falha ao buscar posts");

           });

       return def.promise;

   }




}

Nesse novo método criado no serviço estaremos passando o número da página que iremos buscar na query da url. Com isso a cada vez que chamamos a função ele irá carregar mais 3 postagens da página seguinte. Nosso serviço agora modificado, podemos abrir posts.controller.js e criar a função que vai estar utilizando o serviço:

 

 

angular.module('posts.controller', [])

   .controller('PostsCtrl', PostsCtrl);



function PostsCtrl(postsService, $ionicLoading, $scope) {

   var vm = this;

   vm.noMore = false;

   //usando nosso service para consultar as postagens



   vm.posts = [];

   vm.getPosts = function () {

       postsService.getPosts()

           .then(

           function (data) {

               for (var i = 0; i < data.length; i++) {

                   vm.posts.push(data[i]);

               }

           },

           function (data) {

               console.log('Falha ao consumir API.')

           }

           );

   };



   vm.paginaAtual = 2;



   vm.getPosts();



   vm.getMorePosts = function () {

       postsService.getPostsPerPage(vm.paginaAtual)

           .then(

           function (data) {

               if (data) {

                   for (var i = 0; i < data.length; i++) {

                       vm.posts.push(data[i]);

                   }

                   vm.paginaAtual++;

                   vm.noMore = false;

                   $scope.$broadcast('scroll.infiniteScrollComplete');

               } else {

                   vm.noMore = true;

                   $scope.$broadcast('scroll.infiniteScrollComplete');

               }

           },

           function (data) {

               $scope.$broadcast('scroll.infiniteScrollComplete');

               console.log('Falha ao consumir API.')

           }

           );

   };



}

 

No nosso controlador criamos um método chamado getMorePosts(), ele vai estar consumindo nosso serviço e exibindo mais postagens na tela principal, para o método criado ser chamado na nossa tela, iremos fazer uma pequena alteração no código html, posts.html ficará assim:

 

<ion-view view-title="Posts">

   <ion-content>

       <div ng-repeat="post in postsCtrl.posts" class="list card">



           <div class="item item-avatar">

               <img ng-src="{{post.author.avatar}}">

               <h2 class="cor-texto">{{post.author.name}}</h2>

               <p class="cor-texto">{{post.date}}</p>

           </div>



           <div class="item item-body">

               <div>

                   <h2 ng-bind-html="post.title"></h2>

                   <img class="full-image" src="{{post.featured_image}}">

               </div>

           </div>          

       </div>

       <ion-infinite-scroll

           on-infinite="postsCtrl.getMorePosts()"

           ng-if="!postsCtrl.noMore"

           distance="4%">

       </ion-infinite-scroll>

   </ion-content>

</ion-view>

 

No final da nossa página adicionamos o infinite-scroll onde ele ficará responsável por chamar o nosso método do controlador. A cada vez que o usuário utilizar o scroll e tiver mais postagens, ele irá buscar e exibir novas postagens.

 

Com isso temos a página principal onde são exibidas as postagens mais recentes e também podemos visualizar e carregas as postagens de 3 em 3 podendo visualizar todos os posts de nosso blog de forma agradável.

 

Vamos agora mexer no nosso menu, onde iremos exibir nele todas as categorias do nosso blog, podendo assim ter um filtro de ao clicar em determinada categorias, exibir somente as postagens da mesma.

 

Para isso vamos criar o menu.service.js onde teremos a seguinte estrutura:

 

 

angular.module('menu.service', [])

   .factory('menuService', menuService);



function menuService($http, $q) {

// interface

var service = {

   categories: [],

   getCategories: getCategories

};

return service;



// implementacao

function getCategories() {

   var def = $q.defer();



   $http.jsonp("http://localhost/appvila/wp-json/taxonomies/category/terms/?_jsonp=JSON_CALLBACK")

       .success(function(data) {

           service.categories = data;

           def.resolve(data);

       })

       .error(function() {

           def.reject("Falha ao buscar categorias");

       });

   return def.promise;

}

}

 

Com nosso código pronto, temos o serviço onde podemos consultar as categorias de nosso blog, e podemos usá-lo no controlador para exibir no menu. Vamos criar o código a seguir no controlador:

angular.module('menu.controller', [])

   .controller('MenuCtrl', MenuCtrl);



function MenuCtrl(menuService){

   var vm = this;

   

   //usando nosso service para consultar as postagens

   vm.categorias = [];

   vm.getCategories = function(){

       menuService.getCategories()

           .then(

               function(categorias){

                   vm.categorias = categorias;

               },

               function(data) {

                   console.log('Falha ao consumir API.')

               }

           );

   };



   vm.getCategories();

}

 

Nosso controlador está pronto para ser usado na página do menu, o menu ficará assim:

 

 

<ion-side-menus enable-menu-with-back-views="false">

 <ion-side-menu-content>

   <ion-nav-bar class="bar-calm">

     <ion-nav-back-button>

     </ion-nav-back-button>



     <ion-nav-buttons side="left">

       <button class="button button-icon button-clear ion-navicon" menu-toggle="left">

       </button>

     </ion-nav-buttons>

   </ion-nav-bar>

   <ion-nav-view name="menuContent"></ion-nav-view>

 </ion-side-menu-content>



 <ion-side-menu side="left">

   <ion-header-bar class="bar-calm">

     <h1 class="title">Categorias</h1>

   </ion-header-bar>

   <ion-content>

     <ion-list>

       <ion-item ng-repeat="categoria in menuCtrl.categorias" menu-close>

         <p class="menu-categorias">{{categoria.name}}</p>

       </ion-item>

     </ion-list>

   </ion-content>

 </ion-side-menu>

</ion-side-menus>

 

Para testarmos temos que inserir o script do menu no index.html e injetar o serviço no nosso app.js. Ficarão respectivamente dessa forma:

 

<!DOCTYPE html>

<html>

 <head>

   <meta charset="utf-8">

   <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

   <title></title>



   <link rel="manifest" href="manifest.json">



   <!-- un-comment this code to enable service worker

   <script>

     if ('serviceWorker' in navigator) {

       navigator.serviceWorker.register('service-worker.js')

         .then(() => console.log('service worker installed'))

         .catch(err => console.log('Error', err));

     }

   </script>-->



   <link href="lib/ionic/css/ionic.css" rel="stylesheet">

   <link href="styles/style.css" rel="stylesheet">



   <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above

   <link href="css/ionic.app.css" rel="stylesheet">

   -->



   <!-- ionic/angularjs js -->

   <script src="lib/ionic/js/ionic.bundle.js"></script>



   <!-- cordova script (this will be a 404 during development) -->

   <script src="cordova.js"></script>



   <!-- your app's js -->

   <script src="app/app.js"></script>



   <script src="app/posts/posts.controller.js"></script>

   <script src="app/posts/posts.service.js"></script>



   <script src="app/menu/menu.controller.js"></script>

   <script src="app/menu/menu.service.js"></script>



 </head>

 <body ng-app="appvila">

   <ion-nav-view></ion-nav-view>

 </body>

</html>

 

e

// Ionic Starter App



// angular.module is a global place for creating, registering and retrieving Angular modules

// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)

// the 2nd parameter is an array of 'requires'

angular.module('appvila', ['ionic', 'menu.controller', 'posts.controller', 'posts.service', 'menu.service'])



.run(function($ionicPlatform) {

 $ionicPlatform.ready(function() {

   if(window.cordova && window.cordova.plugins.Keyboard) {

     // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard

     // for form inputs)

     cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);



     // Don't remove this line unless you know what you are doing. It stops the viewport

     // from snapping when text inputs are focused. Ionic handles this internally for

     // a much nicer keyboard experience.

     cordova.plugins.Keyboard.disableScroll(true);

   }

   if(window.StatusBar) {

     StatusBar.styleDefault();

   }

 });

})



.config(function($stateProvider, $urlRouterProvider) {

 $stateProvider



 .state('app', {

   url: '/app',

   abstract: true,

   templateUrl: 'app/menu/menu.html',

   controller: 'MenuCtrl as menuCtrl'

 })



 .state('app.posts', {

   url: "/posts",

   views: {

     'menuContent': {

       templateUrl: "app/posts/posts.html",

       controller: 'PostsCtrl as postsCtrl'

     }

   }

 });



 $urlRouterProvider.otherwise('/app/posts');



});

 

 

 

Agora estamos aptos a testar a nossa aplicação e verificar se tudo ocorreu bem, ao executarmos $ionic serve -l no diretório da nossa aplicação veremos a tela a seguir:

 

Emulador 1

 

No menu lateral serão exibidas as categorias e na tela principal estarão as postagens.

 

Agora está faltando implementar a ação de ao clicar na categoria, buscar somente os posts daquela categoria, para isso vamos primeiramente acrescentar a rota onde isso irá acontecer em nosso app.js vamos acrescentar mais um estado:

 

 

.state('app.postsCategories', {

   url: "/posts/:categorieName",

   views: {

     'menuContent': {

       templateUrl: "app/post-categories/post-categories.html",

       controller: 'PostsCategoriesCtrl as categorieCtrl'

     }

   }

 })

 

em templateUrl podemos observar que está apontando para um diretório que ainda não existe, bom, vamos criá-lo, ele irá ficar dentro de app/ , como podemos observar na imagem, e dentro do diretório seguiremos o nosso padrão e vamos criar post-categories.html, post-categories.controller.js e post-categories.service.js, ele será muito parecido com a página posts:

 

VSCode

 

Com nossos arquivos criados, vamos implementar agora nosso serviço dentro de post-categories.service.js, que terá o seguinte código:

 

 

angular.module('post-categories.service', [])

   .factory('postCategoriesService', postCategoriesService);



function postCategoriesService($http, $q) {

   // interface

   var service = {

       posts: [],

       getPosts: getPosts,

       getPostsPerPage: getPostsPerPage

   };

   return service;



   // implementacao

   function getPosts(categorie) {

       var def = $q.defer();

       var url = "http://localhost/appvila/wp-json/posts?filter[posts_per_page]=3&filter[category_name]="+categorie+"&_embed&_jsonp=JSON_CALLBACK";



       $http.jsonp(url)

           .success(function (data) {

               service.posts = data;

               def.resolve(data);

           })

           .error(function () {

               def.reject("Falha ao buscar posts");

           });

       return def.promise;

   }



   function getPostsPerPage(pagina, categorie) {

       var def = $q.defer();



       $http.jsonp("http://localhost/appvila/wp-json/posts?filter[posts_per_page]=3&filter[category_name]="+categorie+"&page="+pagina+"&_embed&_jsonp=JSON_CALLBACK")

           .success(function (data) {

                   service.posts = data;

                   def.resolve(data);

           })

           .error(function () {

               def.reject("Falha ao buscar posts");

           });

       return def.promise;

   }



}

 

Na nossa URL estamos filtrando os posts pelo nome da categoria que será enviada quando clicarmos no menu, agora vamos continuar nossa implementação, a vez é do post-categories.controller.js, que ficará assim:

 

 

angular.module('post-categories.controller', [])

   .controller('PostCategoriesCtrl', PostCategoriesCtrl);



function PostCategoriesCtrl(postCategoriesService, $ionicLoading, $scope, $stateParams) {

   var vm = this;

   vm.noMore = false;

   //usando nosso service para consultar as postagens

   console.log($stateParams.categorieName);

   vm.posts = [];

   vm.getPosts = function () {

       postCategoriesService.getPosts($stateParams.categorieName)

           .then(

           function (data) {

               for (var i = 0; i < data.length; i++) {

                   vm.posts.push(data[i]);

               }

           },

           function (data) {

               console.log('Falha ao consumir API.')

           }

           );

   };



   vm.paginaAtual = 2;



   vm.getPosts();



   vm.getMorePosts = function () {

       postCategoriesService.getPostsPerPage(vm.paginaAtual, $stateParams.categorieName)

           .then(

           function (data) {

               if (data) {

                   for (var i = 0; i < data.length; i++) {

                       vm.posts.push(data[i]);

                   }

                   vm.paginaAtual++;

                   vm.noMore = false;

                   $scope.$broadcast('scroll.infiniteScrollComplete');

               } else {

                   vm.noMore = true;

                   $scope.$broadcast('scroll.infiniteScrollComplete');

               }

           },

           function (data) {

               $scope.$broadcast('scroll.infiniteScrollComplete');

               console.log('Falha ao consumir API.')

           }

           );

   };



}

 

O que diferencia nossos arquivos são os parâmetros que são passados na URL e enviados para nosso serviço para montar a URL para consulta, agora vamos ver como fica nosso post-categories.html:

 

 

<ion-view view-title="Posts Por Categoria">

   <ion-content>

       <div ng-repeat="post in categorieCtrl.posts" class="list card">



           <div class="item item-avatar">

               <img ng-src="{{post.author.avatar}}">

               <h2 class="cor-texto">{{post.author.name}}</h2>

               <p class="cor-texto">{{post.date}}</p>

           </div>



           <div class="item item-body">

               <div>

                   <h2 ng-bind-html="post.title"></h2>

                   <img class="full-image" src="{{post.featured_image}}">

               </div>

           </div>          

       </div>

       <ion-infinite-scroll

           on-infinite="categorieCtrl.getMorePosts()"

           ng-if="!categorieCtrl.noMore"

           distance="4%">

       </ion-infinite-scroll>

   </ion-content>

</ion-view>

 

Com nossas estrutura e códigos implementados em cada script, vamos modificar o menu para inserir um método que será chamado ao clicar no item do menu, ele terá o código seguinte, logo após de vm.getCategories(); :

 

 

vm.listCategoriesPost = function(name){

       $state.go('app.postsCategories', {categorieName:name});

   };

 

E no nosso arquivo menu.html terá a seguinte mudança na linha 21:

 

 

<ion-item ng-repeat="categoria in menuCtrl.categorias"

         menu-close ng-click="menuCtrl.listCategoriesPost

('{{categoria.name}}')">

 

Vamos alterar o app.js e injetar o controlador e serviço criado:

 

 

angular.module('appvila', ['ionic', 'menu.controller', 'posts.controller', 'posts.service', 'menu.service'

 , 'post-categories.controller', 'post-categories.service'])

 

E no nosso index.html vamos chamas os scripts:

 

 

<script src="app/post-categories/post-categories.controller.js"></script>

   <script src="app/post-categories/post-categories.service.js"></script>

 

Feito isso podemos olhar como nossa aplicação está ficando:

Emulador-final

 

Bom galera, chegamos ao final de mais uma parte de nossa série, dessa vez implementamos muitas coisas, e semana que vem vamos incrementar ainda mais nossa aplicação, já inserindo push notification e claro a ação de ler o post.
Até semana que vem o/.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *