LocalStorage strategy for user and message data - javascript

I am looking for a simple strategy to store user data, as well as messages. I was thinking of using different key values like some random token (Ynjk_nkjSNKJN) for users and some real ids (1,2,3) for messages.
Has anyone ever had that problem?
The reason is that I would like to keep localStorage always up to date with new messages from the server, but users should not be deleted during an update.
Thanks

You can handle "tables" in localStorage this way:
//columns should be an array of column literals
function createTable(tableName, columns) {
db[tableName] = {rows: {}, columns: columns};
}
function insertInto(tableName, row, id) {
var newRow = {};
for (var columnName in row) {
if (db[tableName].columns.indexOf(columnName) === -1) {
//invalid column
return false;
}
newRow[columnName] = row[columnName];
}
db[tableName].rows[id] = newRow;
return true;
}
function getIDs(tableName, where) {
var IDs = [];
for (var id in db[tableName].rows) {
if (where(db[tableName].rows[id])) {
IDs[IDs.length]=id;
}
}
return IDs;
}
function update(tableName, where, what) {
what(tableName, getIDs(tableName, where));
}
function deleteRecord(tableName, where) {
var removeIDs = getIDs(tableName, where);
for (var id in removeIDs) {
//Could be done by regexes, but I am not fluent with them and I am lazy to check them out
delete db[tableName].rows[removeIDs[id]];
}
}
function select(tableName, where) {
var IDs = getIDs(tableName, where);
var result = {};
for (var id in db[tableName].rows) {
result[id] = db[tableName].rows[id];
}
return result;
}
function dropTable(tableName) {
delete db[tableName];
}
You probably see that this is only a minimalistic implementation, but with the same approach you can implement altering, joins, grouping and so on. My focus here was just to illustrate how you can create a database. Let's go to the next step, storing the database into localStorage:
localStorage.setItem("db", JSON.stringify(db));
You will need to be able to convert back the local storage item to object, especially because you want to reuse your database even after reload. Let's see how you should initialize db:
var db = !!localStorage.getItem("db") ? angular.fromJson(localStorage.getItem("db")) : {};

Localstorage is a key-value store, which stores everything in string format. So, the messages will be identified by one key (e.g. "messages") and the users another key (e.g. "users").
Then you need to create 2 (angular) services one for the messages and one for the users. Both will interface with localstorage (using the respective keys) and will perform the operations that you want.
If you provide us with more information then we could help you a bit more.

Related

Setting and modifying array and pushing to localStorage creates nested array

I have a function that takes a string from a search field during runtime, and stores it to localstorage. Since we want to store all search strings from the end user to record it, we need to get the current data from localstorage, and add the latest search string.
Here is my code:
const setDatatoLocalStorag = (searchQuery: string) => {
let searchHistory = localStorage.getItem("searchHistory");
let searchQueryArr = [];
if (searchHistory) {
JSON.parse(searchHistory);
searchQueryArr.push(searchQuery, searchHistory);
} else {
searchQueryArr.push(searchQuery);
}
localStorage.setItem("searchHistory", JSON.stringify(searchQueryArr));
}
Lets assume we run the function twice, with the searchQuery "dog" and "cat". This is how it will look like in localstorage:
["cat","[\"dog\"]"]
I believe localstorage will get the item as string "[myData]" which will cause the error. How to properly handle this?
I have tried to follow How to store an array of objects in Local Storage? withous success.
The problem is you aren't assigning JSON.parse(searchHistory); to a variable. I think what you want to do is this:
var searchQueryArr = ['dog'];
localStorage.setItem("searchHistory", JSON.stringify(searchQueryArr));
var searchHistory = JSON.parse(localStorage.getItem("searchHistory") || '[]');
console.log(searchQueryArr, searchHistory);
Note I wasn't able to get this to work with the inline editor, but I did try it on a real server and it worked.
Make a setter/getter pair that hide the encoding/unencoding. Then add a higher-level push that does a get and a set...
// const pretend local storage, keys => strings
const myLocalStorage = {}
function mySetItem(key, value) {
// use the actual local storage setItem() here
myLocalStorage[key] = JSON.stringify(value);
}
function myGetItem(key) {
// use the actual local storage getItem() here
return JSON.parse(myLocalStorage[key]);
}
function myPush(key, value) {
let current = myGetItem(key);
current.push(value)
mySetItem(key, current)
}
// test
const key = 'myKey'
mySetItem(key, []);
myPush(key, { message: 'hello' })
myPush(key, { message: 'dolly' })
console.log(myGetItem(key))

How to use multiple callbacks when looping data

