Fetch Backbone collection with search parameters

36,269

Solution 1

Backbone.js fetch with parameters answers most of your questions, but I put some here as well.

Add the data parameter to your fetch call, example:

var search_params = {
  'key1': 'value1',
  'key2': 'value2',
  'key3': 'value3',
  ...
  'keyN': 'valueN',
};

App.Collections.SearchResults.fetch({data: $.param(search_params)});

Now your call url has added parameters which you can parse on the server side.

Solution 2

Attention: code simplified and not tested

I think you should split the functionality:

The Search Model

It is a proper resource in your server side. The only action allowed is CREATE.

var Search = Backbone.Model.extend({
  url: "/search",

  initialize: function(){
    this.results = new Results( this.get( "results" ) );
    this.trigger( "search:ready", this );
  }
});

The Results Collection

It is just in charge of collecting the list of Result models

var Results = Backbone.Collection.extend({
  model: Result
});

The Search Form

You see that this View is making the intelligent job, listening to the form.submit, creating a new Search object and sending it to the server to be created. This created mission doesn't mean the Search has to be stored in database, this is the normal creation behavior, but it does not always need to be this way. In our case create a Search means to search the DB looking for the concrete registers.

var SearchView = Backbone.View.extend({
  events: {
    "submit form" : "createSearch"
  },

  createSearch: function(){
    // You can use things like this
    // http://stackoverflow.com/questions/1184624/convert-form-data-to-js-object-with-jquery
    // to authomat this process
    var search = new Search({
      field_1: this.$el.find( "input.field_1" ).val(),
      field_2: this.$el.find( "input.field_2" ).val(),
    });

    // You can listen to the "search:ready" event
    search.on( "search:ready", this.renderResults, this )

    // this is when a POST request is sent to the server
    // to the URL `/search` with all the search information packaged
    search.save(); 
  },

  renderResults: function( search ){
    // use search.results to render the results on your own way
  }
});

I think this kind of solution is very clean, elegant, intuitive and very extensible.

Solution 3

It seems the current version of Backbone (or maybe jQuery) automatically stringifies the data value, so there is no need to call $.param anymore.

The following lines produce the same result:

collection.fetch({data: {filter:'abc', page:1}});
collection.fetch({data: $.param({filter:'abc', page:1})});

The querystring will be filter=abc&page=1.

EDIT: This should have been a comment, rather than answer.

Solution 4

Found a very simple solution - override the url() function in the collection:

App.Collections.SearchResults = Backbone.Collection.extend({

  urlRoot: '/search',

  url: function() {
    // send the url along with the serialized query params
    return this.urlRoot + "?" + $("#search-form").formSerialize();
  }
});

Hopefully this doesn't horrify anyone who has a bit more Backbone / Javascript skills than myself.

Share:
36,269
sa125
Author by

sa125

Updated on January 23, 2020

Comments

  • sa125
    sa125 over 4 years

    I'd like to implement a search page using Backbone.js. The search parameters are taken from a simple form, and the server knows to parse the query parameters and return a json array of the results. My model looks like this, more or less:

    App.Models.SearchResult = Backbone.Model.extend({
        urlRoot: '/search'
    });
    
    App.Collections.SearchResults = Backbone.Collection.extend({
        model: App.Models.SearchResult
    });
    
    var results = new App.Collections.SearchResults();
    

    I'd like that every time I perform results.fetch(), the contents of the search form will also be serialized with the GET request. Is there a simple way to add this, or am I doing it the wrong way and should probably be handcoding the request and creating the collection from the returned results:

    $.getJSON('/search', { /* search params */ }, function(resp){
        // resp is a list of JSON data [ { id: .., name: .. }, { id: .., name: .. }, .... ]
        var results = new App.Collections.SearchResults(resp);
    
       // update views, etc.
    });
    

    Thoughts?

  • fguillen
    fguillen over 11 years
    There is a little coupling here with this DOM reference into the Collection. But I have done uglier things :)
  • ian
    ian over 10 years
    I'd say it was a fault of Backbone's that it's not easier to do this another way.
  • JoeBrockhaus
    JoeBrockhaus over 9 years
    ^--> plus the accepted answer does the same, and relies on jQuery .val() instead of backbone's models.
  • Chris
    Chris almost 9 years
    I agree. Search is normally done with a GET not a POST. I see merits to the Search model .save() approach especially if you are using the server to log/store the searches, but this answer is more standard (and most people are using client-side javascript to track the searches anyway).
  • The Qodesmith
    The Qodesmith almost 8 years
    I had no idea about $.param OR about passing {data: ...} to the fetch call. Thank you for this!
  • The Qodesmith
    The Qodesmith almost 8 years
    This was the approach I was using until I saw @jakee's answer above.
  • Ivan Durst
    Ivan Durst almost 7 years
    Helpful, nonetheless!