如何使用角度上的Lunr搜索js数据资源?

时间:2015-12-24 09:38:07

标签: angularjs jsdata lunrjs

在我的angular(1.3)应用中,我使用JSData(2.0.0),并且我想使用Lunr为这些资源添加全文搜索功能,没有Ajax。有什么提示吗?

1 个答案:

答案 0 :(得分:0)

为此,我已经为JSData的SearchableDS资源创建了DS扩展名。

这是一个用法示例:

angular.module("app")

.factory("User", function(SearchableDS) {
  var resource;
  // so far the same JSData code
  resource = SearchableDS.defineResource({
    name: 'user',
    endpoint: 'users',
    idAttribute: 'id',
    searchFields: { // Lunr searchable fields and their respective boost
      name: 7,
      title: 3
    }
  });
  return resource;
})
.controller(function(User) {
  // first we fetch all the records
  User.findAll({limit: 1000}).then(function() {
    var users;
    // now we can search local records
    return users = User.search('tim');
  });
});

SearchableDS

angular.module("app")
.constant('Lunr', lunr) // lunr.js
.constant('_', _) // underscore.js
.service('SearchableDS', function(DS, Lunr, _) {
  _(this).extend(DS); // extending DS with new capabilites
  this.defineResource = function(options) {
    var addToIndex, defaultOpts, index, resource;
    defaultOpts = {
      searchMapper: angular.identity, // optional. a function to create objects for a different lunr mapping. useful for e.g. when the records have nested objects
      searchFields: {}
    };
    options = _(defaultOpts).extend(options);
    resource = DS.defineResource(options);
    index = Lunr(function() { // create lunr index
      var _this = this;
      this.ref(options.idAttribute); 
      // add searchable fields and their boost value to the index
      _(options.searchFields).each(function(boost, name) {
        _this.field(name, {boost: boost})
      });
    });
    addToIndex = function(entity) {
      index.add(options.searchMapper(entity));
    };
    // wrap the original record-fetching methods so that they'll add newly fetched records to Lunr's index
    resource.findAll = (function() { 
      var originalFunc;
      originalFunc = resource.findAll;
      return function() {
        return originalFunc.apply(resource, arguments).then(function(entities) {
          return _(entities).each(addToIndex); // add to lunr index
        });
      };
    })();
    resource.find = (function() {
      var originalFunc;
      originalFunc = resource.find;
      return function() {
        return originalFunc.apply(resource, arguments).then(function(entity) {
          return addToIndex(entity);  // add to lunr index
        });
      };
    })();
    // full text search of local records using Lunr
    resource.search = function(str) {
      var entities, ids;
      ids = _(index.search(str)).pluck('ref'); // use Lunr only to find the record IDs
      entities = _(resource.getAll())
      .chain()
      .filter(function(t) {
        return ~ids.indexOf(t.id)
      }).sortBy(function(t) {
        return ids.indexOf(t.id)
      })
      .value();
      console.log(options.name + "#search: " + entities.length + " results for '" + str + "'");
      return entities;
    };
    return resource;
  };
  return this;
})