1

HI my basic model which fetches data from server is working perfect. I want to implement a search feature. When user enters any data the request goes to browser and desired model is returned.

var Book = Backbone.Model.extend({
  urlRoot: '/books'
});

  render: function(options) {
  books = new Book({id:options.name});
  books.fetch();
   }

where

  name = "search/"+dynamic_data;

Request URL that is being formed when i pass --> 'life' in variable dynamic_data

  http://host/path/search%2Flife

Request URL that i want

 http://host/path/search/life

How can I encode/escape my string to achieve the desired result. I have tried escape(), encodeURI(), encodeURIComponents

  1. A workaround to solve this is create one more model with urlRoot as /books/search and pass just name . I don't think this is correct. Should I use this ?
Abhishek
  • 1,717
  • 6
  • 22
  • 39
  • Is the `id` of your book really **/search/life**? That seems very wrong to me. Is **life** a book category? I have never used Backbone, but I can understand that it will treat the `id` as a parameter and encode it using `encodeURIComponent` or some other method and that's the behaviour I would expect. Here you are calling `fetch` on a single model instance, wich by default, will try to retrieve that model's data by doing **GET {urlRoot}/{id}**. For a search feature, you should be looking into `Backbone.Collection`. – plalx Mar 31 '13 at 13:43
  • Yeah life is a book name. no the id of the book is life. /search/ is used to tell the backend server to show all book names having life in them. /book/id will give only one book /book/search/id will give all the books having id string in them. Note : id in this case is a name n not primary key – Abhishek Mar 31 '13 at 13:49

3 Answers3

1

According to your additionnal precisions stating that life is actually a book name...

It looks like Backbone is better integrated with RESTful API's. In REST, your urls should not contain verbs and to search books, you would do a GET /books/?name=life.

In that case, you would only have to define a Backbone.Collection like:

var BooksCollection = Backbone.Collection.extend({
    model: Book,
    url: '/books'
});

The to fetch books:

var books = new BooksCollection();

books.fetch({data : {name: 'life'}}); //GET /books/?name=life

If you really want your search operation to target /search/:name, you will have to check the Backbone.Collection api, but I think you will want to look at http://backbonejs.org/#Sync

You could override your collection's sync method to something like:

Backbone.Collection.extend({
    ...
    sync: function (method, model, options) {

        //for read operations, call the search url
        if (method === 'read') {
            options.url = '/search/' + options.data.name;
            delete options.data.name;
        }

        //call the default sync implementation
        return Backbone.Collection.prototype.sync.apply(this, arguments);
    }
});

In this cased calling books.fetch({data : {name: 'life'}}); will result in GET /books/life.

Here's a fiddle that shows the example.

plalx
  • 42,889
  • 6
  • 74
  • 90
  • Thanks for the answer. the idea of GET /books/?name=life is great. – Abhishek Mar 31 '13 at 15:38
  • Can you refer me to any article or tutorial for overridding the sync method other than the official document.? I'm new to backbone.js. Your answer has given the big picture but i need to know finer details too – Abhishek Mar 31 '13 at 16:22
  • This answer can probably help you -> http://stackoverflow.com/questions/5096549/how-to-override-backbone-sync – plalx Mar 31 '13 at 21:11
  • var books = new BooksCollection(); books.fetch({data : {name: 'life'}}); This is throwing error Uncaught TypeError: undefined is not a function – Abhishek Apr 01 '13 at 08:59
  • I seriously think overriding the Backbone.sync is a horrible strategy. Backbone is flexible and you can do literally anything with it but I would strongly suggest you should override the `url` of the model upon initialization. `books = new Books({}, {url: options.name)); books.fetch()` –  Apr 02 '13 at 04:12
  • @JohnEdward In that case you should contribute to the answer and suggests an edit that shows an alternative way of doing it explaining why overriding the `sync` method is so bad. – plalx Apr 02 '13 at 12:11
  • @Abhishek, I added a jsFiddle link at the end of the example that shows it working. – plalx Apr 02 '13 at 12:18
  • @plalx : umm .. I just did. Why override `Backbone.sync` when you can override Model's `url` attribute? –  Apr 02 '13 at 15:26
  • @JohnEdward, well because you might want to perform other tasks with the collection than `fetching` data. If you override the url, won't it use `/search` for every method now? – plalx Apr 02 '13 at 15:45
0

this would work:

books = new Book({id:options.name}, {url: options.name));

neebz
  • 11,465
  • 7
  • 47
  • 64
0

decodeURIComponent() will decode http://host/path/search%2Flife to http://host/path/search/life.

capu
  • 2,245
  • 1
  • 14
  • 11