Статьи

Начало работы с Ionic: Услуги

Конечный продукт
Что вы будете создавать

В первой и второй части этой серии статей по Ionic мы настроили локальную разработку и создали пару представлений для загрузки списка парков с использованием некоторых компонентов Ionic, таких как базовая навигация и компоненты списка. В этом руководстве мы рассмотрим, как Ionic предоставляет ряд сервисов, которые позволяют программно управлять приложением и интерфейсом.

Ранее мы продемонстрировали, как Ionic предоставляет интерактивные функции через компоненты, которые используются в качестве элементов HTML (реализованных в виде угловых директив). Однако есть некоторые элементы интерфейса, которые не имеют смысла в качестве компонентов, созданных с помощью HTML, такие как наложения загрузчика или таблицы действий.

Давайте начнем с рассмотрения роли сервисов в вашем приложении. Я определил три основных типа услуг в Ionic:

  • компонентные услуги
  • услуги делегатов
  • вспомогательные услуги

Службы компонентов расширяют возможности использования компонентов, но вместо того, чтобы использовать HTML для их объявления (как мы видели в ionNavBar ), они управляются с помощью JavaScript. Другими словами, вы будете использовать эти компоненты, добавляя код в свои контроллеры. Мы будем использовать два из них в примере ниже.

Может быть полезно рассматривать эти сервисы как компоненты, имеющие жизненный цикл. Как правило, вы хотите, чтобы они загружались в определенный момент, и после того, как они это сделали, они удаляются. Например, $ionicModal позволяет создавать модальные. Модалы имеют жизненный цикл, они открываются и закрываются по определенным причинам. Возможно, у вас есть модал, который просит пользователей войти в систему, или они могут закрыть модель, чтобы пропустить ее, тем самым завершив жизненный цикл.

Некоторые из компонентов имеют сопутствующую службу делегатов, которая может изменять или управлять компонентом. Вы можете захотеть программно манипулировать компонентом после его создания, и эти сервисы предназначены для того, чтобы сделать это возможным. Они названы так, поскольку делегируют поведение компоненту.

Компонент ionNavBar имеет службу делегатов с именем $ionicNavBarDelegate . Эта служба имеет несколько методов, но одним примером является метод title() , который позволяет обновить заголовок панели навигации. Объем функций, доступных для каждой службы делегатов, различен, но их легко найти в документации по имени.

Последняя категория — это сервисы, которые предоставляют вспомогательные функции или предоставляют информацию. Их всего несколько, и они не совсем вписываются в две другие категории. Вот некоторые примеры:

  • $ionicPlatform : помогает взаимодействовать с оборудованием устройства
  • $ionicGesture : позволяет обрабатывать события жестов
  • $ionicPosition : сообщает вам расположение элементов на экране

Эти вспомогательные услуги, как правило, помогают вам развивать логику или управлять взаимодействием. Они не генерируют и не изменяют компоненты самостоятельно.

Мы также рассмотрим несколько других вещей в этом уроке:

  • Компоненты CSS, которые являются только визуальными и не предоставляют никакой функциональной логики в отличие от их родных компонентов JavaScript
  • Ионные события, которые мы можем использовать для привязки к событиям, например, когда представление загружается или завершило загрузку
  • дополнительные функции навигации, облегчающие навигацию, управление состоянием и добавление кнопок на панель навигации

В этом уроке мы собираемся расширить приложение, которое мы начали в предыдущем уроке . Напоминаем, что приложение предназначено для предоставления пользователям информации об их местных общедоступных объектах, таких как библиотеки и парки. Приложение уже отображает список парков в Чикаго, и теперь мы добавим возможность отображать индикаторы загрузки, просматривать отдельные экраны парков, открывать меню действий и реализовывать некоторые базовые функции общего доступа.

Вы можете просмотреть завершенный проект на GitHub . Последний пример также доступен для предварительного просмотра .

Вы можете скачать файлы или проверить их с помощью Git. Когда у вас есть файлы на вашем компьютере, вам нужно запустить npm install для настройки проекта. Если вы проверяете код с помощью Git, вы можете писать код, если вы сбрасываете репозиторий, чтобы он соответствовал месту, где последняя часть закончилась, запустив git checkout –b start . Когда у вас есть файлы, запустите ваш Ionic-сервер, запустив ionic serve .

В настоящее время приложение загружает данные, и имеется небольшой круговой индикатор из компонента бесконечной прокрутки, который отображается до его загрузки. Тем не менее, мы на самом деле хотим наложить все приложение, чтобы было ясно, что приложение загружается.

Служба $ionicLoading очень полезна для наложения и блокирования взаимодействия пользователя с приложением до загрузки данных. Это настраивается. Например, вы можете объявить, появляется ли значок загрузки или какой-либо текст, хотите ли вы фон или нет, или он должен автоматически скрываться через определенный промежуток времени. Вы можете увидеть загрузчик в действии на скриншоте ниже.

