Primeros pasos con Ionic:Servicios

1. Introducción a los Servicios

En la primera y segunda parte de esta serie sobre Ionic, configuramos el desarrollo local y construimos un par de vistas para cargar una lista de parques usando algunos de los componentes de Ionic, como la navegación base y los componentes de lista. En este tutorial, profundizaremos en cómo Ionic proporciona una serie de servicios que le permiten administrar la aplicación y la interfaz mediante programación.

Anteriormente, demostramos cómo Ionic proporciona funciones interactivas a través de componentes, que se utilizan como elementos HTML (implementados como directivas Angular). Sin embargo, hay algunos elementos de la interfaz que no tienen sentido como componentes instanciados con HTML, como un cargador o superposiciones de hojas de acción.

Comencemos por echar un vistazo a la función que desempeñan los servicios en su aplicación. He identificado tres tipos principales de servicios en Ionic:

  • servicios de componentes
  • servicios delegados
  • servicios de asistencia

Servicios de componentes

Los servicios de componentes permiten el uso de componentes, pero en lugar de usar HTML para declararlos (como vimos con ionNavBar ) se gestionan mediante JavaScript. En otras palabras, aprovechará estos componentes agregando código a sus controladores. Usaremos dos de estos en el siguiente ejemplo.

Puede ser útil pensar en estos servicios como componentes que tienen un ciclo de vida. Por lo general, desea que se carguen en un punto específico y, una vez que terminan, se eliminan. Por ejemplo, $ionicModal le permite crear un modal. Los modales tienen un ciclo de vida, se abren y cierran por razones específicas. Es posible que tenga un modal que pida a los usuarios que inicien sesión o que puedan cerrar el modelo para omitirlo, completando así el ciclo de vida.

Servicios delegados

Algunos de los componentes tienen un servicio delegado complementario que puede modificar o administrar el componente. Es posible que desee manipular mediante programación un componente después de que se haya creado y estos servicios están diseñados para hacerlo posible. Se llaman así porque delegan el comportamiento al componente.

El ionNavBar componente tiene un servicio delegado llamado $ionicNavBarDelegate . Este servicio tiene varios métodos, pero un ejemplo es el title() método, que le permite actualizar el título de la barra de navegación. El alcance de las funciones disponibles para cada servicio delegado varía, pero deberían ser fáciles de identificar en la documentación por su nombre.

Servicios de Asistencia

La última categoría son servicios que brindan algún tipo de funcionalidad de asistencia o brindan información. Solo hay unos pocos y no encajan del todo en las otras dos categorías. Algunos ejemplos son:

  • $ionicPlatform :te ayuda a interactuar con el hardware del dispositivo
  • $ionicGesture :le permite manejar eventos de gestos
  • $ionicPosition :le dice la ubicación de los elementos en la pantalla

Estos servicios de asistencia tienden a ayudarlo a desarrollar la lógica o manejar la interacción. No generan ni modifican componentes por su cuenta.

También veremos algunas otras cosas en este tutorial:

  • Componentes CSS, que son solo visuales y no proporcionan una lógica funcional a diferencia de sus componentes hermanos JavaScript
  • Eventos iónicos, que podemos aprovechar para vincular eventos, por ejemplo, cuando la vista se está cargando o ha terminado de cargarse.
  • más funciones de navegación, que facilitan la navegación, la administración del estado y la adición de botones a la barra de navegación

Archivos fuente

En este tutorial, vamos a ampliar la aplicación que comenzamos en el tutorial anterior. Solo un recordatorio, la aplicación está diseñada para proporcionar a los usuarios información sobre sus instalaciones públicas locales, como bibliotecas y parques. La aplicación ya muestra una lista de parques en Chicago y ahora agregaremos la capacidad de mostrar indicadores de carga, ver pantallas de detalles de parques individuales, abrir un menú de acción e implementar algunas funciones básicas para compartir.

