I'm working with Ionic framework as part of an online course I'm taking to learn AngularJS and a great many other tools useful to a web developer. And, being the sort of advanced beginner type, I'm stuck. In this unit, we've learned to leverage local storage to persist data locally so we can get our favourite items even after the app is shut down. However, I have trouble getting that to work.
So here's what I've done:
The Failed Attempt
I can get data into local storage. And I can append data. I do this using this function:
$scope.favoriteData = $localStorage.getObject('favorites', '[]');
$scope.addFavorite = function (index) {
console.log('Current Favorites', $scope.favoriteData);
$scope.favoriteData = Object.keys($scope.favoriteData).map(function(k) { return $scope.favoriteData[k] });
console.log ($scope.favoriteData);
$scope.storeVar = $scope.favoriteData.push("'{id':" + index + '},');
console.log ($scope.favoriteData);
$localStorage.storeObject('favorites', $scope.favoriteData);
console.log('Added Favorite', $scope.favoriteData)
};
In local storage, this produces the following entry:
favorites: ["'{id':0},","'{id':1},"]
So far so good. However, this is useless. Because I need this object to have the following format:
favorites: [{'id':0}, {'id':1}]
and so on. Also, I should not be able to add duplicates. I have a kind of function for that elsewhere, but I am stuck on how to combine the two functions.
The function I have is this:
function (index) {
for (var i = 0; i < favorites.length; i++) {
if (favorites[i].id == index)
return;
}
favorites.push({
id: index
});
};
The problem with this is, I don't understand how it does what it does.
So please, help?
EDIT #1:
The Second Attempt
With the help of #Muli and #It-Z I'm working with the following code right now:
$scope.favoriteData = $localStorage.getObject('favorites', '[]');
$scope.addFavorite = function (index) {
console.log('Current Favorites', $scope.favoriteData);
$scope.favoriteData = Object.keys($scope.favoriteData).map(function(k) { return $scope.favoriteData[k] });
console.log ($scope.favoriteData);
for (var i = 0; i < favorites.length; i++) {
if (favorites[i].id == index) {
console.log ("Found duplicate id " + favorites[i].id);
return;
}
}
$scope.storeVar = $scope.favoriteData.push({id: index});
console.log ($scope.favoriteData);
$localStorage.storeObject('favorites', $scope.favoriteData);
console.log('Added Favorite', $scope.favoriteData)
};
However, this doesn't work because with a nonexistant key favorites, it doesn't work and gives me an error. So I need to implement a check if the key exists and if it doesn't, then it should create one. I've looked at this question, but it didn't work, mainly because I must use the following factory in services.jsto access local storage:
.factory('$localStorage', ['$window', function ($window) {
return {
store: function (key, value) {
$window.localStorage[key] = value;
},
get: function (key, defaultValue) {
return $window.localStorage[key] || defaultValue;
},
storeObject: function (key, value) {
$window.localStorage[key] = JSON.stringify(value);
},
getObject: function (key, defaultValue) {
return JSON.parse($window.localStorage[key] || defaultValue);
}
}
}])
So this is where I'm at right now. And I'm still stuck. Or again stuck. I don't know.
$localStorage handles serialization and deserialization for you so there's no need for $scope.favoriteData = $localStorage.getObject('favorites', '[]');
You can just call:
$scope.favoriteData = $localStorage.favoriteData || {/*Defaults object*/};
Same goes for saving data. use the dot notation.
Check the demo.
As for the duplicates: just handle them yourself like you would normally. when you're done call $localStorage.mySet = modifiedSet (modified set is standard JS object).
Note: this assumes you use ngStorage.
First of all, this line:
$scope.storeVar = $scope.favoriteData.push("'{id':" + index + '},');
Should be:
$scope.storeVar = $scope.favoriteData.push({id: index});
This is because in the original line you are pushing string into favoriteData while you wanted objects.
And if you want to check first for duplicates your can go with somthing like this:
$scope.favoriteData = $localStorage.getObject('favorites', []);
$scope.addFavorite = function (index) {
console.log('Current Favorites', $scope.favoriteData);
$scope.favoriteData = Object.keys($scope.favoriteData).map(function(k) { return $scope.favoriteData[k] });
console.log ($scope.favoriteData);
for (var i = 0; i < favorites.length; i++) {
if (favorites[i].id == index) {
console.log ("Found duplicate id " + favorites[i].id);
return;
}
}
$scope.storeVar = $scope.favoriteData.push({id: index});
console.log ($scope.favoriteData);
$localStorage.storeObject('favorites', $scope.favoriteData);
console.log('Added Favorite', $scope.favoriteData)
};
Related
I've been working on a project and I'm currently working on a function which dynamically creates a dictionary data structure. The key used is the roll number of the student, and the value is the student's name.
But I'm unable to iterate through this dictionary. I've tried displaying the dictionary on console, but all I could see is an empty dictionary. I could see the elements in it, only if I expand it further. And when I display length using Obj.length on console, it displays 'undefined'. I've read on other questions that Obj.length only works on arrays(i.e., enumerable types), and I've tried using an array instead of a dictionary. In that case, it shows an empty array and would not show values unless I manually expand it. I've also tried Obj.keys() method on the dictionary, and I've encountered the same issue.
This is the function's code:
function dictGenerator(rollnos, selectedValue) {
var dict = {};
for(let i = 0; i < rollnos.length; i++) {
get(child(dbref, "RegisterNos/" + rollnos[i])).then((snapshot)=>{
if(Object.keys(snapshot.val()).length-1 == selectedValue){
dict[rollnos[i]] = snapshot.val()["name"];
}
});
}
console.log(dict);
console.log(dict.length);
}
}
Any help on how I could iterate through my dictionary would be appreciated, Thank you.
Edit:
code implementation using promises.
function dictGenerator(regnos, selectedValue) {
const get_dict = async () => {
var dict = {};
for(let i = 0; i < regnos.length; i++){
get(child(dbref, "RegisterNos/" + regnos[i])).then((snapshot)=>{
if(Object.keys(snapshot.val()).length-1 == selectedValue){
dict[regnos[i]] = snapshot.val()["name"];
}
});
}
return dict;
};
get_dict().then((dict) => {
console.log(dict);
});
}
Basing on comments made by VALZ and JaredSmith, this is the working code:
function dictGenerator(regnos, selectedValue) {
const get_dict = async () => {
var dict = {};
for(let i = 0; i < regnos.length; i++){
await get(child(dbref, "RegisterNos/" + regnos[i])).then((snapshot)=>{
if(Object.keys(snapshot.val()).length-1 == selectedValue){
dict[regnos[i]] = snapshot.val()["name"];
}
});
}
return dict;
};
get_dict().then((dict) => {
console.log(dict);
});
}
}
I have an array in chrome local storage, format:
{"flights":
[
{"end":"2018-02-10","price":"476","start":"2018-02-01","tabId":1129367822},
{"end":"2018-02-11","price":"493","start":"2018-02-01","tabId":1129367825},
{"end":"2018-02-12","price":"468","start":"2018-02-01","tabId":1129367828}
]
}
Now I'm updating all data this way:
function updateValue(index, item) {
chrome.storage.local.get(['flights'], function (response) {
response.flights[index] = item;
chrome.storage.local.set({flights: response.flights});
});
}
But there is problem with async requests, because I have several request at the time. Some requests get old data and save it again in storage...
I want to update only specified element (for example flights[0] with new data), but it doesn't work...
Something like this, but workable:
chrome.storage.local.set({flights[0]: item});
Is there any way to do this? Or maybe you have some advices to resolve this issue other way.
many thanks for any help
Based on terales' answer (that code has some errors).
I make it this way:
function parseFlight(result) {
let flightsArray = [];
Object.keys(result).forEach(function (key) {
if (key.includes('flight')) {
let index = key.replace('flight_', '');
flightsArray[index] = result[key];
}
});
return flightsArray;
}
function updateValue(index, item) {
let flightPrefix = 'flight_';
let obj = {};
obj[flightPrefix + index] = item;
chrome.storage.local.set(obj);
}
chrome.storage.local.get(null, function (result) {
let flights = parseFlight(result);
});
Thanks for help!
You can save each flight into a separate key and get all flights by traversing all storage:
cosnt flightPrefix = 'flight_';
function updateValue(index, item) {
chrome.storage.local.set({flightPrefix + index: item});
}
function getFlights() {
// Pass in null to get the entire contents of storage.
chrome.storage.sync.get(null, function(items) {
let flights = Object.keys(items).filter(key => key.beginsWith(flightPrefix));
console.log(flights);
});
}
Im not getting how remove chrome.storage.local values in javascript?
i use like this but the storage value is not removing from the store:chrome.storage.local.remove(result.MyFile.Base64File);
Please check the below code, here I'm using chrome.storage.local.set to set
var obj = { DocName: "name", Base64File: "Base64string" };
chrome.storage.local.set({ 'MyFile': obj });
and chrome.storage.local.get to retrive the values
chrome.storage.local.get('MyFile', function (result) {
var PdfBase64 = result.MyFile.Base64File;
var DocumentName = result.MyFile.DocName;
}
Note: You can not remove values, you can remove indexes with specific names what causes that they gets removed WITH there values.
Tbh I could not run the code but I'm pretty sure something like this should work. But I really recommend you to avoid chrome.storage because it's some kind of "dumb" :)
So please have a look at this code:
function clearItem(symbol) {
var remove = [];
chrome.storage.sync.get(function(Items) {
$.each(Items, function(index, value) {
if (index == "symbol") remove.push(index);
});
chrome.storage.sync.remove(remove, function(Items) {
chrome.storage.sync.get(function(Items) {
$.each(Items, function(index, value) {
console.log("removed: " + index);
});
});
});
});
};
In my dashboard application am using elastic search to retrieve data, which retrieves data fine. Now i need to iterate over the data and get the result in the required way.
Here is my code,
routerApp.controller('SearchCtrl', function($scope, ejsResource) {
var ejs = ejsResource('http://192.168.1.200:9200');
var oQuery = ejs.QueryStringQuery().defaultField('Agent');
var client = ejs.Request()
.indices('nondomain_callrelatedinfo')
.types('callrelatedinfos');
$scope.search = function() {
$scope.results = client
.query(oQuery.query($scope.queryTerm || '*'))
.doSearch();
console.log($scope.results);
};
});
I have added a console.log in the results and it reuturns something like this,
Data:
when i iterate over hits, it says cannot read property of "hits" undefined
$scope.dataRetrieved= $scope.results.value.hits;
for (var i = 0; i < $scope.dataRetrieved.length; i++) {
console.log($scope.dataRetrieved[i]);
};
};
You should use the Promise object that the doSearch() returns :
client
.query(oQuery.query($scope.queryTerm || '*'))
.doSearch().then(function (resp) {
var hits = resp.hits.hits;
// do whatever
}, function (err) {
console.trace(err.message);
});
Knowing angular, if you want to bind the result to $scope.result maybe a $timeout(function() {}) could also help.
https://docs.angularjs.org/api/ng/function/angular.forEach
just nest your forEach:
angular.forEach(results, function(result, key) {
angular.forEach(result, function(value, key) {
this.push(key + ': ' + value);
}, log);
}, log);
$scope.results.hits.hits;
$scope.dataRetrieved= $scope.results.hits.hits;
for (var i = 0; i < $scope.dataRetrieved.length; i++) {
console.log($scope.dataRetrieved[i]);
};
};
the first hits is a object the second is your array. thats why the first hits has no property length
When fetching an item from a DOJO datastore, DOJO adds a great deal of extra fields to it. It also changes the way the data is structure.
I know I could manually rebuild ever item to its initial form (this would require me to make updates to both JS code everytime i change my REST object), but there certainly has to be a better way.
Perhaps a store.detach( item ) or something of the sort?
The dojo.data API is being phased out, partly because of the extra fields. You could consider using the new dojo.store API. The store api does not add the extra fields.
I have written a function that does what you are looking to do. It follows. One thing to note, my function converts child objects to the { _reference: 'id' } notation. You may want different behavior.
Util._detachItem = function(item) {
var fnIncludeProperty = function(key) {
return key !== '_0'
&& key !== '_RI'
&& key !== '_RRM'
&& key !== '_S'
&& key !== '__type'
};
var store = item._S;
var fnCreateItemReference = function(itm) {
if (store.isItem(itm)) {
return { _reference: itm.id[0] };
}
return itm;
};
var fnProcessItem = function(itm) {
var newItm = {};
for(var k in itm) {
if(fnIncludeProperty(k)) {
if (dojo.isArray(itm[k])) {
// TODO this could be a problem with arrays with a single item
if (itm[k].length == 1) {
newItm[k] = fnCreateItemReference(itm[k][0]);
} else {
var valArr = [];
dojo.forEach(itm[k], function(arrItm) {
valArr.push(fnCreateItemReference(arrItm));
});
newItm[k] = valArr;
}
} else {
newItm[k] = fnCreateItemReference(itm[k]);
}
}
}
return newItm;
};
return fnProcessItem(item);
};
NOTE: this function is modified from what I originally wrote and I did not test the above code.