I'm trying to have a collection in backbone that calls /search/:searchTerm to the server upon fetch.
I have the following line:
this.collection.fetch({ data: {searchTerm: "user input"} });
Firebug tells me this leads to a GET http://localhost:4242/search?[object%20Object]
Can this only be done by writing myself the ajax call in the backbone router, or is there a smoother faster way?
I had the same problem, but using jQuery.param seems to have fixed it, i.e.
this.collection.fetch({ data: jQuery.param({searchTerm: "user input"}) });
Related
So I'm trying to AJAX a single solr doc from my results list to a "doc view" view. I'm trying to use AngularJS to AJAX to my view render method and display the doc that way, but I can't seem to get the angular to work and I'm not sure I'm doing things correctly on the Play side either. Would you at least be willing to tell me if what I'm trying to do will work? The Angular error comes from the docText.text(); call. Here is my code:
Angular controller code:
var docText = $resource("http://localhost:9000/views/full-doc-text.html", {
text: {method: 'PUT'}
});
$scope.handleViewText = function(value) {
docText.text({doc: value});
}
Java code:
public static Result viewText() {
JsonNode json = request().body().asJson();
//do stuff here
return ok(viewtext.render(json));
}
route:
GET /views/full-doc-text.html controllers.Application.viewText()
I see three problems with the code above;
1.The definition of docText resource is not correct. if your read the angularjs manual here you'll see that $resource has 4 parameters. First one is resource url, second is parameter defaults, third one is custom actions and forth one is resource options where last three of them are optional. In your code you pass custom actions as the second parameter, which should be the third. And since you don't have any parameters in your resource url second parameter must be null. So first correction is:
var docText = $resource("http://localhost:9000/views/full-doc-text.html", null, {
text: {method: 'PUT'}
});
2.You define your text action's HTTP method as PUT however in your routes file you are handling GET requests for your desired action. You should change your route definition as:
PUT /views/full-doc-text.html controllers.Application.viewText()
3.PUT method is usually used for update operations when implementing a RESTFULL service. In your case you don't seem to be updating anything. So I suggest to use POST method just for convention.
I am developing a Backbone application.
I have a view named as "Dashboard". In this dashboard View, I will be fetching two collections of data; one for the List of recent articles from the articles table and the other for the list of Authors from the authors table.
Please note that I have two different tables in mySQL Database, I use SlimPHP Api to make queries and retrieve data.
I am also using Handlebars templating Javascript library to compile the HTML.
Question:
My Question is that what is the best approach to make the two queries and then send both collections data to the Handlebars compile which will create the HTML (after looping through collection models) and eventually be taken into render function.
Here is what I have tried so far (Dashboard View Javascript File):
http://jsfiddle.net/n6c3q16r/2/
I tried to fetch two models data and pass it into the render function on line # 17 on jsFiddle:
this.$el.html(this.template(this.collection, this.topAuthorsCollection));
But this does not work.
Try this:
initialize: function() {
this.listenTo(this.topAuthorsCollection, 'reset', this.render);
this.topAuthors = new topAuthorsModel();
this.topAuthorsCollection = new topAuthorsCollection({model: this.topAuthors});
this.collection.fetch({
reset: true,
success: function() {
this.topAuthorsCollection.fetch({reset: true})
}
});
}
You can use promises. My personal favourite in such a scenario is jQuery.when
$.when(collection1.fetch(),collection2.fetch()).done(function(){
//Do stuff here
});
API - http://api.jquery.com/jquery.when/
Updated fiddle - http://jsfiddle.net/n6c3q16r/4/
I have an API that gives me paginated results, like:
http://quickstart.local/api/conversations/326/messages?page=1
so url is a function that changes each time I want to fetch another page.
When I fetch a new page, my collection resets and only the new results will be kept inside the collection. If I fetch with the same URL, the merge is done though. Is there a way to avoid this? I've already tried to fetch like this:
this.fetch({
reset : false,
merge:true,
add: true,
success : opts.success,
error : opts.error
});
but it does not work at all. Any suggestion?
Alright, I've forgotten the remove: false option. Fetch exploits the collection.set method, which takes the parameters listed here
I want to call save on a Backbone model and have it write data to the server, but not update the client. How do I do this?
To clarify: when Backbone saves a model, it sends all the data to the server, and then retrieves the data from the server and updates it on the client. This second step is what I want not to happen.
To clarify further: The model ('parent' model) has an attribute which is itself a model ('child' model); when it's saved to the server, this child model is converted to JSON. When the parent model updates after the save, the attribute that previously contained a reference to the child model is replaced with the parsed JSON object of the child model that was saved. This is what I need not to happen.
When the data is initially pulled from the server, the parent model "reconstitutes" that object into an appropriate child model, but this is an expensive process and there is no reason to re-do it every time save fires on the parent model, since the child model will never change.
It sounds like you do not want to parse your model when you receive the response from the server on a model.save
You can try something such as:
model.save(attributes,{
success: function() { ... },
parse : false // This will be passed to your parse function as an option
});
You would have to set-up your parse function in your corresponding model as follows:
parse: function(resp,options) {
// don't update model with the server response if {parse:false} is passed to save
if (options && !options.parse) return;
/ ... rest of your parse code ... /
Backbone currently defaults options.parse to true. Here is a short-discussion on the topic.
As discussed in that thread, perhaps you want to consider why you do not want want to update the server response to the client. There may be a cleaner way to achieve the results you desire.
Depending on how/what your server setup is, all you really have to do is issue a regular AJAX request. This is exactly what backbone does in the background so you'll just bypass the client side logic.
You could do this with native JavaScript, but I'm fairly sure you have some other library in use that can make things much easier.
For the completeness of this answer, I'll give an example with jQuery:
$.ajax({
type: "POST",
url: "http://same.as.your.model",
data: { "the" : "model" },
dataType: "JSON",
success: function(){
// once the request has returned
}
});
The $.ajax function also has some additional functionality, and you can read about it in the jQuery docs.
On client you mean Views? If you want to save your model but not render your views which happens since save will trigger a change event, you should call save with option silent:true, or set a custom option like dontchange:true when calling save and check it in when handling change. I prefer the custom option, because silent has side effects (at least in my version of backbone 1.0.0)
a little code:
when you save:
model.save({},{dontchange: true});
you install your event listeners in the view:
this.listenTo(model, 'change', function(model, options){
if (options.dontchange)
return;
this.render();
});
I ran into same problem. model.save(attrs,{patch:true, parse:false}) really did not invoke parse method but model was still merged with server response.
It is not elegant, but this worked for me:
model.clone().save(attrs,{patch:true})
I believe it's best to avoid this situation by clean REST api design.
I currently started using Firebase as my backend solution for persistance.
I found it easy to create new objects and persist it to Firebase with Backfire with a simple
collection.add(obj)
The issue comes when I try to get a Firebase collection from the server.
For example when i try
console.log(collection);
I get this output:
=> {length: 0, models: Array[0], _byId: Object, _events: Object, constructor: function…}
Which result in an empty models array
console.log(collection.models);
=> []
After some searching, I figured out that Backbone Collections aren't yet loaded at the time I try to log it to the console (see this previous question).
I also tried using
Backbone.Collection.extend({
model: Todo,
firebase: new Backbone.Firebase("https://<your-namespace>.firebaseio.com")
});
To explicitly call fetch from the server and use success callback with no success either.
My question is: How can I get the Firebase Collection and populate the DOM from it?
When you call Backbone.Firebase.Collection.add, it does not get added to the collection synchronously. Rather, it sends the request to Firebase and then waits for the return event. See the code here
Thus, if you immediately try to read the collection, you will see zero elements. However, if you try something like this:
collection.once('add', function() { console.log(collection.length); });
You'll see the element you have added.
Remember that we're dealing with real-time data here, so when you want to populate the DOM, you shouldn't think in terms of a single transaction, but instead rely on events and take everything as you get it (in real time).
So to populate the DOM, do something like this in your view:
Backbone.View.extend({
render: function() {
this.listenTo(this.collection, 'add', this.rowAdded);
},
rowAdded: function(m) {
/* use `m` here to create your new DOM element */
}
});
Additionally, you'll probably want to check out a nice binding library like ModelBinder to help you deal with the constantly changing DOM, so you don't have to re-invent any wheels.
It seems you have to use a Backbone.Firebase.Collection and not a Backbone.Collection which will tell you that your calls to fetch or sync are silently ignored.
Also, Backbone.Firebase's got a read and a readall methods that should get you started. It seems Backbone.Firebase.Collection doesn't inherit this method, but I'm not sure though.
Edit:
As Kato stated in his comment, it seems you don't have to do anything. Just use Backbone.Backfire.Collection and Backbone.Backfire.Model.