Search code examples
javascriptbackbone.js

Implement search effectively in Backbone.js


I am trying to perform a search on my current collection and if the results aren't retrieved i am trying to query my search api

Collection:

  var Backbone = require('backbone'),
  _ = require('underscore'),
  Urls = require('../../libs/urls'),
  services = require('../../libs/services'),
  skuListModel = require('../../models/sku/SkuListModel');
var SkuListCollection= Backbone.Collection.extend({
  model: skuListModel,
    sync: function (method, model, options) {
    options = _.defaults({}, options, {
      readUrl: Urls.sku.list
    });

    return services.sync.call(model, method, model, options);
  }
});

View

     searchData: function (e) {
    var self = this;

    var models = this.skuCollection.filter(function (item) {
      return item.get("sku_code").indexOf(e.target.value) > -1
    });
     console.log(models);
    if (models != null) {

      self.skuCollection.set(models);

    }
    else {
      self.skuCollection.fetch({
        data: {
          search_string: e.target.value
        }
      }).then(function (response) {
        console.log(response);
        //self.skuCollection.add(self.skuSearchCollection.toJSON(), { silent: true });
      });

    }

  }

My question effectively is how do i modify my current collection to store the retrieved results and if my solution seems effective.


Solution

    1. Move your filtering logic to the collection
    2. Use promises to unify your response : an immediately resolved deferred if you find models, the xhr object if you have to fetch the data
    3. Customize the behavior of fetch via the set options, e.g {remove: false} to keep the existing models

    These points lead to a collection definition :

    var SkuListCollection = Backbone.Collection.extend({
        skus: function(code) {
            var self = this;
            var filtered = function() {
                return self.filter(function (item) {
                    return item.get("sku_code").indexOf(code) !== -1;
                });
            };
    
            var models = filtered();
    
            if (models.length) {
                // models found : define a promise and resolve it
                var dfd = $.Deferred();
                dfd.resolve(models);
                return dfd.promise();
            } else {
                // models missing: fetch and add them
                return this.fetch({
                    remove: false,
                    data: {
                        search_string: code
                    }
                }).then(filtered);
            }
        }
    });
    

    Your view would then be rewired as :

    searchData: function (e) {   
        this.skuCollection.skus(e.target.value).then(function(models) {
            // do what you have to do with the filtered models
        });
    }
    

    And a demo http://jsfiddle.net/nikoshr/84342xer/1/