Ionic Loader Overlaying App

Откройте www / views / place.js, чтобы внести несколько изменений в загрузчик. Во-первых, нам нужно добавить сервис в наш контроллер, добавив $ionicLoading к параметрам функции. Сервис довольно прост, у него есть только два метода, show() и hide() . Мы можем заставить загрузчик показывать и скрывать, вызывая методы, которые вы видите здесь в этом фрагменте.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.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();
    });
  };
});

Метод $ionicLoading.show() вызывается сразу после загрузки контроллера, что означает его немедленное срабатывание. Теперь нам нужно сказать загрузчику скрыться после окончания загрузки данных, как вы видите сразу после $broadcast .

Вы можете заметить, что метод $ionicLoading.hide() вызывается при каждой загрузке данных. Это не проблема. Поскольку загрузчик уже скрыт, этот вызов не имеет никакого эффекта.

Теперь мы внедрили ионный сервис. Довольно просто Правильно? Некоторые из них немного сложнее, и мы будем работать над другим примером, используя лист действий. Однако прежде чем мы перейдем к этому, мы хотим расширить наше приложение, чтобы иметь два представления как для списка заметок, так и для отдельного просмотра заметки.

Наш следующий шаг — создать новый вид, который будет отображать более подробную информацию о конкретном парке. Информация может варьироваться от парка к парку, но мы сосредоточимся на получении информации об изображении, веб-сайте, телефоне и адресе. Результаты добавления этого представления показаны здесь.

Просмотр мест с подробным описанием парка

Чтобы создать новый вид, создайте файл по адресу www / views / place / place.js и включите содержимое, которое вы видите ниже. Это контроллер и определение состояния для представления place .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
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;
});

Если вы посмотрите на метод config() , вы увидите, что мы объявляем новое состояние. Это UI-маршрутизатор в действии, поэтому вам следует обратиться к документации по UI-маршрутизатору для получения подробной информации об объявлении состояний.

Определение объекта показывает, что мы используем URL-адрес /places/:place_id . Когда вы видите часть URL с двоеточием впереди, например :place_id , она помечает эту часть пути как параметр состояния. Состояние может получить значение и предоставить его вам с $stateParams объекта $stateParams . Например, /places/12345 $stateParams.place_id = '12345' /places/12345 приведет к $stateParams.place_id = '12345' .

Вы видели другие части определения ранее, за исключением свойства resolve . Это функция, которая позволяет запрашивать различные функции для вызова до создания состояния. Он принимает объект с ключом и значениями функции, поэтому здесь мы используем Place в качестве ключа и результат функции будет присвоен ему.

В функции он может принимать параметры для ввода, аналогично тому, что вы можете сделать с контроллером. Здесь $stateParams сервисы $http и $stateParams . Затем функция использует значение из place_id переданного через URL, создает и возвращает HTTP-запрос. По сути, это то, что делается в представлении мест, за исключением того, что это делает контроллер.

Функция разрешения достаточно умна, чтобы определить, что если вы вернете обещание, оно будет ждать разрешения, прежде чем создавать состояние. Другими словами, $http.get() возвращает обещание загрузить данные, а ui-router ждет, пока данные $http.get() доступны, прежде чем создавать состояние и передавать Place в контроллер. Функция разрешения довольно полезна для предварительной загрузки данных в ваши приложения, и это довольно простой пример того, как ее использовать.

Теперь, когда мы определили состояние, контроллер объявляется и присваивает результирующие данные из Place (это то, что было разрешено в состоянии) vm.place . Нам также нужно сделать наш шаблон для этого состояния, поэтому создайте новый файл по адресу www / views / place / place.html и добавьте в него следующий контент.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<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>

Этот шаблон начинается с использования ionView для упаковки содержимого, чтобы система навигации Ionic могла правильно его отслеживать. Он также присваивает название на основе названия места. ionContent содержит основной контент, и вы заметите, что шаблон использует классы CSS вместо элементов для создания компонента карты.

В предыдущей части мы говорили о том, что некоторые компоненты являются только классами CSS. Карта является одним из примеров этого. Концептуально это похоже на список. Внутреннее содержимое складывается вертикально как список, но стилизация выглядит больше как карта. Это использует стили карты, которые включают такие функции, как поддержка изображений, значки и другие аккуратные макеты, описанные в документации .

ngIf несколько директив ngIf поскольку нет гарантии, что возвращаемые данные будут иметь номер телефона или веб-сайт. Директива ngIf гарантирует, что пустые значения не отображаются. Он также использует ngHref или ngSrc для правильного построения ссылок.

