Статьи

AngularJS IndexedDB Demo

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