I am using amplify.js with Knockout.js and I want to store data locally. I tried using this code: amplify guide
but it isn't working for me.
My view model
define(['services/datacontext'], function (dataContext) {
var store = amplify.store("offlineData"); // Why is agency undefined after retrieving from the store?!?!?!
var agency = ko.observableArray([]);
var initialized = false;
var save = function (agency) {
return dataContext.saveChanges(agency);
};
var vm = { // This is my view model, my functions are bound to it.
//These are wired up to my agency view
activate: activate,
agency: agency,
title: 'agency',
refresh: refresh, // call refresh function which calls get Agencies
save: save
};
return vm;
function activate() {
if (initialized) {
return;
}
initialized = true;
if (initialized == true) {
amplify.store("offlineData", vm.agency);
}
return refresh();
}
function refresh() {
return dataContext.getAgency(agency);
}
});
After refresh retrieves the data, I save this data to the local store. So when I make another request for this page. I would expect var store to contain this data but it is undefined.
Does anyone know how to use amplify?
amplify.store("offlineData", vm.agency);
vm.agency is a function, therefore you need to invoke it to get its value
amplify.store("offlineData", vm.agency());
Related
The angularjs guide contains an example detailing an async call in a service.
The following code is given
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
var currencies = ['USD', 'EUR', 'CNY'];
var usdToForeignRates = {};
var convert = function(amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr];
};
var refresh = function() {
var url = 'https://api.exchangeratesapi.io/latest?base=USD&symbols=' + currencies.join(",");
return $http.get(url).then(function(response) {
usdToForeignRates = response.data.rates;
usdToForeignRates['USD'] = 1;
});
};
refresh();
return {
currencies: currencies,
convert: convert
};
}]);
Since the refresh function is async, how does angularjs ensure that the data is loaded before loading the controller which accesses the data returned by the refresh function, ie the data contained in the usdToForeignRates object.
I assume there is some blocking going on somewhere, otherwise when the controller accesses the object returned, it will get undefined values.
I want to understand the flow, does angular internally ensure that service loads before injecting it into the controller?
I am currently develloping a little app with angularJS;
the users have to go through a login form and then they can click on a few links who display data fetched from a server.
The login form only takes the user's input and it is then "stored" into a factory
app.factory('IdFormHolder', function () {
var that = this;
that.setId = function (data) {
that = data;
};
that.getId = function () {
return that;
};
return that;
});
Which works fine I need to keep it stored because the server requires the login form to be sent each time I do a $http.get as a header.
Each controller takes the login form from the factory and uses it to get the data from the server.
This works fine until someone decides to refresh the page, at which point it seems the factory is "emptied" from its login form, and the web-app then fails to show anything.
Is there a way to store this login info so that it doesn't get erased so easily ?
You can use this code after youve installed sessionStorage:
app.factory('IdFormHolder', ['$sessionStorage', function ($sessionStorage) {
var that = this;
that.setId = function (data) {
$sessionStorage.id = data;
that = data;
};
that.getId = function () {
return $sessionStorage.id;
};
return that;
}]);
Download Link: https://github.com/gsklee/ngStorage
In order to persist data you'd have to use some kind of local DB || LocalStorage || SessionStorage at least. When initializing the Factory you could check and attempt to retrieve from DB/LS that data and hold it as a variable if it does exist.
Something like
app.factory('IdFormHolder', function () {
this.heldId = attemptToGetSavedDataFromSomewhere(); // would be null otherwise
this.setId = (id) => {
this.heldId = id;
};
this.getId = () => this.heldId;
return this;
});
Using angular-local-storage you can access to the browsers local storage:
app.factory('IdFormHolder', function(localStorageService) {
return {
setId: function(data) {
return localStorageService.set('loggedUserData', data);
},
getId: function() {
return localStorageService.get('loggedUserData');
}
};
});
I'm trying to implement nested Collections exactly like the example I found here: https://stackoverflow.com/a/17453870/295133
The only difference being is that I'm trying to store the data locally using the localStorage plugin.
Here, my Lists would be the Hotels in the example above:
var app = app || {};
(function (){
'use strict';
// List Collection - list of words
//---------------------
var listCollection = Backbone.Collection.extend({
//referebce to this collection's model
model: app.ListModel,
localStorage: new Backbone.LocalStorage('translate-lists')
});
app.listCollection = new listCollection();
})();
(function (){
'use strict';
app.ListModel = Backbone.Model.extend({
initialize: function() {
// because initialize is called after parse
_.defaults(this, {
words: new app.wordCollection
});
},
parse: function(response) {
if (_.has(response, "words")) {
this.words = new app.wordCollection(response.words, {
parse: true
});
delete response.words;
}
return response;
}
});
})();
What the localStorage does is stores the ListModels, but if I add anything to the words collection it soon disappears after I refresh.
Any ideas how I should be saving the entire nested collection?
So got this working and it came down to something in parse but also if you want to ensure you just get the attributes out of your nested collection you should override the toJSON otherwise you get the full collection in what this returns.
Backbone.Model.prototype.toJSON = function() {
var json = _.clone(this.attributes);
for (var attr in json) {
if ((json[attr] instanceof Backbone.Model) || (json[attr] instanceof Backbone.Collection)) {
json[attr] = json[attr].toJSON();
}
}
return json;
};
The main thing that was breaking is in the parse. Is assigns words directly to the model,
this.words = new app.wordCollection(response.words, {
parse: true
});
but this means that it will not show up when toJSON is called as it is not in the attributes (it also means you can't access it via model.get)
so this should be changed to
initialize: function () {
// because initialize is called after parse
_.defaults(this.attributes, {
words: new app.WordCollection()
});
},
parse: function (response) {
if (_.has(response, "words")) {
this.attributes.words = new app.WordCollection(response.words, {
parse: true
});
delete response.words;
}
return response;
}
this way it is added to the attributes of the model on not directly on the model. If you look at this fiddle http://jsfiddle.net/leighking2/t2qcc7my/ and keep hitting run it will create a new model in the collection, save it in local storage then print the results to the console. each time you hit run you should see it grow by 1 (as it gets the previous results local storage) and contain the full information that you want.
I'm having some troubles with services in angular.
Basically I have a service that I use as a constant class for user specific parameters, I store these in variables that read the values from a cookie.
This is my service:
shoutApp.service('userConfig', function (userService, config) {
this.USER_ID = $.cookie('shoutUserObj')._id;
this.USER_USERNAME = $.cookie('shoutUserObj').username;
this.USER_PASSWORD = $.cookie('shoutUserObj').password;
this.USER_JOINDATE = $.cookie('shoutUserObj').joinDate;
this.USER_TWITTER = $.cookie('shoutUserObj').twitter;
this.USER_FACEBOOK = $.cookie('shoutUserObj').facebook;
this.USER_GOOGLE = $.cookie('shoutUserObj').google;
this.refreshUserObj = function (callback) {
console.log("Starting refresh");
//This function retrieves new user data
userService.requestUserObj($.cookie('shoutUserObj')._id, function (code, userObj) {
if (code === config.CODE_AJAX_SUCCESS) {
//Here I delete the old cookie and set a new one with the same name
$.removeCookie('shoutUserObj');
$.cookie.json = true;
$.cookie('shoutUserObj', userObj, { path: '/', expires: 7 });
//When I log the new values of the cookie at this point they changed
}
});
}
});
I also tried storing these in an object, but every time I change the paramters they only change inside the class ( Like when i log out the new variables in my refresh function, they changed, but when I try to access them from a controller through the return values, they are not changed).
Example Controller:
shoutApp.controller('profileController', function ($scope, config, userConfig) {
console.log("Username: " + userConfig.USER_USERNAME);
//This value allways stays the same, even when I changed the cookie
});
My goal is to get the changed paramteres in all my Controllers that use the user service, how can I achieve this?
Would be really thankful for any help!
Services are singletons, therefore the values of your userConfig properties will always have the values they had when the service was initialized.
In the service, use a function if you want to retrieve a new value each time
this.getUSER_USERNAME = function() {
return $.cookie('shoutUserObj').username;
}
instead of a property
this.USER_USERNAME = $.cookie('shoutUserObj').username;
then the example controller would be:
shoutApp.controller('profileController', function ($scope, config, userConfig) {
console.log("Username: " + userConfig.getUSER_USERNAME());
//This will return the current value of the cookie
});
I'm working on a controller that reloads data when data is received from a websocket. I've got it working up to the point of reloading the data. I'm not sure why this isn't working, but I'm getting an error when I call self.get('contact').reload(); below. 'object has no method reload'. I'm pretty sure I'm calling this incorrectly, but I'm not sure how to reload the data from the store. Could someone help me out?
CallMonitor.ContactsRoute = Ember.Route.extend({
model: function(){
return this.store.find('contact');
},
setupController: function(controller, contacts) {
var socket = io.connect('http://localhost:3000');
controller.set('socket', socket);
controller.set('contact', contacts);
}
});
CallMonitor.ContactsController = Ember.ArrayController.extend({
socketDidChange: function(){
var socket = this.get('socket'),
self = this;
if(socket)
{
socket.on('call', function (data) {
var contactToUpdate = self.contact.filter(function(item) {
return item.id == data.contactId;
});
if(contactToUpdate.length)
{
contactToUpdate.reload();
}
else
{
// reload all the contacts
self.get('contact').reload();
}
});
}
}.observes('socket')
});
I ended up just doing another fetch from the store and then setting the controller's contact property again. Couldn't find an easy way to do a reload for multiple records. For single records, it's easy to just do a "reload()" but for new records and such it's apparently not that easy.
var contactPromise = self.contact.store.find('contact');
contactPromise.then(function(data){
self.set('contact', data);
}, undefined);
Kind of a bummer. Also couldn't find a good way to remove records in ember data.