I'm following the Progressive Web App lab from Google and it says that it's using localStorage for simplicity but that we should change it to idb.
Basically, we want to store a list of cities to display their weather information.
I tried using plain idb following the info here but I think I'm too new to this and I couldn't get any of this. Am I supposed to do:
const dbPromise = idb.open('keyval-store', 1, upgradeDB => {
upgradeDB.createObjectStore('keyval');
});
and would keyval be the name of my variable where I would use keyval.get() or keyval.set() to get and store values?
I decided to move on to the simpler idbKeyval, I'm doing:
app.saveSelectedCities = function() {
var selectedCities = JSON.stringify(app.selectedCities);
idbKeyval.set(selectedCities);
};
instead of the localStorage example:
app.saveSelectedCities = function() {
var selectedCities = JSON.stringify(app.selectedCities);
localStorage.selectedCities = selectedCities;
};
and
app.selectedCities = idbKeyval.keys().then(keys => console.log(keys)).catch(err => console.log('It failed!', err));
instead of the localStorage example:
app.selectedCities = localStorage.selectedCities;
But my app is not loading any data, and in the developer tools console, I get:
app.js:314 Uncaught ReferenceError: idbKeyval is not defined(…)
I'm sure I'm missing something trivial but these are my first steps with javascript and the likes, so please, any help with any of the points touched here would be greatly appreciated!
Given the error you're seeing, it looks like you've forgotten to include the idb-keyval library.
I too was going through this, and wanted it to work with localForage. Took a bit, because I'm new to it too, but here is what I used for the save and load functions which made it all work.
// TODO add saveSelectedCities function here
// Save list of cities to localStorage
app.saveSelectedCities = function() {
var selectedCities = JSON.stringify(app.selectedCities);
localforage.setItem('selectedCities', selectedCities);
//localStorage.selectedCities = selectedCities;
}
localforage.getItem('selectedCities').then(function(cityList) {
app.selectedCities = cityList;
app.selectedCities.forEach(function(city) {
app.getForecast(city.key, city.label);
});
}).catch(function(err) {
app.updateForecastCard(initialWeatherForecast);
app.selectedCities = [
{key: initialWeatherForecast.key, label: initialWeatherForecast.label}
];
app.saveSelectedCities();
});
Related
Given the following localStorage code (jsfiddle) :
// my new information
var data = {character: "中", totalMistakes: 0};
var han = data.character;
// create localStorage; Unpack, update, repackage knol
/* **** THIS IS THE SECTION TO CONVERT **** */
localStorage.knol = '{}'; // create pseudo object, as string
var knol = JSON.parse(localStorage.knol)
knol[han] = data;
localStorage.knol = JSON.stringify(knol);
// Print to check if all went well.
console.log('data: ',data)
console.log('han: ',han)
console.log('knol: ',knol)
console.log('localStorage.knol: ',localStorage.knol)
console.log('localStorage.knol: ',JSON.parse(localStorage.knol))
console.log('localStorage.knol[han]: ',JSON.parse(localStorage.knol)[han])
At the end, localStorage.knol is :
{
"中": {character: "中", totalMistakes: 0}
}
I'am looking for a Mongo-like js library to store data on client side indexedDB, with a syntax similar to MongoDB with which I'am already familiar.
How to convert localStorage code above into Mongo-like IndexedDB library syntax so to store an object ?
EDIT: I suggest minimongo, but any MongoDB-like library storing in indexedDB will do.
There is a variety of librairies available to do that.
Dexie.js
Using Dexie.js and its API (jsfiddle) :
<!-- Include dexie.js -->
<script src="https://unpkg.com/dexie#latest/dist/dexie.js"></script>
<script>
var db = new Dexie('MyDatabase');
// Define a schema
db.version(1).stores({ knol: 'character, totalMistakes' });
// Open the database
db.open().catch(function(error) { alert('Uh oh : ' + error); });
// or make a new one
db.knol.put({ character: '中', totalMistakes: 8 });
// Find some old friends
var mistakes = db.knol.where('totalMistakes');
//mistakes.above(6).each (function (item) { console.log (item); });
mistakes.aboveOrEqual(0).each (function (item) { console.log (item)});
</script>
Minimongo
I don't recommend it, but there is how to use it in web browsers
ZangoDB
(Exploration ongoing https://jsfiddle.net/vb92pecv/3/ )
I'm trying to scrape a webpage, and save the data to Firebase. I can console.log the data, but I can't get it to save. At first I thought the tabletojson function took a second to grab the data, so I decided to put the Firebase part where I save data into a separate function.
When I run this in the terminal, the console.log doesn't appear because something is going wrong with saving the data to Firebase. Any ideas on how to fix this script?
var tabletojson = require('tabletojson');
var Firebase = require('firebase')
var url = 'https://en.wikipedia.org/wiki/List_of_sovereign_states#List_of_states';
tabletojson.convertUrl(url, function(tablesAsJson) {
var listofSovereignStates = tablesAsJson[0];
sendToFirebase(listofSovereignStates)
});
function sendToFirebase(data) {
dataRef = new Firebase("https://mikesweather.firebaseio.com/flags")
dataRef.set(data)
console.log(data)
}
Try this:
function sendToFirebase(data) {
var dataRef = new Firebase("https://mikesweather.firebaseio.com/flags")
dataRef.set({myData: data})
console.log(data)
}
Per the example below you can see that you need to pass in an object to set:
dataRef.set({
alanisawesome: {
date_of_birth: "June 23, 1912",
full_name: "Alan Turing"
}
});
https://www.firebase.com/docs/web/guide/saving-data.html
Edit, after thinking about it, it is possible this is not the solution, let me know if this works...
I am trying to follow a tutorial on lynda.com which uses angularfire (angularjs firebase) except it uses stuff like $firebase.$asObject and such, which is now obsolete. I tried to look at the documentation as well as some other SOF questions, and I finally found something that worked, but it looks ugly and seems quite inefficient since the only way I found for it to work is to iterate through all the objects in an array returned from the database. This array holds all the users which are registered. This is how I got it to work, but can someone tell me the correct way to do it, because this does not seem like it should be it.
var ref = new Firebase(FIREBASE_URL);
var auth = firebaseAuth(ref);
auth.$onAuth(function(authUser){
if(authUser){
var ref = new Firebase(FIREBASE_URL + 'users/');
var stuff = firebaseArray(ref);
ref.on('value', function(snapshot) {
if(snapshot.val() !== null) {
var keys = Object.keys(snapshot.val());
for(var key in keys){
if(keys.hasOwnProperty(key)){
if(authUser.uid === snapshot.val()[keys[key]].registeredUser){
rootScope.currentUser = snapshot.val()[keys[key]];
}
}
}
} else {
console.log('location does not exist');
}
});
var user = firebaseObject(ref);
//console.log(user);
rootScope.currentUser = user;
} else {
rootScope.currentUser = '';
}
});
Here is what my firebase forge looks like:
Thank you in advance!
It is usually helpful to store user data like proposed in https://www.firebase.com/docs/web/guide/user-auth.html#section-storing.
You need to use the unique ID as the key for the user object, so you don't have to iterate over all users to search for it. The unique ID is part of the auth data, see https://www.firebase.com/docs/web/guide/user-auth.html#section-monitoring-authentication).
I'm trying to convert my basic crud operations into an API that multiple components of my application can use.
I have successfully converted all methods, except the update one because it calls for each property on the object to be declared before the put request can be executed.
controller
$scope.update = function(testimonial, id) {
var data = {
name: testimonial.name,
message: testimonial.message
};
dataService.update(uri, data, $scope.id).then(function(response) {
console.log('Successfully updated!');
},
function(error) {
console.log('Error updating.');
});
}
dataService
dataService.update = function(uri, data, id) {
var rest = Restangular.one(uri, id);
angular.forEach(data, function(value, key) {
// needs to be in the format below
// rest.key = data.key
});
// needs to output something like this, depending on what the data is passed
// rest.name = data.name;
// rest.message = data.message;
return rest.put();
}
I tried to describe the problem in the codes comments, but to reiterate I cannot figure out how to generate something like rest.name = data.name; without specifying the name property because the update function shouldn't need to know the object properties.
Here is what the update method looked like before I started trying to make it usable by any of my components (this works)
Testimonial.update = function(testimonial, id) {
var rest = Restangular.one('testimonials', id);
rest.name = testimonial.name;
rest.message = testimonial.message;
return rest.put();
}
How can I recreate this without any specific properties parameters hard-coded in?
Also, my project has included lo-dash, if that helps, I don't know where to start with this problem. Thanks a ton for any advice!
Try like
angular.extend(rest,testimonial)
https://docs.angularjs.org/api/ng/function/angular.extend
I have a Single Page Application that is working pretty well so far but I have run into an issue I am unable to figure out. I am using breeze to populate a list of projects to be displayed in a table. There is way more info than what I actually need so I am doing a projection on the data. I want to add a knockout computed onto the entity. So to accomplish this I registered and entity constructor like so...
metadataStore.registerEntityTypeCtor(entityNames.project, function () { this.isPartial = false; }, initializeProject);
The initializeProject function uses some of the values in the project to determine what the values should be for the computed. For example if the Project.Type == "P" then the rowClass should = "Red".
The problem I am having is that all the properties of Project are null except for the ProjNum which happens to be the key. I believe the issue is because I am doing the projection because I have registered other initializers for other types and they work just fine. Is there a way to make this work?
EDIT: I thought I would just add a little more detail for clarification. The values of all the properties are set to knockout observables, when I interrogate the properties using the javascript debugger in Chrome the _latestValue of any of the properties is null. The only property that is set is the ProjNum which is also the entity key.
EDIT2: Here is the client side code that does the projection
var getProjectPartials = function (projectObservable, username, forceRemote) {
var p1 = new breeze.Predicate("ProjManager", "==", username);
var p2 = new breeze.Predicate("ApprovalStatus", "!=", "X");
var p3 = new breeze.Predicate("ApprovalStatus", "!=", "C");
var select = 'ProjNum,Title,Type,ApprovalStatus,CurrentStep,StartDate,ProjTargetDate,CurTargDate';
var isQaUser = cookies.getCookie("IsQaUser");
if (isQaUser == "True") {
p1 = new breeze.Predicate("QAManager", "==", username);
select = select + ',QAManager';
} else {
select = select + ',ProjManager';
}
var query = entityQuery
.from('Projects')
.where(p1.and(p2).and(p3))
.select(select);
if (!forceRemote) {
var p = getLocal(query);
if (p.length > 1) {
projectObservable(p);
return Q.resolve();
}
}
return manager.executeQuery(query).then(querySucceeded).fail(queryFailed);
function querySucceeded(data) {
var list = partialMapper.mapDtosToEntities(
manager,
data.results,
model.entityNames.project,
'ProjNum'
);
if (projectObservable) {
projectObservable(list);
}
log('Retrieved projects using breeze', data, true);
}
};
and the code for the partialMapper.mapDtosToEntities function.
var defaultExtension = { isPartial: true };
function mapDtosToEntities(manager,dtos,entityName,keyName,extendWith) {
return dtos.map(dtoToEntityMapper);
function dtoToEntityMapper(dto) {
var keyValue = dto[keyName];
var entity = manager.getEntityByKey(entityName, keyValue);
if (!entity) {
extendWith = $.extend({}, extendWith || defaultExtension);
extendWith[keyName] = keyValue;
entity = manager.createEntity(entityName, extendWith);
}
mapToEntity(entity, dto);
entity.entityAspect.setUnchanged();
return entity;
}
function mapToEntity(entity, dto) {
for (var prop in dto) {
if (dto.hasOwnProperty(prop)) {
entity[prop](dto[prop]);
}
}
return entity;
}
}
EDIT3: Looks like it was my mistake. I found the error when I looked closer at initializeProject. Below is what the function looked like before i fixed it.
function initializeProject(project) {
project.rowClass = ko.computed(function() {
if (project.Type == "R") {
return "project-list-item info";
} else if (project.Type == "P") {
return "project-list-item error";
}
return "project-list-item";
});
}
the issue was with project.Type I should have used project.Type() since it is an observable. It is a silly mistake that I have made too many times since starting this project.
EDIT4: Inside initializeProject some parts are working and others aren't. When I try to access project.ProjTargetDate() I get null, same with project.StartDate(). Because of the Null value I get an error thrown from the moment library as I am working with these dates to determine when a project is late. I tried removing the select from the client query and the call to the partial entity mapper and when I did that everything worked fine.
You seem to be getting closer. I think a few more guard clauses in your initializeProject method would help and, when working with Knockout, one is constantly battling the issue of parentheses.
Btw, I highly recommend the Knockout Context Debugger plugin for Chrome for diagnosing binding problems.
Try toType()
You're working very hard with your DTO mapping, following along with John's code from his course. Since then there's a new way to get projection data into an entity: add toType(...) to the end of the query like this:
var query = entityQuery
.from('Projects')
.where(p1.and(p2).and(p3))
.select(select)
.toType('Project'); // cast to Project
It won't solve everything but you may be able to do away with the dto mapping.
Consider DTOs on the server
I should have pointed this out first. If you're always cutting this data down to size, why not define the client-facing model to suit your client. Create DTO classes of the right shape(s) and project into them on the server before sending data over the wire.
You can also build metadata to match those DTOs so that Project on the client has exactly the properties it should have there ... and no more.
I'm writing about this now. Should have a page on it in a week or so.