За последние несколько месяцев у меня была серия статей ( часть 1 , часть 2 , часть 3 ), обсуждающих IndexedDB. В прошлой статье я создал полное, хотя и довольно простое приложение, позволяющее писать заметки. (Я любитель делать заметки для приложений.) Когда я создавал приложение, я намеренно не использовал фреймворк. Конечно, я пытался написать хороший, понятный код, но хотел избежать всего, что не было на 100% необходимым для демонстрации приложения и IndexedDB. С точки зрения статьи, я думаю, что это было правильное решение. Я хотел, чтобы мои читатели сосредоточились на этой функции, а не на чем-то еще. Но я подумал, что это будет отличная возможность снова попробовать AngularJS.
По большей части это преобразование работало отлично. Это может звучать глупо, но я обнаружил, что ухмыляюсь, когда создавал это приложение. Я твердо верю, что если что-то делает тебя счастливым, это, вероятно, полезно для тебя. ?
Я все еще чувствую себя немного … не смущенным … но замедленным из-за системы модулей и внедрения зависимостей. Обе эти вещи я понимаю в целом, но в AngularJS они чувствуют себя немного неловко. Такое ощущение, что я никогда не смогу кодировать из памяти, но мне нужно будет ссылаться на старые приложения, чтобы напомнить мне. Я не говорю, что они не правы, конечно, они просто пока не чувствуют себя естественными для меня.
С другой стороны, поддержка переплета невероятна. Я люблю работать с шаблонами HTML и $ scope. Это невероятно мощно. Черт, возможность добавить поле ввода и использовать его в качестве фильтра примерно за 30 секунд была просто невероятной.
Одна проблема, с которой я столкнулся, и я не уверен, что создал лучшее решение — это асинхронная природа открытой логики IndexedDB. AngularJS имеет встроенную библиотеку обещаний, и она работает невероятно хорошо для моего приложения в целом. Но мне нужно было, чтобы все приложение было загружено до асинхронного вызова для запуска базы данных. Я обошел это с двумя вещами, которые походили на взлом.
Во-первых, мой домашний просмотр (все записи) запустил вызов функции init, чтобы убедиться, что БД уже открыта. Итак, рассмотрим этот init ():
function init() { var deferred = $q.defer(); if(setUp) { deferred.resolve(true); return deferred.promise; } var openRequest = window.indexedDB.open("indexeddb_angular",1); openRequest.onerror = function(e) { console.log("Error opening db"); console.dir(e); deferred.reject(e.toString()); }; openRequest.onupgradeneeded = function(e) { var thisDb = e.target.result; var objectStore; //Create Note OS if(!thisDb.objectStoreNames.contains("note")) { objectStore = thisDb.createObjectStore("note", { keyPath: "id", autoIncrement:true }); objectStore.createIndex("titlelc", "titlelc", { unique: false }); objectStore.createIndex("tags","tags", {unique:false,multiEntry:true}); } }; openRequest.onsuccess = function(e) { db = e.target.result; db.onerror = function(event) { // Generic error handler for all errors targeted at this database's // requests! deferred.reject("Database error: " + event.target.errorCode); }; setUp=true; deferred.resolve(true); }; return deferred.promise; }
Эта логика похожа на ту, что была у меня в не-фреймворковом приложении, но я использовал обещания и флаг, чтобы помнить, когда я уже открыл базу данных. Это позволяет мне затем связываться с init () в моей логике getNotes.
function getNotes() { var deferred = $q.defer(); init().then(function() { var result = []; var handleResult = function(event) { var cursor = event.target.result; if (cursor) { result.push({key:cursor.key, title:cursor.value.title, updated:cursor.value.updated}); cursor.continue(); } }; var transaction = db.transaction(["note"], "readonly"); var objectStore = transaction.objectStore("note"); objectStore.openCursor().onsuccess = handleResult; transaction.oncomplete = function(event) { deferred.resolve(result); }; }); return deferred.promise; }
Все это работало нормально — но я столкнулся с проблемой на других страницах моего приложения. Например, если вы добавили в закладки ссылку для редактирования заметки, вы столкнетесь с ошибкой. Я мог бы применить такое же исправление в своем слое обслуживания (сначала запустите init), но это было просто неправильно. Поэтому вместо этого я сделал это в моем app.js:
$rootScope.$on("$routeChangeStart", function(event,currentRoute, previousRoute){ if(!persistanceService.ready() && $location.path() != '/home') { $location.path('/home'); }; });
Вызов готов был просто оболочкой для переменной flag. Так что да, это сработало для меня, но я все еще думаю, что есть (вероятно) более хорошее решение. В любом случае, если вы хотите проверить это, просто нажмите ссылку Демо ниже. Я хочу поблагодарить Шарон ДиОрио за помощь, советы и поддержку во время создания этого приложения.
PS Я предполагаю, что это очевидно, но я не предлагаю это как приложение AngularJS «Best Practices». Я полагаю, что мог бы справиться с каждой частью лучше. ?