Вы также заметите использование протокола tel:// , который при использовании на телефоне должен побуждать пользователя звонить по номеру при его выборе. Это удобная функция, которая проста в использовании и прекрасно интегрируется на физическом устройстве. Некоторые программы на вашем компьютере, такие как Skype, могут также попытаться обработать телефонный звонок для вас, в зависимости от ваших настроек.

Это должно дать нам рабочее представление, но как мы к нему перейдем? Нам нужно сделать пару небольших изменений, чтобы навигация работала из вида мест.

Ui-router предоставляет директиву ui-sref которая используется для связи элементов с другим состоянием. В этом случае мы хотим, чтобы каждый элемент в списке представлений мест связывался с соответствующим представлением мест.

Откройте www / views / place / place.html и добавьте директиву для ссылки на каждое место. Обновите ionItem с новым атрибутом здесь.

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

Директива ui-sref имеет формат, в котором вы можете ссылаться на другое состояние по его имени, а не по некоторому URL, как вы делаете с помощью href . Это удобно, так как URL могут измениться. Он также может принимать параметры, используемые для построения URL, и в нашем случае мы хотим передать свойство place.place_id . ui-sref принимает свойства как объект, поэтому синтаксис — это state-name({param: value}) .

Теперь просмотрите приложение и выберите парк, оно перейдет к новому виду place и вы можете посмотреть в адресной строке, чтобы увидеть, что URL добавляет значение place_id . Тем не менее, у нас сейчас есть проблема. Как нам вернуться к списку?

Мы используем функциональность ionNavBackButton чтобы дать нам автоматическую кнопку возврата. Откройте www / index.html и добавьте следующий фрагмент внутри ionNavBar . Это добавляет кнопку возврата, которая будет отображаться только тогда, когда есть место, куда можно вернуться.

1
2
3
4
5
<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>

Навигация Ionic достаточно умна, чтобы отслеживать историю, пока вы используете приложение. Если есть предыдущий вид для возврата, он покажет кнопку возврата. В противном случае он будет просто скрыт.

Мы также хотим объявить, что представление мест никогда не должно показывать кнопку «назад», что мы можем сделать, добавив директиву hideBackButton в www / views / place / place.html .

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

Во время разработки и предварительного просмотра в браузере иногда история сбрасывается. Например, когда вы находитесь в представлении мест и сохраняете изменения в редакторе, браузер автоматически перезагружается и сбрасывает историю. В этом случае кнопка «Назад» не отображается должным образом. Вы можете исправить это, вернувшись к списку и обновив, чтобы исправить историю.

Мы добились хорошего прогресса, но сейчас, когда вы нажимаете на элемент в списке, он ожидает перехода к новому представлению, пока вызов API не вернется с данными. Это может показаться вам быстрым, но иногда оно может быть медленным, если API медленный. Это может заставить кого-то думать, что приложение зависло, работает медленно или что оно не зарегистрировало свой кран, поскольку оно не сразу начало реагировать на нажатие. Мы обращаемся к этому с некоторыми событиями жизненного цикла, которые помогают нам настроить загрузчик для отображения в течение этого времени.

Чтобы улучшить взаимодействие с пользователем, мы будем использовать сервис $ionicLoading для наложения приложения, пока данные загружаются для представления места. Чтобы узнать, когда показать и скрыть загрузчик, мы используем события жизненного цикла .

Эти события генерируются на основе событий навигации, таких как до / после входа в вид или до / после выхода из вида. Вы можете сделать все, что может потребоваться в эти моменты времени, например сброс некоторых данных или, возможно, использовать их для отправки информации об использовании.

Чтобы продемонстрировать это, давайте добавим один прослушиватель событий в представление мест, которое обрабатывает запуск загрузчика, когда вы начинаете переходить к представлению мест. Откройте www / views / place / place.js и добавьте следующее в контроллер. Вы также должны убедиться, что $scope объявлен в параметрах функции контроллера, чтобы он был доступен.

1
2
3
$scope.$on(‘$ionicView.beforeLeave’, function() {
  $ionicLoading.show();
});

Это прослушиватель событий области, который прослушивает событие $ionicView.beforeLeave (см. События угловой области ). Ionic передает это событие вашему контроллеру и вызывает анонимную функцию, объявленную здесь. Эта функция просто вызывает метод $ionicLoading.show() для включения загрузчика.

Это заставляет загрузчик появляться, как только пользователь нажимает на элемент. Теперь мы добавляем подобный фрагмент к представлению места, которое обрабатывает скрытие загрузчика, когда представление завершило загрузку. Откройте www / views / place / place.js и добавьте следующее в контроллер. Вам необходимо добавить как $ionicLoading и $scope к параметрам функции контроллера, так как они в настоящее время не вводятся.

1
2
3
$scope.$on(‘$ionicView.afterEnter’, function() {
  $ionicLoading.hide();
});

