I have a model which keeps some other models in an attribute array. When these models are stored, however, I don't want to keep the sub-modules around--instead, I want to store the primary keys, and then when the model is fetched from the server, its parse will "reconstitute" them by fetching the related models.
What is the best approach to accomplishing this? The closest I've come to getting it to work is overriding the sync method:
sync : function(method, model, options) {
var topics = this.get('topics');
model.attributes.topics = _.pluck(topics, 'id');
var ret = Backbone.Model.prototype.sync.call(this, method, model, options);
this.attributes.topics = topics;
return ret;
},
but this regularly fails, leaving the keys in the attributes instead of the full models & consequently crashing.
Parse function (slightly paraphrased):
parse : function(response) {
response.topics = _.map(response.topics, function(item) {
return app.topics.getByPK(item);
}
return response;
}
What I would do would be something more along these lines:
parse : function(response) {
this.topics = _.map(response.topics, function(item) {
return app.topics.getByPK(item);
}
return response;
}
Which keeps your array of ids intact at all times, and you have access by using this.topics instead of this.get('topics') or this.attributes.topics
Related
I am making $http request to multiple environment and processing after I get all the responses. I am using the code below:
$q.all(Object.keys($rootScope.envs).map(request)).then(function(res){
var results = {};
for (var env in res) {
results[env] = res[env].data;
}
}, function(err){
console.error(err);
});
function request(env) {
return $http.get(callService.getDomainUrl()+'/'+$rootScope.envs[env]+ '/hosts.json');
}
The above code works fine, but the results object looks like below:
{
0: {data:{}},
1: {data:{}},
2: {data:{}},
3: {data:{}}
}
I want the corresponding response for each key and the results should be like
{
env1: {data:{//data for env1}},
env2: {data:{//data for env2}},
env3: {data:{//data for env3}},
env4: {data:{//data for env4}},
}
How to map the corresponding response to the key? Please let me know how to get this as this is asynchronous request. Should I have something from the API to know which env the API is coming from?
I think the simplest way would be to push the result handling into the request function, that way you still have the 'env' value in scope.
var results = {};
$q.all(Object.keys($rootScope.envs).map(request)).then(function(res){
// Do something with 'results' here.
}, function(err){
console.error(err);
});
function request(env) {
return $http.get(callService.getDomainUrl()+'/'+$rootScope.envs[env]+ '/hosts.json')
.then(function(res) { results[env] = res.data; return env; });
}
Another option would be to replace my return env with return [env, res.data] and then you can go back to creating the results object as in your original code.
The important thing here is to remember you can handle the $http.get promises individually as well as using the promises from the call to then in $q.all.
i am very new to pouchdb, meaning i have not yet been successfully able to implement an app that uses it.
This is my issue now, in my controller i have two functions:
var init = function() {
vm.getInvoicesRemote(); // Get Data from server and update pouchDB
vm.getInvoicesLocal(); // Get Data from pouchDB and load in view
}
init();
Basically in my app i have a view that shows customer invoices, now i want customers to be able to still see those invoices when they're offline. I have seen several examples of pouchdb and couchdb but all use the "todo" example which does not really give much information.
Now i'm just confused about what the point was in me spending hours understanding couchdb and installing it if in the end i'm just going to be retrieving the data from my server using my API.
Also when the data is returned how does pouchdb identify which records are new and which records are old when appending.
well, i m working on same kind..!this is how i m making it work..!
$scope.Lists = function () {
if(!$rootScope.connectionFlag){
OfflineService.getLocalOrdersList(function (localList) {
if(localList.length > 0) {
$scope.List = localList;
}
});
}else{
if(!$scope.user){
}else {
Common.callAPI("post", '***/*************', $scope.listParams, function (data) {
if (data !== null) {
$scope.List = data.result;
OfflineService.bulkOrdersAdd_updateLocalDB($scope.List);
}
});
}
}
};
so,$scope.List will be filled if online as well as offline based on connectionFlag
note : OfflineService and Common are services.
call method:
$ionicPlatform.ready(function () {
OfflineService.configDbsCallback(function(res) {
if(res) {
$scope.Lists();
}
});
});
u can try calling $scope.Lists(); directly..!
hope this helps u..!
Backbone documentation says,
parse is called whenever a model's data is returned by the server, in
fetch, and save. The function is passed the raw response object, and
should return the attributes hash to be set on the model.
But i have customized parse function for my model. I want to execute it only when i fetch data not when i save data.
Is there a way to do it? I can check my response inside parse function. But is there any built-in option to do it?
This is from the backbone source file regarding saving a model:
var model = this;
var success = options.success;
options.success = function(resp) {
model.attributes = attributes;
var serverAttrs = model.parse(resp, options);
if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
return false;
}
if (success) success(model, resp, options);
model.trigger('sync', model, resp, options);
};
You could pass a custom option on your save like: model.save(null, { saved: true }), then in your custom parse:
parse: function(response, options) {
if ( options.saved ) return this.attributes;
// do what you're already doing
}
I haven't tested this at all, but it should at least get you started.
Just pass a parse:false into the save method as an option.
m = new MyModel()
s.save(null, {parse: false})
Disk is my collections object. I need to stop fetching collections
customPoll: function(time){
var set_time = 0;
if(time === undefined){
set_time = 4000;
}
var route = Backbone.history.fragment.split('/');
var self = this;
if(route[0] === "disks"){
setTimeout(function() {
Disks.fetch({update:true,success: function(){
self.customPoll();
}, error: function(){
self.customPoll();
}
});
}, set_time); //TODO Need to handle efficiently...
}
}
Am trying to call this fetching in every 4 second if some condition exist other wise i need to stop calling this fetching.
var route = Backbone.history.fragment.split('/');
var smart = new Smart.model({
"id" : route[1]
});
var self = this;
smart.save(null,{
success: function(model,event,response){
model = Disks.get(route[1]).toJSON();
$('#smart-confirm-dialog').modal('hide');
self.showStatusMsg(1,"<b> S.M.A.R.T. Test : </b>S.M.A.R.T Test started succesfully");
if(model.smart.progress === "100%"){
self.clearAllTimeout();
alert("please stop fetching....pleaseeee");
// Stop polling here . then fetch information from smart.fetch api.
Smart.fetch({update: true}); //this is another api i need to call this api now.
}else{
self.customPoll();
}
});
But it seems to be not working... Its keep on fetching collection.. How can i stop this Disk collection fetching.
My answer maybe is funny, I want to add comment, but I couldn't. can you add new field to your model and
customPoll: function(time){
var disks = this.model.toJSON();
if(disks.yourField){
// here your code
}
}
but before saving the model need to do delete disks.yourField;
I gave up finally. I have struggling to get this one to work but no luck. I simply have a collection.create call like this:
var createData = {
full_name : full_name,
email : email,
role_id : role_id
};
var that = this;
app.collections.teamMembers.create(createData,{
wait: true,
success : function(){
log("in success")
},
error : function(a,b,c){
log("in error")
}
})
The server is PHP and it returns the result like this:
header('Content-type: application/json');
echo json_encode(array(
"data" => $data,
"meta" => $meta
));
In the above, the $data is actually the array("attr"=>"val", ...) which matches exactly how the model for this collection is defined.
The problem is that since I am not returning directly a JSON object similar to the original model, but using namespacing (data/meta), I use model.parse on the model like this:
parse : function(response){
log(response, "inside model parse, this is the response from server")
return response.data;
},
ISSUE: The model doesn't get created on the client end. No 'add' event is fired. I am also using the wait:true option.
However, the model gets created on the local if:
- I don't use wait:true
- I use wait true but return the exact JSON model from server, with no name spacing.
I WANT to use wait:true as well as namespacing. Please help :(
Finally I was able to fix it, I was overriding backbone collections and models in my bootstrap to have a loading state which I am not using anyway. So I commented out that whole code. Now it works fine. this was the code in my bootstrap that I commented out:
// OVERRIDINGS AND SETTINGS
//----------------------
// Adding close method to all views
Backbone.View.prototype.close = function() {
if (this.onClose) {
this.onClose();
}
_.each(this.childViews, function(childView){
childView.close();
delete childView;
})
this.remove();
this.unbind();
};
// Adding loading state to every model and collection
Backbone.Collection.prototype.loading = false;
Backbone.Model.prototype.isLoading = false;
// Set isLoading to true when fetch starts
var oldFetch = Backbone.Collection.prototype.fetch;
Backbone.Collection.prototype.fetch = function(options) {
this.isLoading = true;
oldFetch.call(this, options);
}
Backbone.Model.prototype.fetch = function(options) {
this.isLoading = true;
oldFetch.call(this, options);
}
// Turn off isLoading when reset
Backbone.Collection.prototype.on('reset', function(){
this.isLoading = false;
})
Backbone.Model.prototype.on('reset', function(){
this.isLoading = false;
})