Puede ver el proyecto completo en GitHub. El ejemplo final también está disponible para obtener una vista previa.

Puede descargar los archivos o verificarlos usando Git. Una vez que tenga los archivos en su máquina, debe ejecutar npm install para configurar el proyecto. Si verifica el código usando Git, puede codificar si restablece el repositorio para que coincida donde terminó la última parte ejecutando git checkout –b start . Una vez que tenga los archivos, inicie su servidor Ionic ejecutando ionic serve .

2. Implementando un Indicador de Carga

Actualmente, la aplicación carga datos y hay un pequeño indicador de círculo del componente de desplazamiento infinito que se muestra hasta que se carga. Sin embargo, en realidad queremos superponer toda la aplicación para que quede muy claro que la aplicación se está cargando.

El $ionicLoading El servicio es muy útil para superponer y bloquear al usuario para que no interactúe con la aplicación hasta que se hayan cargado los datos. Es configurable. Por ejemplo, puedes declarar si aparece un icono de carga o algún texto, si quieres el fondo o no, o si debería ocultarse automáticamente después de un cierto período de tiempo. Puede ver el cargador en acción en la siguiente captura de pantalla.

Abra www/views/places.js para hacer algunas modificaciones para usar el cargador. Primero, debemos inyectar el servicio en nuestro controlador agregando $ionicLoading a los parámetros de la función. El servicio es bastante simple, solo tiene dos métodos, show() y hide() . Podemos hacer que el cargador se muestre y se oculte llamando a los métodos como se ve aquí en este fragmento.

.controller('PlacesController', function($http, $scope, $ionicLoading, Geolocation) {
  var vm = this;
  var base = 'https://civinfo-apis.herokuapp.com/civic/places?type=park&location=' + Geolocation.geometry.location.lat + ',' + Geolocation.geometry.location.lng;
  var token = '';
  vm.canLoad = true;
  vm.places = [];

  $ionicLoading.show();

  vm.load = function load() {
    var url = base;
    if (token) {
      url += '&token=' + token;
    }

    $http.get(url).then(function handleResponse(response) {
      vm.places = vm.places.concat(response.data.results);
      token = response.data.next_page_token;

      if (!response.data.next_page_token) {
        vm.canLoad = false;
      }
      $scope.$broadcast('scroll.infiniteScrollComplete');
      $ionicLoading.hide();
    });
  };
});

El $ionicLoading.show() El método se llama tan pronto como se carga el controlador, lo que significa que se activa inmediatamente. Ahora debemos decirle al cargador que se oculte después de que los datos hayan terminado de cargarse, como se ve justo después del $broadcast. .

Puede notar que el $ionicLoading.hide() El método se llama cada vez que se cargan los datos. Esto no es un problema. Dado que el cargador ya está oculto, esta llamada no tiene ningún efecto.

Ahora hemos implementado un servicio Ionic. Bastante simple. ¿Derecha? Algunos son un poco más complejos y trabajaremos en otro ejemplo usando la hoja de acción. Sin embargo, antes de llegar a eso, queremos expandir nuestra aplicación para tener dos vistas tanto para la lista de notas como para ver una nota individualmente.

3. Agregar la vista de notas

Nuestro siguiente paso es crear una nueva vista que muestre más detalles sobre un parque en particular. La información puede variar de un parque a otro, pero nos concentraremos en obtener una imagen, un sitio web, un teléfono y una dirección. Los resultados de agregar esta vista se muestran aquí.

Para crear una nueva vista, cree un archivo en www/views/place/place.js e incluye el contenido que ves a continuación. Este es el controlador y la definición de estado para el place ver.

