Статьи

JavaScript-приложение Parse.com с автономной поддержкой

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


Наткнулся на ваше сообщение в блоге на Parse + PhoneGap и хотел бы узнать ваше мнение о следующем сценарии использования этого комбо …

Я изучал возможности приложения, которое по существу имеет веб-форму (аналогично контактной форме, которую вы получили прямо здесь), которая будет хранить полученные данные с помощью Parse. Причина в том, что … было бы важно, чтобы приложение позволяло отправлять форму, даже если не было активного подключения к Интернету.

Итак, просто хотелось, чтобы вы подумали о том, ищу ли я правильное направление для достижения этой цели. У вас нет большого опыта работы с приложениями для iOS, но нужно с чего-то начинать, верно?

Я ответил ему в общих чертах:

  • Когда вы отправляете форму, нажмите Parse, если вы онлайн, и нажмите WebSQL, если нет.
  • Когда приложение запустится, проверьте, есть ли у вас данные в WebSQL, и если вы подключены к сети, нажмите их для анализа.

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

Я начал с создания макета для приложения. Поскольку читатель только что упомянул форму, я построил все приложение вокруг одной формы. Я решил создать простую форму отчета по НЛО. В нем есть поле для количества НЛО, вашего имени и описания. Я не использовал какую-либо инфраструктуру пользовательского интерфейса, но вместо этого направил свои невероятные дизайнерские навыки на эту задачу

Вот HTML-код формы, на случай, если вам интересно:

<h2>Sighting Reporter</h2>

<form id="sightForm">
Number of UFOs: <input type="number" id="numufos"><br/>
Your Name: <input type="text" id="yourname"><br/>
Description: <textarea id="description"></textarea><br/>
<input type="submit" value="Send Sighting">
</form>
view raw
gistfile1.html
Этот Gist предоставлен вам
GitHub .

Фантазии, а? Хорошо, теперь пришло время войти в код. Я собираюсь разобраться с этой частью за частью, и это может немного запутать, но я опубликую весь файл в одном куске в конце для вашего прочтения.

Независимо от того, в сети мы или нет, нам нужно настроить базу данных. Это делается через API WebSQL. Хотя этот API устарел, он полностью поддерживается в PhoneGap и прекрасно работает в Chrome, основном браузере, который я использую для тестирования.

$(document).ready(function() {

     //initialize db
     db = window.openDatabase("sightingdb", "1.0", "Sighting Database", 200000);
     db.transaction(createDB, errorCB, initApp);

     function createDB(trans) {
          trans.executeSql("create table if not exists sighting(id INTEGER PRIMARY KEY,numufos,yourname,description)");
     }

});

view raw
gistfile1.js
Этот Gist доставлен вам
GitHub .

Я не буду вдаваться в подробности, как это работает, как я уже говорил ( пример поддержки базы данных PhoneGap ), но даже если это совершенно новое для вас, я думаю, вы можете понять эту идею.

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

Я написал функцию, чтобы обернуть мой чек для онлайн / оффлайн поддержки. Зачем? Я написал это демо , не на самом деле строить его как приложение PhoneGap. Он должен нормально работать при преобразовании в мобильное приложение, и в этот момент мою функцию-обертку можно изменить, чтобы использовать API PhoneGap, но для моего первоначального тестирования я просто хотел использовать свойство navigator.onLine. Наличие обертки также позволило мне легко добавить хак (см. Закомментированную строку), чтобы проверить, что он не в сети.

function online() {
          //return false;
          return navigator.onLine;
}
view raw
gistfile1.js
Этот Gist доставлен вам
GitHub .

Если мы в сети, мне нужно инициализировать поддержку Parse. Я не буду повторять то, что уже описано в руководстве Parse JavaScript Guide . Вместо этого, это всего лишь пример того, как я инициализирую Parse.com с помощью своих ключей API и определяю тип объекта, который я называю SightingObject (как в случае наблюдения НЛО).

Parse.initialize("8Y0x2rCA0jKYdiC7wLKQuF9nQqKGFKdpqUHMfue3", "8m7ng0w9UirTV6k4ExsJ0WsmPGeZMsJd5hcu54Oq");
SightingObject = Parse.Object.extend("SightingObject");
view raw
gistfile1.js
Этот Gist доставлен вам
GitHub .

Теперь давайте посмотрим на обработчик формы. Помните, что это необходимо сохранить в Parse или в базу данных.

