In most of my cases, the model.parse is called during a collection.parse. In some cases the model.parse isnt called.
I need it in all cases. Is it possible to place it somewhere global as in the similar option: Backbone.emulateHTTP = true;
Also the docs offer seemingly conflicting info regarding model.parse
model.parse(response, options)
parse is called whenever a model's data is returned by the server, in fetch, and save.
versus and possible/maybe
model.initialize
...
If {parse: true} is passed as an option, the attributes will first be
converted by parse before being set on the model.
Ok. i solved it. seems the official docs are confusing. here is a more concise description of when and where to use parse: true options.
http://adzdavies.blogspot.ca/2012/08/backbone-parsing.html
Related
This is more of a general question, I've been bouncing around multiple posts on StackOverflow and reading what I've found so far in the docs. I haven't found anything super concrete yet to answer the post question which is: what are the benefits of linking documents to one another through the ref type vs. the string type?
As of now, I'm converting all my string "refs" to properly typed "refs". However, since i'm still relatively new to the platform I'm scratching my head wondering if this is even necessary. I assume I'd be just as effective at finding related docs with the string as with a reference.
Also, for the sake of future readers as of me posting this, you can set a ref like so:
db.collection(...).add({
...
reference: firebaseFirestore.doc(
`lesson_translations/${translationID}`
),
// reference is now typed as a 'ref'
})
I had found other posts on stackoverflow accessing it with .doc(...).ref which doesnt seem to be a thing anymore.
It's mostly a matter of personal preference and perceived convenience. There is not really anything a reference type can do that a string and your own code could not also do.
Having a reference type mostly saves you the trouble of building a new reference object in your code, if that's what you would have done with a string document ID anyway. You can also use it in security rules for the same purpose when it comes time to use get() to fetch another document referenced by a field.
Again, it's personal preference. Do whatever is most convenient for you.
When you call a document reference, you instantly get the document details while if you take a string path and call it, it will take some time to find that data. It is just a matter of a few milliseconds and a few lines of code. Imagine if you had a list of document references to store and you store them as strings, and then had to call all of them looping over it
I know of one tangible benefit, but it's only relevant if you are using a library for data binding that supports loading nested documents to n depth. I personally am using vuefire, but I would assume something similar exists for the react ecosystem.
It allows you to e.g. bind a collection or document to a variable, and automatically sync all the data of referenced documents.
Example
You sync a collection('users') with a depth of two, and each user document contains an array of favourites:
{
name:'John',
favourites: [ref1, ref2, ref3]
}
The library would immediately download the references and replace the original ref files with the data:
{
name:'John',
favourites: [{title:'foo'}, {title:'bar', {title: 'baz'}]
}
The Problem:
I'd like a single ui-router state to match the following urls:
#/.../update?id
#/.../update?username
#/.../update?customerId&sandwichId
If/when the 'update' state is active (it's a routed component), the component's controller knows enough to expect which params will be there (via a provided array of Strings that should/will match whatever query params are in fact present).
Current Solutions (none of which I'm 100% happy with)
I could just leave the url at '#/.../update' with the implicit understanding that I cannot navigate to that url from anywhere but it's parent state, and just pass in its primary key fields as a component binding. The drawback obviously being if I just type the URL in my browser, it will not have enough information to load.
As per an example I found here, I defined my 'update' state with single query parameter: pkKeys. I then define pkKeys upon my state transition to be the entire query parameter string I desire. This effectively achieves what I am looking for. However, typing this just doesn't feel right:
#/.../update?pkKeys=username=test
Moreover, it looks ugly on the more complicated situations:
#/.../update?pkKeys=customerId%3D3ae2e6eb-3bf7-42f8-a09c-9c690c8dbe15%26sandwichId%3D2cb6d513-06a3-4aa4-93bb-e53d279d95cb
Ideal Target State
Ideally, I'm looking for a way to configure my state in a way that matches the above patterns of urls. I did not have much success with $location service, but something tells me that has something to do with it. It appeared to me that $location.search() was cleared whenever $state.go( ... ) was invoked.
Thanks for any help in advance! Happy to elaborate on anything that might not be clear. It's a rather unique problem set I find myself in here...
On Further Research
For reference, I'm using Angular UI Router 1.x. I have found they have the notion of dynamic parameters, which seems to nearly solve the problem I am encountering (see the GitHub issue for this change). However, where this fails me is the state configuration still expects you to list the dynamic parameter's name. As my query param names are data-driven, the set of names is not a finite set. So I need dynamic parameters...with dynamic names.
What is the difference between these two? Both seems to make a GET to /users and retrieve them.
Restangular.one('users').getList().then(function(users) {
// do something with users
});
Restangular.all('users').getList().then(function(users) {
// do something with users
});
I understand that you can do one('users', 123) and it will retrieve /users/123 but without the second argument it seems to be the same thing. Why not just have one method in that case?
The one() function has a second argument that accepts an id e.g. .one('users', 1).
one('users', 1).get() translates to /users/1
all('users').getList() translates to /users
Unlike all(), one() is not generally used with .getList() without argument. However, if you were to call .one('users', 1).getList('emails') or .one('users', 1).all('emails').getList(), then you would make a GET request to /users/1/emails.
My guess is that they are there for expressing an intention of what you are going to do. I would understand those as a way to build the url, expressing if you are accessing to the whole resource or to a specific one.
In the end, they are gonna build and do a GET request but because you do a GET and retrieve some data it does not mean that it should be used in that way.
Example extracted from https://github.com/mgonto/restangular/issues/450
getList can be called both ways. If it's called in an element one,
then it needs a subelement to get to a Collection. Otherwise, it
fetches the collection. So the following is the same:
Restangular.one('places', 123).getList('venues') // GET /places/123/venues
Restangular.one('places', 123).all('venues').getList() // GET /places/123/venues
As you can see, it is more expressive to call one('places', 123).all('venues') to understand that you just want the venues located in the area/place 123.
Maybe the following url will help you:
https://github.com/mgonto/restangular/issues/450
I've recently discovered a difference between these methods. Yes, both of them make the same get requests, but the results you get might surprise you (as they surprised me).
Let's assume we have an API method /users which returns not strictly an array, but something like this:
{
"result": [{...}]
}
So an array is returned as a value of some prop of the response object. In this case get() and getList() work differently. This code works well:
Restangular.get('users').then(function (response) {...});
Your response handler gets invoked after response has been received. But this code doesn't seem to work:
Restangular.all('users').getList().then(function (response) {...});
Response handler is not invoked, despite that request completed with status code 200 and non-empty response. Browser console doesn't show any errors and network monitor shows successful request.
I've tested this with Restangular 1.5.2 so probably this is already fixed in newer versions.
What technique shall one use to implement batch insert/update for Backbone.sync?
I guess it depends on your usage scenarios, and how much you want to change the calling code. I think you have two options:
Option 1: No Change to client (calling) code
Oddly enough the annotated source for Backbone.sync gives 'batching' as a possible reason for overriding the sync method:
Use setTimeout to batch rapid-fire updates into a single request.
Instead of actually saving on sync, add the request to a queue, and only batch-save every so often. _.throttle or _.delay might help you here.
Option 2: Change client code
Alternatively, instead of calling save on your models, you could add some sort of save method to collections. You'd have to track which models were actually modified and hence in need of update, since as far as I can tell, Backbone only knows whether they're new or not (but I could be wrong about that).
Here's how I did it
Backbone.originalSync = Backbone.sync;
Backbone.sync = function (method, model, options) {
//
// code to extend sync
//
// calling original sync
Backbone.originalSync(method, model, options);
}
works fine for me , and I use it to control every ajax request coming out of any model or collection
According the Backbone.js documentation Model-parse does the following:
parse is called whenever a model's data is returned by the server, in
fetch, and save.
To augment models I've already loaded I use Model.parse(). I accomplish this by using fetch to make an additional request for data, then use that data to add properties to an existing model.
Example:
the fetch object is {age: 19}
after the parser will be {age: 19, isAdult: true}
When I perform the save request, in the PUT request I also have other parameters not needed (for example isAdult). I would like to have the original model (without additional parameters in PUT request).
What is the best way to achieve my goal in Backbone?
If I understand your question correctly ....
When backbone talks to a server using a save it sends a complete respresentation of the model. As the docs put it :
The attributes hash (as in set) should contain the attributes you'd
like to change — keys that aren't mentioned won't be altered — but, a
complete representation of the resource will be sent to the server.
So the default behavior is to send the complete model. If you want to implement you're own logic you're going to have to override the sync method. Dig through the expanded backbone code a bit and you'll see this comment above sync :
// Override this function to change the manner in which Backbone persists
// models to the server. You will be passed the type of request, and the model in question.
I would use the default implementation of sync as my starting point.