angular.module('App')
.config(function($stateProvider) {
  $stateProvider.state('place', {
    url: '/places/:place_id',
    controller: 'PlaceController as vm',
    templateUrl: 'views/place/place.html',
    resolve: {
      Place: function($http, $stateParams) {
        var url = 'https://civinfo-apis.herokuapp.com/civic/place?place_id=' + $stateParams.place_id;
        return $http.get(url);
      }
    }
  });
})
.controller('PlaceController', function($scope, Place) {
  var vm = this;

  vm.place = Place.data.result;
});

Si echas un vistazo al config() método, verá que estamos declarando un nuevo estado. Este es el enrutador ui en acción, por lo que debe consultar la documentación del enrutador ui para obtener todos los detalles sobre la declaración de estados.

La definición del objeto muestra que estamos usando una URL de /places/:place_id . Cuando vea una parte de la URL con dos puntos delante, como :place_id , marca esta parte de la ruta como un parámetro de estado. El estado puede extraer el valor y proporcionárselo mediante $stateParams objeto. Por ejemplo, /places/12345 daría como resultado $stateParams.place_id = '12345' .

Has visto las otras partes de la definición anteriormente, excepto el resolve propiedad. Esta es una función que le permite solicitar que se llamen varias funciones antes de que se cree el estado. Acepta un objeto de valores de clave y función, por lo que aquí tenemos Place como tecla y se le asignará el resultado de la función.

En la función, puede aceptar parámetros para inyectar, similar a lo que puede hacer con un controlador. Aquí, el $http y $stateParams Se inyectan servicios. La función luego usa el valor del place_id pasa a través de la URL y crea y devuelve una solicitud HTTP. Esto es esencialmente lo que se hace en la vista de lugares, excepto que lo hace el controlador.

La función de resolución es lo suficientemente inteligente como para determinar que si devuelve una promesa, esperará a que se resuelva antes de crear el estado. En otras palabras, $http.get() devuelve una promesa de cargar los datos y ui-router espera hasta que los datos estén disponibles antes de crear el estado y pasar el Place al controlador. La función de resolución es muy útil para precargar datos en tus aplicaciones y este es un ejemplo bastante básico de cómo aprovecharla.

Ahora que tenemos el estado definido, el controlador se declara y asigna los datos resultantes de Place (esto es lo que se resolvió en el estado) a vm.place . También necesitamos hacer nuestra plantilla para este estado, así que crea un nuevo archivo en www/views/place/place.html y añádele el siguiente contenido.

<ion-view view-title="{{vm.place.name}}">
  <ion-content>
    <div class="card" ng-if="vm.place">
      <div class="item item-text-wrap item-icon-left">
        <i class="icon ion-map"></i> {{vm.place.formatted_address}}</p>
      </div>
      <div class="item item-image" ng-if="vm.place.photos[0].photo_reference">
        <img ng-src="{{'https://civinfo-apis.herokuapp.com/civic/photo?photo_id=' + vm.place.photos[0].photo_reference}}">
      </div>
      <a ng-if="vm.place.website" class="item item-icon-left" ng-href="{{vm.place.website}}" target="_system">
        <i class="icon ion-link"></i> {{vm.place.website}}
      </a>
      <a ng-if="vm.place.formatted_phone_number" class="item item-icon-left" ng-href="tel://{{vm.place.formatted_phone_number}}">
        <i class="icon ion-ios-telephone"></i> {{vm.place.formatted_phone_number}}
      </a>
    </div>
  </ion-content>
</ion-view>

Esta plantilla comienza usando el ionView para envolver el contenido, de modo que el sistema de navegación Ionic pueda seguirlo correctamente. También asigna un título basado en el nombre del lugar. El ionContent wrapper contiene el contenido principal, y notará que la plantilla usa clases CSS en lugar de elementos para crear un componente de tarjeta.

En la parte anterior, hablamos sobre cómo algunos de los componentes son solo clases de CSS. La tarjeta es un ejemplo de eso. Conceptualmente, es como una lista. El contenido interno se apila verticalmente como una lista, pero el estilo se parece más a una tarjeta. Esto aprovecha los estilos de las tarjetas, que incluyen características como compatibilidad con imágenes, íconos y otros diseños ordenados que aparecen en la documentación.