I'm trying to get HTML form data, loop it through, change it a bit and insert it to database. I have tried like below app.js.
How can I make callbacks so that formdata what I have modified is available for .create function?
I have searched from everywhere and I always end up in dead end and undefined variable somehow.
app.js:
//Find the day where to save
Day.findById(req.params.id, function(err, day) {
if (err) {
console.log(err);
res.redirect("/diary");
} else {
// Search function to find data with _id
function ingredientIdQuery(reqBodyId) {
var ingQuery = Ingredient.find({_id:reqBodyId});
return dbQuery;
}
// This loops through HTML formdata and formats it for mongoose model
for (var i = 0; i < req.body.amount.length; i++) {
if (req.body.amount[i] !== "") {
var amount = Number(req.body.amount[i]);
var singleMealTempObj = {};
singleMealTempObj.amount = amount;
var _id = req.body.id[i];
var query = ingredientIdQuery(_id);
// Executing the query for the data I need with id
query.exec(function(err, ingr){
if(err) {
return console.log(err);
} else {
singleMealTempObj.ingredient = ingr[0];
singleMealTempArr.push(singleMealTempObj);
}
});
}
}
}
// This inserts data into day
Meal.create(singleMealTempArr, function(err, singleMealObject) {
if (err) {
console.log(err);
} else {
day.meals.push(singleMealObject);
day.save();
res.redirect("/day/" + day._id + "/dayshow");
}
});
});
});
Edit:
Thanks for reply and notices! While I was trying to do everything to get this work I missed those few things like declaring variables. Sorry for that. I threw the towel in to the cage at this point.
flow goes like this:
User sends HTML form data to app.js which is inside object of two arrays (id[] and amount[]). Amount array needs to be looped through if it has value other than 0. Same index id array value is used to fetch data from database. This data what is found from database with id from id[] is used with same index amount[] and it should be saved to mongo.
I can get the values from HTML form ok. but I have tried to make a search in Mongo in a for loop (query.exec in the code) I get the data ok. When I log the data outside the database query, variable is undefined.
I hope this clarifys a bit what I'm trying to achieve.
I'll continue this later... :)
I guess issue originates because of this function.
function ingredientIdQuery(reqBodyId) {
var ingQuery = Ingredient.find({_id:reqBodyId});
return dbQuery;
}
Is find function asynchronous or synchronous?
Also you are returning dbQuery but dbQuery does not seem to be changed inside the function.
Couple I noticed that may fix this:
You never define singleMealTempArr, so when you try to push data to it, you are gonna run into problems.
Your ingredientIdQuery function returns dbquery - which also isn't defined. You actually call it ingQuery. Even so...are you positive that this will return the data that you want?
// lets loop through all the form fields in req.body.amount
for (var i = 0; i < req.body.amount.length; i++) {
// keep going unless the form field is empty
if (req.body.amount[i] !== "") {
// assign all the form fields to the following vars
var amount = Number(req.body.amount[i]);
var singleMealTempObj = {};
singleMealTempObj.amount = amount;
var _id = req.body.id[i];
var query = ingredientIdQuery(_id);
// we are executing the ingredientIdQuery(_id), better
// double-check that this query returns the result we are
// looking for!
query.exec(function(err, ingr){
if(err) {
return console.log(err);
} else {
singleMealTempObj.ingredient = ingr[0];
// now that we've gone through and mapped all the form
// data we can assign it to the singleMealTempArr
// WOOPS! Looks like we forgot to assign it!
singleMealTempArr.push(singleMealTempObj);
}
});
}
}
}

Amazon API call to get number of listed products on page

Is it possible to get count of listed products in an Amazon page?
I need to get this number. I know I can use javascript to get it by ID or class, but I know that amazon changes the values of IDs and classes in some period of time, so later on I wouldn't be able to get this number unless I check the ID or class by myself and change it in code.. So is there an API call or something to freely get this number, without changing code every time?
You need a combination of ItemSearch and the ResponseGroup BrowseNodes. It would be something like this if you were to use C# and pass the results back to your JavaScript app:
ItemSearchRequest request = new ItemSearchRequest();
request.ResponseGroup = new string[] { "BrowseNodes", "ItemAttributes" };
request.SearchIndex = "Movies";
request.Keywords = "game of thrones";
ItemSearch search = new ItemSearch();
search.AWSAccessKeyId = access_key_id;
search.AssociateTag = associate_tag;
search.Request = new ItemSearchRequest[] { request };
AWSECommerceServicePortTypeClient port = new AWSECommerceServicePortTypeClient("AWSECommerceServicePort");
port.ChannelFactory.Endpoint.EndpointBehaviors.Add(new AmazonSigningEndpointBehavior(access_key_id, secret_access_key));
ItemSearchResponse response = port.ItemSearch(search);
foreach (var items in response.Items)
{
foreach (var item in items.Item)
{
Console.WriteLine("{0}\t{1}\t{2}", item.ItemAttributes.Title, item.ASIN, item.ItemAttributes.Author[0]);
if (item.BrowseNodes != null)
{
Console.WriteLine(" - BrowseNodes");
foreach (var node in item.BrowseNodes)
{
Console.WriteLine(" -- \t{0}\t{1}\t{2}", node.TotalResults);
}
}
}
}
https://flyingpies.wordpress.com/2009/08/01/17/
https://docs.aws.amazon.com/AWSECommerceService/latest/DG/LocaleUS.html
https://docs.aws.amazon.com/AWSECommerceService/latest/DG/ItemSearch.html
https://docs.aws.amazon.com/AWSECommerceService/latest/DG/RG_BrowseNodes.html

