За последние несколько месяцев у меня была серия статей ( часть 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». Я полагаю, что мог бы справиться с каждой частью лучше. ?
