Добро пожаловать в третью часть моей серии блогов о создании приложения PhoneGap с поддержкой Parse.com . Если вы еще не читали более ранние записи в этой серии, пожалуйста, смотрите ссылки внизу для фона и истории до сих пор. В сегодняшней записи я наконец дошел до некоторого кода! Не много кода, но фактические данные создаются и отображаются, что немного дальше, чем мы получили до сих пор.
Моя цель для сегодняшнего поста — создать начальный макет приложения. Это включает в себя домашнюю страницу, страницу добавления подсказки и страницу получения подсказок. Я хотел, чтобы страница «Добавить подсказку» фактически поддерживала создание контента, в то время как страница «Полезные советы» выводила бы существующие данные в виде простого списка. Необычные карты будут позже.
Прежде чем я начал, я должен был принять решение. Я хотел, чтобы мое приложение хорошо выглядело на мобильных устройствах. Я мог бы использовать jQuery Mobile . Но я не хотел, чтобы установка jQuery Mobile была проблемой для людей, читающих эту серию. Всякий раз, когда я веду блог о конкретной теме, я стараюсь как можно более узко сосредоточиться на этой теме и избегать вещей, которые могут отвлечь внимание. Я не хотел, чтобы у людей, просматривающих эти записи в блоге, возникали проблемы с jQuery Mobile. Не поймите меня неправильно — jQuery Mobile очень прост в использовании, и я не думаю, что это вызовет какие-либо проблемы, но мне было достаточно этого, чтобы я мог рассмотреть другие варианты.
В итоге я выбрал Twitter Bootstrap . Я знал, что он поддерживает адаптивный дизайн для мобильных устройств, и я подумал, что это будет отличной возможностью опробовать его. Он также имел минимальные требования к коду и, по большей части, держался в стороне от меня.
Выбор структуры пользовательского интерфейса для приложения является невероятно важным решением. Я не хочу упрощать это. В то же время я хочу, чтобы мой удобный пользовательский интерфейс был выполнен быстро и сосредоточился на текущей задаче — использовании Parse.com и PhoneGap.
Тогда я начал с простой домашней страницы, основанной на моих макетах из первой записи в блоге . Я нажал на заголовок, немного рекламного текста и кнопки. Вот как это выглядело:
Заметили это меню сверху? Это часть адаптивной навигационной системы Bootstrap. При нажатии на него появляется всплывающее меню. При просмотре на планшете в альбомном режиме элементы отображаются на панели.
Как быстро — как я генерировал эти снимки экрана? С Adobe Edge Inspect (ранее Shadow) конечно. Edge Inspect мне очень помог, когда я создал приложение.
Давайте посмотрим на код за главной страницей. Здесь нет ничего ужасно интересного, но он даст вам возможность взглянуть на страницу с Bootstrap.
<!doctype html> <html lang="en"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script src="js/parse-1.1.2.min.js"></script> <script src="js/main.js"></script> <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet"> <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet"> </head> <body> <div class="navbar"> <div class="navbar-inner"> <div class="container"> <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </a> <!-- Be sure to leave the brand out there if you want it shown --> <a class="brand" href="#">CowTipLine</a> <div class="nav-collapse"> <ul class="nav"> <li class="active"><a href="index.html">Home</a></li> <li><a href="add.html">Add Tip</a></li> <li><a href="get.html">Get Tips</a></li> </ul> </div> </div> </div> </div> <div class="container"> <img src="images/ctl.png" title="CowTipLine"> <p> Tipping Cows? Need to find a cow? Welcome to the app that hooks you up! </p> <a href="add.html" class="btn btn-block">Add Tip</a> <a href="get.html" class="btn btn-block">Get Tips</a> </div> <script src="js/jquery-1.8.2.min.js"></script> <script src="bootstrap/js/bootstrap.min.js"></script> </body> </html>
Следующей была страница «Добавить совет». Опять же, это было довольно легко, поскольку наши советы состоят только из трех требований. Я построил простую форму:
<form id="addtipForm"> <label for="numcows">How many cows?</label> <input type="number" id="numcows" class="input-xlarge" placeholder="Enter the number of cows"> <label for="howdangerous">How dangerous?</label> <select id="howdangerous" class="input-xlarge"> <option value="1">Totally Safe</option> <option value="2">Some Risk</option> <option value="3">Farmer with Shotgun!</option> </select> <label for="comments">Anything else?</label> <textarea id="comments" class="input-xlarge"></textarea> <input type="submit" class="btn btn-block btn-primary" value="Send Tip"> </form>
Который дал мне это …
Хорошо, теперь давайте поговорим о коде, который будет интегрирован с этой формой. Я поделюсь соответствующим кодом (который можно найти в main.js), а затем объясню, что происходит.
Parse.initialize("oe3dboiG0RzJNULxKvdHYGWEb3Cq7mzHRC3Dwh6E", "cR8whmMjybMoXUqfAzhxUJSiBXw3QPt7ZB4bRGw8"); TipObject = Parse.Object.extend("TipObject"); $("#addtipForm").on("submit", function(e) { e.preventDefault(); //get values var numcows = $("#numcows").val(); var howdangerous = $("#howdangerous option:selected").val(); var comments = $("#comments").val(); //TBD: Validation var tip = new TipObject(); tip.save( { numcows:numcows, howdangerous:howdangerous, comments:comments },{ success:function(object) { console.log("Saved object"); doAlert("Tip Saved!", function() { document.location.href='index.html'; }); }, error:function(model, error) { console.log("Error saving"); } }); });
Прежде всего — у меня есть инициализация для Parse, которая использует мой идентификатор приложения и ключ JavaScript API. Я назвал это в моей последней записи в блоге .
Затем я создаю экземпляр моего TipObject. Это способ Parse для создания универсального типа объекта, который в конечном итоге будет сохранен. TipObject будет действовать как класс, который я могу использовать при работе с данными.
Теперь давайте посмотрим на этот обработчик событий. Первая часть — это шаблонная форма доступа jQuery. Как видите, я решил пока пропустить проверку. (Проверка для слабаков!) Как только я получу свои данные, я могу сделать новый совет. Переменная tip является экземпляром TipObject, который создается библиотекой Parse.
Сохранение этих данных становится тривиальным. У объекта есть экземпляр метода сохранения. Первый аргумент — это фактические данные, которые я сохраняю. Сейчас — это решающий момент, поэтому обратите пристальное внимание.
Разбор типов данных в свободной форме. Это означает, что я могу определять свои типы объектов так, как я хочу. Я решил, что «Советы» будут состоять из числа коров, рейтинга того, насколько опасен этот район, и комментариев в свободной форме. Parse не волнует, как я определяю свой объект Tip. Еще интереснее, позже я могу полностью передумать, как будет выглядеть структура.
Это и хорошо, и плохо. Во время разработки это здорово. Я могу попробовать и выяснить, какая форма «чувствует» лучше всего для приложения. Parse с удовольствием сохранит новые объекты с новой схемой без проблем. На самом деле, я планирую сделать это в следующей записи блога. (Я буду добавлять поддержку геолокации.)
Однако после запуска это попадает в область Very Bad Idea.
Если вы измените свою структуру данных после того, как люди используют приложение, ваш код должен как-то с этим справиться. Итак, представьте, что у вас есть тип данных с именем person и свойством Name. Позже вы поймете, что имеет больше смысла иметь вместо них свойства firstName и lastName. Теперь вам нужно обновить все эти старые данные или написать код, который обрабатывает оба «стиля» объектов. Это, безусловно, возможно сделать (не забывайте, что вы можете получить доступ к данным Parse.com через REST API — что означает, что вы можете использовать некоторый код на стороне сервера для одноразового обновления данных), но по большей части, Вы хотите попытаться сделать вашу конструкцию как можно более конкретной перед запуском.
Хорошо, достаточно с проповедью, вы поняли идею. Но самое крутое — мне не нужно было идти в браузер данных Parse. Мне не нужно было составлять таблицу базы данных. Я сделал объект. Я сохранил это. Я задолбался. Серьезно — я только что выгрузил все требования к базе данных на Parse.com примерно за 30 секунд кода. Если вас это не волнует, тогда я не знаю, что будет!
При сохранении объекта я сообщаю пользователю, а затем отправляю его обратно. Вызов doAlert — это просто функция-обертка, которую я написал для обработки предупреждений и обратных вызовов. Когда я заставлю PhoneGap работать с кодом должным образом, эта функция будет обрабатывать обнаружение десктопа в сравнении с устройством и по возможности использовать API уведомления PhoneGap .
Итак, последняя часть сегодняшней записи в блоге — это функция списка. Я планирую использовать там некоторые карты и интеллектуальные отчеты (например, скажите мне отчеты в пределах 10 миль), но сейчас я делаю простой список:
Я пропущу HTML для этого, так как это просто div, но вот посмотрим, как я получил эти данные:
var query = new Parse.Query(TipObject); query.find({ success: function(results) { var s = ''; for(var i=0, len=results.length; i<len; i++) { var result = results[i]; console.dir(result); s+= '<p>'; s+= '<b>ID:</b> '+ result.id + '<br/>'; s+= 'Created: ' + result.createdAt + '<br/>'; s+= 'Number of Cows: ' + result.attributes.numcows + '<br/>'; s+= 'How Dangerous?: ' + result.attributes.howdangerous + '<br/>'; s+= 'Comments: ' + result.attributes.comments; s+= '</p>'; } $("#tipdisplay").html(s); }, error: function(error) { alert("Error: " + error.code + " " + error.message); } });
Parse поддерживает очень подробные запросы и даже нумерацию страниц. Но сейчас я просто спрашиваю у службы обо всем и выкидываю ее на экран. Вместо этого я обычно использую шаблонизатор JavaScript, но поскольку он временный, он выполняет свою работу.
Обратите внимание, как каждый объект имеет идентификатор и автоматически создается. Мне не нужно беспокоиться об этом. Парс делает это. Он также отслеживает последнее обновленное значение.
Хотите поиграть с этим? Я обновил репозиторий GitHub с последним кодом. Да, и хотя я на самом деле не использую API PhoneGap, я решил создать приложение в PhoneGap Build:
https://build.phonegap.com/apps/215210/share
Обратите внимание, что хотя там есть ссылка для загрузки iOS, она будет работать только на моих устройствах. Если это приложение станет модным и если читатели захотят, чтобы я попробовал, я отправлю его в App Store и посмотрю, что произойдет. Обратите внимание, что это сборка с поддержкой Hydration. Это означает, что когда я обновляю приложение, я могу сказать PhoneGap Build автоматически создавать новые сборки из репозитория GitHub. Это не может быть проще.