Hay algunos ngIf directivas utilizadas ya que no hay garantía de que los datos devueltos tengan un número de teléfono o un sitio web. El ngIf directiva asegúrese de que no se muestren valores vacíos. También usa ngHref o ngSrc para construir enlaces correctamente.

También notará el uso del tel:// protocolo, que, cuando se usa en un teléfono, debe solicitar al usuario que llame al número cuando lo seleccione. Es una característica útil que es fácil de usar y se integra muy bien en un dispositivo físico. Algunos programas en su computadora, como Skype, también pueden tratar de hacer una llamada telefónica por usted, dependiendo de su configuración.

Esto debería darnos una vista de trabajo, pero ¿cómo navegamos hacia ella? Tendremos que hacer un par de pequeñas modificaciones para que la navegación funcione desde la vista de lugares.

4. Navegación entre vistas

El enrutador ui proporciona un ui-sref directiva que se utiliza para vincular elementos a otro estado. En este caso, queremos que cada uno de los elementos de la lista de la vista de lugares se vincule a la vista de lugar correspondiente.

Abra www/views/places/places.html y agregue la directiva para vincular a cada lugar. Actualice el ionItem con el nuevo atributo aquí.

<ion-item ng-repeat="place in vm.places" class="item-avatar" ui-sref="place({place_id: place.place_id})">

El ui-sref La directiva tiene un formato en el que puede vincular a otro estado por su nombre, no por una URL como lo hace con href . Esto es útil ya que las URL pueden cambiar. También puede aceptar parámetros para construir la URL y, en nuestro caso, queremos pasar el place.place_id propiedad. El ui-sref toma propiedades como un objeto, por lo que state-name({param: value}) es la sintaxis.

Ahora obtenga una vista previa de la aplicación y seleccione un parque, navegará al nuevo place ver y puede  mirar la barra de direcciones para ver que la URL agrega un place_id valor. Sin embargo, ahora tenemos un problema. ¿Cómo volvemos a la lista?

Usamos el ionNavBackButton funcionalidad para darnos un botón de retroceso automático. Abra www/index.html y agrega el siguiente fragmento dentro del ionNavBar . Esto agrega un botón Atrás que solo se mostrará cuando haya un lugar al que volver.

<ion-nav-bar class="bar-balanced">
  <ion-nav-back-button class="button-clear">
    <i class="ion-arrow-left-c"></i> Back
  </ion-nav-back-button>
</ion-nav-bar>

La navegación de Ionic es lo suficientemente inteligente como para realizar un seguimiento del historial mientras usa la aplicación. Si hay una vista anterior a la que volver, se mostrará el botón Atrás. De lo contrario, simplemente se ocultará.

También queremos declarar que la vista de lugares nunca debe mostrar el botón Atrás, lo que podemos hacer agregando el hideBackButton directiva en www/views/places/places.html .

<ion-view view-title="Local Parks" hide-back-button="true">

Mientras desarrolla y obtiene una vista previa en el navegador, a veces se restablece el historial. Por ejemplo, cuando está en la vista del lugar y guarda un cambio en su editor, el navegador se vuelve a cargar automáticamente y restablece el historial. En este caso, el botón Atrás no aparece como se esperaba. Puede solucionar esto volviendo a la lista y actualizando para aclarar el historial.

Hemos hecho un buen progreso, pero en este momento, cuando toca un elemento en la lista, espera para pasar a la nueva vista hasta que la llamada a la API regresa con los datos. Puede parecerle rápido, pero a veces puede ser lento si la API es lenta. Puede hacer que alguien piense que la aplicación está atascada, lenta o que no registró su toque porque no comenzó a reaccionar inmediatamente al toque. Abordamos esto con algunos de los eventos del ciclo de vida que nos ayudan a configurar un cargador para mostrar durante este tiempo.