Best practice to remove/kick the expired/oldest item in HTML5 localStorage?

Background
I am working on a MEAN stack project, which needs to store some data in browser's localStorage.
Since there is limitation on the capacity of localStorage(several megaBytes) and the data volumn is not predictable, I have to handle this problem.
Similar to this answer: make localStorage or sessionStorage expire like cookies [duplicate], I made some common functions for getting/setting items in localStorage. Every item contains an _expires field to indicate when the item will be expired. This filed will be checked when the getLocalStorageItem function is called, if expired, the item will be removed.
angular.module('ca.interaction').factory('CommonService', function() {
return {
// Check expired time before getting item from localStorage
getLocalStorageItem: function (name) {
var v = localStorage.getItem(name);
try {
if (v) {
var v2 = JSON.parse(v);
var now = new Date().getTime();
if (v2._expires && v2._expires >= now) {
return v2._val;
} else if (v2._expires && v2._expires < now) {
localStorage.removeItem(name);
return "";
} else {
return v;
}
} else {
return "";
}
} catch (e) {
return v;
}
},
// Set expire time when storing an item
saveLocalStorageItem: function (name, value, expires) {
var expiresDateTime = new Date().getTime() + expires;
localStorage.setItem( name, JSON.stringify({_val: value, _expires: expiresDateTime}) );
},
removeLocalStorageItem: function (name) {
localStorage.removeItem(name);
}
}
});
Problem
If the program stores items into localStorage in a high frequency and all of them are not expired yet, the capacity limitation will be exceed.
So my original idea is to implement a FIFO(First In First Out) mechanism: use a sorted queue data Structure to hold all the keys and their Creation time(keys are sorted by Creation time from oldest to youngest). When the localStorage is full and the program continue to store a new item, the oldest key will be kicked out of the queue and the item corresponding to the key will be removed from localStorage.
But I meet some technical difficulties:
How can I get all existing keys from localStorage? Because I may need to re-construct the queue when user refreshes browser and the program reloads. I read Storage API in MDN but no API can do this.
How can I know how much free space remaining in localStorage? Because before storing a new item, I need to do a calculation and know how many oldest items should be removed.
I am not sure if any existing library/framework can achieve this goal, please share your advice

Push object to empty array after condition is met

I've created a couple of services that grab data from a REST API. These services return objects with names, ids, and some unique keys pertaining to a foo or a bar name. I also have a service doing the same for businesses, also with names, ids, and what foo/bar is tied to that business.
Unfortunately, the data model for this is...not ideal. Rather than just showing which foo/bar is attached to that business, it has every single foo or bar for every single business with a published: true/false key/val pair.
What I'm attempting to do is grab the URL name, loop through my foo object, check to see if the name from the current URL and the data match, and if they do store that object in $scope.results. From here, I want to loop through my businesses object and check to see if its conditionData id matches that of the new $scope.results array's id. Once this condition is met, I want to store those businesses in a $scope.businesses array. As it stands right now, I'm getting all businesses returned, rather than just the ones that have the same id as the current $scope.results id. I suspect the issue is either a) I'm a noob (most likely) or b) the published: true/false is creating issues.
Thanks in advance for any help, let me know if I need to clarify anything else. I'm still pretty new to Angular and JS as a whole, so I'm not sure if how I'm attempting to do this is super optimal. I'm open to better ideas if anyone has any.
.controller('ResultsController', function($scope, $location, getData) {
$scope.businesses = [];
$scope.results = [];
var url = $location.path().split('/')[2]; // we do this because it's always going to follow a pattern of /:base/:name
function init() {
getData.getConditions().success(function(data) {
var tempCondition = data;
var tempData;
for (var condition in tempCondition) {
tempData = tempCondition[condition];
if (url === tempData.name) {
$scope.results = tempData;
}
}
})
.error(function(data, status, headers, config) {
console.log('err: ' + data);
});
getData.getBusinesses().success(function(data) {
var tempBusinesses = data,
tempConditionData;
for (var business in tempBusinesses) {
tempConditionData = tempBusinesses[business].conditionData;
for (var condition in tempConditionData) {
if (tempConditionData[condition].id === $scope.results.id) {
$scope.businesses.push(tempBusinesses[business]);
}
}
}
})
.error(function(data, status, headers, config) {
console.log('err: ' + data);
});
}
init();
});
I find myself using SO as a rubber duck most of the time, I figured it out basically as soon as I finished typing the question. It was due to the published: true/false key/val pair.
All I had to do was change
for (var condition in tempConditionData) {
if (tempConditionData[condition].id === $scope.results.id) {
$scope.businesses.push(tempBusinesses[business]);
}
}
to
for (var condition in tempConditionData) {
if (tempConditionData[condition].id === $scope.results.id && tempConditionData[condition].published === true ) {
$scope.businesses.push(tempBusinesses[business]);
}
}
The two http calls you are using may also be problematic as they depend one each other. what if the first calls takes some time, your second http call returns first.

Categories

Resources