Он прослушивает другое событие области действия, которое запускается, когда представление завершается, и вызывает функцию, чтобы скрыть загрузчик. Загрузчик отображается в промежутке между моментом, когда пользователь нажимает на место для просмотра, пока представление не загрузится полностью. Вы можете попробовать другие события и посмотреть, когда они сработают.

Последнее, что мы сделаем в этом руководстве, — это установим кнопку обмена листами действий, которая позволит вам публиковать сообщения в Twitter, Facebook или по электронной почте и делиться информацией о парке.

Листы действий очень полезны для предоставления списка дополнительных опций. Обычно это делается для ситуаций, когда вы хотите представить список действий, которые сгруппированы, и, в нашем примере, это список способов обмена информацией о парке. Лист действий, который мы создадим, выглядит следующим образом.

Ionic Action Sheet в действии

Служба лист действий немного сложнее, чем служба загрузки, потому что она обрабатывает конфигурацию и пользовательский ввод. Откройте www / views / place / place.js и добавьте этот новый метод в свой контроллер. Вы также должны убедиться, что $ionicActionSheet введен в ваш контроллер.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
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();
    }
  });
};

Метод openSheet() отвечает за создание листа действий. Это делается путем вызова $ionicActionSheet.show() , который возвращает функцию, которая хранится на sheet . Это позволяет вам закрыть лист, когда вы закончите с ним позже, вызвав sheet() . Метод show() принимает объект с рядом свойств, которые мы разберем. Есть несколько примеров сервисов Ionic, которые следуют этому шаблону, таких как модалы и всплывающие окна, так что вы всегда можете обработать их закрытие.

Лист управляет заголовком с titleText свойства titleText и обычно используется для информирования пользователя о том, как использовать кнопки. Свойство cancelText принимает строку, которая используется для включения кнопки отмены. Если вы не заявите об этом, кнопка отмены не будет выбрана. Вы также можете отменить, нажав на фоне за пределами кнопок.

Чтобы объявить кнопки, вы используете свойство buttons , которое представляет собой массив объектов, имеющих свойство text . Они отображаются в порядке их объявления, поэтому сортируйте их соответствующим образом.

Свойство buttonClicked принимает функцию и передает индекс выбранной кнопки (как было объявлено в buttons ). Следовательно, вы можете выяснить, что делать, основываясь на том, какой индекс передан. В этой функции индекс проверяется и либо открывает Facebook, Twitter, либо использует mailto: для запуска почтового клиента.

Он может открывать эти ссылки в приложениях Facebook, Twitter или электронной почты, в зависимости от настроек пользователя и, возможно, устройства, но, по крайней мере, будет открывать ссылки за пределами вашего приложения (во внешнем браузере). Последним этапом является вызов метода sheet() , который закрывает лист действий.

Лист действий теперь готов к действию, но нам все еще нужно добавить кнопку для запуска листа. Для этого мы добавляем кнопку панели навигации в представление мест, которое вызывает vm.openSheet() . Откройте www / views / place / place.html и добавьте фрагмент ionNavButtons между ionView и ionContent .

1
2
3
4
5
6
7
<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>

Вот еще одна полезная навигационная функция Ionic, которая позволяет добавить кнопку панели навигации в конкретный вид с помощью ionNavButtons . Любые кнопки внутри добавляются на панель навигации, и вы можете настроить, с какой стороны они появляются.

На данный момент все работает. Пользователи могут открыть лист действий, чтобы поделиться парком со своими друзьями.

В этом уроке мы рассказали о сервисах Ionic и о том, как они используются. По пути мы обнаружили ряд других ионных функций:

  • Ионные сервисы вызываются в контроллерах и обычно имеют жизненный цикл независимо от текущего представления.
  • $ionicLoading полезен для отображения и скрытия индикатора загрузки, когда ваше приложение загружает данные или должно блокировать пользовательский интерфейс.
  • Служба $ionicActionSheet предоставляет пользователю список кнопок, наложенных на приложение, чтобы обеспечить легкий доступ к важным действиям.
  • Ионные функции навигации также включают в себя ionNavBackButton чтобы автоматически отображать кнопку возврата, когда можно вернуться назад. ionNavButtons позволяет добавлять кнопки панели навигации в определенные виды.
  • В Ionic есть CSS-компоненты, такие как карта, которые не имеют специальных интерактивных функций и используются просто путем объявления CSS-классов.

В следующей части мы еще углубимся в некоторые навигационные функции Ionic.

Если вы уже знакомы с платформой Ionic, то вы можете рассмотреть возможность участия в конкурсе Envato Most Wanted для ионных шаблонов . Как? Создайте уникальный шаблон Ionic и отправьте его в Envato Market до 27 апреля 2016 года.

Пять лучших шаблонов получают 1000 долларов. Заинтересованы? Читайте больше на сайте конкурса для получения подробной информации о требованиях и правилах конкурса.