5. Agregar el cargador durante las transiciones

Para proporcionar una mejor experiencia de usuario, vamos a utilizar el $ionicLoading service para superponer la aplicación mientras se cargan los datos para la vista del lugar. Para saber cuándo mostrar y ocultar el cargador, usamos los eventos del ciclo de vida.

Estos eventos se activan en función de los eventos de navegación, como antes o después de acceder a una vista o antes o después de abandonar una vista. Puede hacer cualquier cosa que sea necesaria en estos momentos, como restablecer algunos datos o tal vez usarlos para enviar información de uso.

Para demostrarlo, agreguemos un detector de eventos a la vista de lugares que maneje la activación del cargador cuando comience a navegar a la vista de lugares. Abra www/views/places/places.js y agregue lo siguiente al controlador. También debe asegurarse de que $scope se declara en los parámetros de la función del controlador para que esté disponible.

$scope.$on('$ionicView.beforeLeave', function() {
  $ionicLoading.show();
});

Este es un detector de eventos de alcance que está escuchando el $ionicView.beforeLeave evento (consulte Eventos de alcance angular). Ionic transmite este evento a su controlador y llama a la función anónima declarada aquí. Esta función simplemente llama al $ionicLoading.show() método para encender el cargador.

Esto hace que el cargador aparezca tan pronto como el usuario toque un elemento. Ahora agregamos un fragmento similar a la vista del lugar que maneja ocultar el cargador cuando la vista ha terminado de cargarse. Abra www/views/place/place.js y agregue lo siguiente al controlador. Debe agregar ambos $ionicLoading$scope a los parámetros de función del controlador ya que no se inyectan actualmente.

$scope.$on('$ionicView.afterEnter', function() {
  $ionicLoading.hide();
});

Esto escucha un evento de alcance diferente que se activa cuando la vista finaliza y llama a la función para ocultar el cargador. El cargador se muestra en el tiempo que transcurre entre el momento en que el usuario toca un lugar para verlo y hasta que la vista se carga por completo. Puedes probar con otros eventos y ver cuándo se activan.

Lo último que hacemos en este tutorial es configurar un botón para compartir la hoja de acción que le permite publicar en Twitter, Facebook o correo electrónico y compartir la información del parque.

6. Botón para compartir usando el servicio de hoja de acción

Las hojas de acción son bastante útiles para proporcionar una lista de opciones adicionales. La intención suele ser para situaciones en las que desea presentar una lista de acciones que se agrupan y, en nuestro ejemplo, es una lista de formas de compartir la información del parque. La hoja de acción que crearemos se ve así.

El servicio de hoja de acción es un poco más complejo que el servicio de carga, porque maneja la configuración y las entradas del usuario. Abra www/views/place/place.js y agregue este nuevo método a su controlador. También debe asegurarse de que $ionicActionSheet se inyecta en su controlador.

vm.openSheet = function() {
  var sheet = $ionicActionSheet.show({
    titleText: 'Share this place',
    buttons: [
      { text: 'Share via Twitter' },
      { text: 'Share via Facebook' },
      { text: 'Share via Email'}
    ],
    cancelText: 'Cancel',
    buttonClicked: function(index) {
      if (index === 0) {
        window.open('https://twitter.com/intent/tweet?text=' +
          encodeURIComponent('I found this great place! ' + vm.place.url));
      } else if (index === 1) {
        window.open('https://www.facebook.com/sharer/sharer.php?u=' + vm.place.url);
      } else if (index === 2) {
        window.open('mailto:?subject=' + encodeURIComponent('I found this great place!') + '&body=' + vm.place.url);
      }
      sheet();
    }
  });
};