$("#sightForm").on("submit", function(e) {
     e.preventDefault();
     /*
     gather the values - normally we'd do a bit of validation, but since UFO chasers
     are known for their rigorous and rational pursuit of science, this will not be necessary
     */
     var report = {};
          report.numufos = $("#numufos").val();
          report.yourname = $("#yourname").val();
          report.description = $("#description").val();
     console.log("To report: ",report);
     //ok, disable the form while submitting and show a loading gfx
     $(this).attr("disabled","disabled");
     $("#loadingGraphic").show();

     if(online()) {
           console.log("I'm online, send to parse");
          saveToParse(report,resetForm);
     } else {
          console.log("I'm offline, save to WebSQL");
          db.transaction(function(trans) {
                trans.executeSql("insert into sighting(numufos,yourname,description) values(?,?,?)", [report.numufos, report.yourname, report.description]);
          }, errorCB, resetForm);
      }
});

view raw
gistfile1.js
Этот Gist доставлен вам
GitHub .

Этот блок кода немного большой, поэтому давайте разберем его. Первое, что я делаю, это беру значения из формы. Как упоминалось в комментариях, возможно, имеет смысл провести некоторую базовую проверку. Проверка винта — это демо. Затем я делаю некоторые базовые элементы пользовательского интерфейса, чтобы пользователь знал, что на заднем плане происходят захватывающие вещи (хотя в теории, не такие захватывающие, как НЛО перед ними). Тогда у нас есть онлайн / оффлайн блок. Я взял логику разбора в другую функцию, которую я покажу через минуту. Другая часть условного просто записывает его в базу данных. В обоих случаях мы запускаем функцию resetForm, которая обрабатывает сброс моего пользовательского интерфейса.

Вот saveToParse. Обратите внимание, как чертовски легко это. На всякий случай, если это не очевидно — это весь код, который мне нужен для постоянного хранения моих данных в облаке. Было бы проще, если бы инженеры Parse.com давали мне виноград и лайм-желе, пока я писал код.

function saveToParse(ob,successCB) {
     var sightingObject = new SightingObject();
     sightingObject.save(ob, {
         success: function(object) {
               console.log("Saved to parse.");
               console.dir(object);
               successCB(object);
         },
         error: function(model, error) {
               console.log("Error!");
               console.dir(error);
         }
     });
}

view raw
gistfile1.js
Этот Gist доставлен вам
GitHub .

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

//handles removing the disabled form stuff and loading gfx
function resetForm() {
          $("#numufos").val("");
          $("#yourname").val("");
          $("#description").val("");
          $("#sightForm").removeAttr("disabled","disabled");
          $("#loadingGraphic").hide();
          var status = $("#status");
          if(online()) {
                 status.fadeIn().html("Your sighting has been saved!").fadeOut(4000);
          } else {
               status.fadeIn().html("Your sighting has been saved locally and will be uploaded next time you are online!").fadeOut(4000);
          }
}

 

view raw
gistfile1.js
Этот Gist доставлен вам
GitHub .

Я провел небольшое тестирование и подтвердил, что оно работает. Сначала я использовал онлайн-браузер данных Parse.com:

Затем я проверил автономное хранилище. Chrome облегчает проверку, поскольку в него встроено средство просмотра базы данных:

Это почти все. Последний кусочек головоломки — загрузка данных из базы данных. Это тоже оказалось простым. Если мы в сети, мы можем запустить SQL для таблицы. Если что-то существует, мы загружаем его и удаляем.

//do we have existing objects in the db we can upload?
db.transaction(function(trans) {
     trans.executeSql("select * from sighting", [], function(trans,result) {
          //do we have rows?
          if(result.rows.length > 0) {
                    console.log("Ok, we need to push stuff up");
                    for(var i=0, len=result.rows.length; i<len; i++) {
                         var row = result.rows.item(i);

                         (function(row) {
                              //Parse will try to save everything, including ID, so make a quick new ob
                              var report = {};
                              report.numufos = row.numufos;
                              report.yourname = row.yourname;
                              report.description = row.description;

                              saveToParse(report, function() {
                                   console.log("i need to delete row "+row.id);
                                   db.transaction(function(trans) {
                                        trans.executeSql("delete from sighting where id = ?", [row.id]);
                                   }, errorCB);
                         });
                    }(row));

               }
          }
     },errorCB);
}, errorCB, function() {
     console.log("Done uploading the old rows");
});

view raw
gistfile1.js
Этот Gist доставлен вам
GitHub .

Это в основном это. Самая большая проблема с этим кодом заключается в том, что он не обрабатывает изменения вашего онлайн / автономного статуса, в частности, если вы запустите приложение в автономном режиме, сохраните некоторые наблюдения, а затем перейдете в онлайн, оно не будет загружать старые строки. Это не было бы слишком сложно исправить, но я старался сделать это простым. Как минимум, при следующем запуске приложения оно загрузит эти старые записи. Для людей, которые хотят видеть всю базу кода, просто просмотрите суть здесь: https://gist.github.com/3723074

Я также включил почтовый индекс, приложенный к этой записи в блоге. (Обратите внимание, что анимированный GIF предоставлен jQuery Mobile.)

Скачать прикрепленный файл