El openSheet() El método es responsable de crear la hoja de acción. Lo hace llamando al $ionicActionSheet.show() , que devuelve una función que se almacena en sheet . Eso le permite cerrar la hoja cuando haya terminado más tarde llamando al sheet() . El show() El método toma un objeto con una serie de propiedades que desglosaremos. Hay varios ejemplos de servicios de Ionic que siguen este patrón, como los modales y los popovers, por lo que siempre puede encargarse de cerrarlos.

La hoja administra el título usando el titleText propiedad y normalmente se usa para informar al usuario cómo usar los botones. El cancelText La propiedad acepta una cadena que se utiliza para habilitar un botón de cancelación. Si no declara esto, no se seleccionará ningún botón de cancelación. También puede cancelar tocando el fondo fuera de los botones.

Para declarar los botones usas el buttons propiedad, que es una matriz de objetos que tienen un text propiedad. Se muestran en el orden en que se declaran, así que ordénelos en consecuencia.

El buttonClicked property toma una función y pasa el índice del botón que fue seleccionado (como fue declarado en buttons ). Por lo tanto, puede averiguar qué hacer según el índice que se pasa. En esta función, se verifica el índice y se abre Facebook, Twitter o se usa mailto: para activar el cliente de correo electrónico.

Puede abrir estos enlaces en las aplicaciones de Facebook, Twitter o correo electrónico, según la configuración del usuario y quizás el dispositivo, pero al menos abrirá los enlaces fuera de su aplicación (en un navegador externo). La pieza final es llamar al sheet() método, que cierra la hoja de acción.

La hoja de acción ahora está lista para la acción, pero aún necesitamos agregar un botón para activar la hoja. Para hacer esto, agregamos un botón de la barra de navegación a la vista del lugar que llama vm.openSheet() . Abra www/views/place/place.html y agrega el ionNavButtons fragmento entre el ionView y ionContent .

<ion-view view-title="{{vm.place.name}}">
  <ion-nav-buttons side="right">
    <button class="button button-clear" ng-click="vm.openSheet()">
      <i class="icon ion-ios-upload-outline"></i>
    </button>
  </ion-nav-buttons>
  <ion-content>

Aquí hay otra característica útil de navegación de Ionic que le permite agregar un botón de barra de navegación a una vista particular usando ionNavButtons . Todos los botones del interior se agregan a la barra de navegación y puede configurar de qué lado aparecen.

En este punto, todo está funcionando. Los usuarios pueden abrir la hoja de acción para compartir el parque con sus amigos.

Conclusión

En este tutorial, cubrimos los servicios de Ionic y cómo se usan. En el camino, descubrimos una serie de otras funciones de Ionic:

  • Los servicios iónicos se llaman en los controladores y, por lo general, tienen un ciclo de vida independiente de la vista actual.
  • El $ionicLoading El servicio es útil para mostrar y ocultar un indicador de carga mientras su aplicación carga datos o tiene que bloquear la interfaz de usuario.
  • El $ionicActionSheet El servicio presenta al usuario una lista de botones superpuestos a la aplicación para facilitar el acceso a acciones importantes.
  • Las funciones de navegación Ionic también incluyen el ionNavBackButton para mostrar automáticamente un botón atrás cuando es posible volver atrás. ionNavButtons le permite agregar botones de la barra de navegación a vistas específicas.
  • Ionic tiene componentes CSS, como la tarjeta, que no tienen funciones interactivas especiales y se utilizan simplemente declarando clases CSS.

En la próxima entrega, profundizaremos aún más en algunas de las funciones de navegación de Ionic.

Cree una plantilla Ionic y gane $1000

Si ya se siente cómodo con el marco Ionic, entonces puede considerar participar en el concurso Most Wanted de Envato para plantillas Ionic. ¿Cómo? Cree una plantilla única de Ionic y envíela a Envato Market antes del 27 de abril de 2016.

Las cinco mejores plantillas reciben $1000. ¿Interesado? Lea más en el sitio web del concurso para obtener detalles sobre los requisitos y las pautas del concurso.