为什么我在尝试使用Meteor搜索源包时遇到错误?

时间:2015-11-16 10:09:14

标签: javascript meteor

我在this上关注meteor search-source教程并修改了示例,以便符合我当前的需求。 这是我的collections.js,它位于我的lib目录

Guides = new Mongo.Collection("guides");

我的客户端控制器中有以下代码。

var options = {
    keepHistory: 1000 * 60 * 5,
    localSearch: true
};

var fields = ['title'];

GuideSearch = new SearchSource('guides', fields, options);

Template.guide_list.helpers({
    getGuides: function () {
        return GuideSearch.getData({
            transform: function (matchText, regExp) {
                return matchText.replace(regExp, "<b>$&</b>")
            }
        });
    },

    isLoading: function () {
        return GuideSearch.getStatus().loading;
    }
});


Template.guide_list.events({
    "keyup #title": _.throttle(function(e) {
        var text = $(e.target).val().trim();
        GuideSearch.search(text);
    }, 200)
});

这是我的服务器端代码

SearchSource.defineSource('guides', function(searchText, options) {
  if(searchText) {
    var regExp = buildRegExp(searchText);
    var selector = {title: regExp}
    return Guides.find(selector, options).fetch();
  } else {
    return Guides.find({}, options).fetch();
  }
});

function buildRegExp(searchText) {
  // this is a dumb implementation
  var parts = searchText.trim().split(/[ \-\:]+/);
  return new RegExp("(" + parts.join('|') + ")", "ig");
}

出于某种原因,我在输入字段中输入内容时收到以下错误消息

Exception in delivering result of invoking 'search.source': Meteor.makeErrorType/errorClass@http://10.0.3.162:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:525:15
._livedata_result@http://10.0.3.162:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:4625:23
Connection/onMessage@http://10.0.3.162:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3365:7
._launchConnection/self.socket.onmessage/<@http://10.0.3.162:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:2734:11
_.forEach@http://10.0.3.162:3000/packages/underscore.js?46eaedbdeb6e71c82af1b16f51c7da4127d6f285:149:7
._launchConnection/self.socket.onmessage@http://10.0.3.162:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:2733:9
REventTarget.prototype.dispatchEvent@http://10.0.3.162:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:173:9
SockJS.prototype._dispatchMessage@http://10.0.3.162:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1158:5
SockJS.prototype._didMessage@http://10.0.3.162:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1216:13
SockJS.websocket/that.ws.onmessage@http://10.0.3.162:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1363:9

这是我的模板代码:

template(name="guide_list")
    .format-properly
        .container-fluid
            .input-group#adv-search
                .form-horizontal(role="form" method="POST" action="#")
                    .col-md-6
                        .form-group
                            label(for="contain") Guide title
                            input.form-control(type="text" id="title")
                    .col-md-6
                        .form-group
                            label(for="contain") Author
                            input.form-control(type="text" name="author")
                    .col-md-6
                        .form-group
                            label(for="hero") Select a hero
                            select.form-control(name="hero")
                                option(value="all" selected) All Heroes
                                option(value="Druid") Druid
                                option(value="Hunter") Hunter
                                option(value="Mage") Mage
                                option(value="Paladin") Paladin
                                option(value="Priest") Priest
                                option(value="Rogue") Rogue
                                option(value="Shaman") Shaman
                                option(value="Warlock") Warlock
                                option(value="Warrior") Warrior
                    .col-md-6
                        .form-group
                            label(for="filter") Filter by
                            select.form-control(name="filterBy")
                               option(value="0" selected) All guides
                               option(value="most_viewed") Most viewed
                               option(value="top_rated") Top rated
                               option(value="most_commented") Most commented

        .container-fluid
            .table-responsive
                table.table.table-hover
                    thead
                        tr
                            th hero
                            th title
                            th author
                            th updated
                            th dust
                            th
                                span.glyphicon.glyphicon-eye-open
                            th
                                span.glyphicon.glyphicon-heart
                            th
                                span.glyphicon.glyphicon-comment
                    tbody
                        each guides
                            tr
                                td {{hero}}
                                td
                                    a(href="/guide/{{formatId _id}}") {{title}}
                                td {{authorUsername}}
                                td {{moFormat modifiedAt 'YYYY-MM-DD'}}
                                td {{dust}}
                                td {{hitCount}}
                                td {{rating}}
                                td {{commentCount}}

                    tbody
                        each getGuides
                            tr
                                td {{hero}}
                                td
                                    a(href="/guide/{{formatId _id}}") {{title}}
                                td {{authorUsername}}
                                td {{moFormat modifiedAt 'YYYY-MM-DD'}}
                                td {{dust}}
                                td {{hitCount}}
                                td {{rating}}
                                td {{commentCount}}

非常感谢任何帮助或建议!

修改:我将search-source包更新为1.4.2

2 个答案:

答案 0 :(得分:3)

我认为问题是options方法缺少GuideSearch.search

这会导致搜索定义处理程序获得选项的null

SearchSource.defineSource('guides', function(searchText, options) {
  if(searchText) {
    var regExp = buildRegExp(searchText);
    var selector = {title: regExp}
    return Guides.find(selector, options).fetch(); //illegal
  } else {
    return Guides.find({}, options).fetch();
  }
});

这导致集合的find()方法获得空options参数,如果提供,则必须是对象(而不是null)。

因此,要么检查数据源中的空options并将空对象(或什么都没有)传递给find()方法,要么将空对象传递给GuideSearch.search()方法:

Template.guide_list.events({
    "keyup #title": _.throttle(function(e) {
        var text = $(e.target).val().trim();
        GuideSearch.search(text, {}); // here
    }, 200)
});

在任何情况下,您应该确保服务器方法中的options不是null,而不是@ webdeb的答案。

此外,目前一些软件包(checkejson)必须作为依赖项添加到您的应用程序,因为meteorhacks:search-source软件包使用它们而不声明依赖项。这是由于v1.2.0中引入的更改。 (在此之前,这些符号自动可用于包)。

为了让所有结果最初可用,您可以在首次创建模板时触发搜索。 请注意,当您拥有大量数据时,这可能相当昂贵,因此您应该限制从服务器上的搜索定义处理程序返回的结果。

Template.guide_list.onCreated(function () {
  GuideSearch.search('', {});
});

为了在搜索结果中正确显示标题,您可以使用Spacebars.SafeString(),以便blaze知道将其呈现为HTML。

Template.guide_list.helpers({
    getGuides: function () {
        return GuideSearch.getData({
            transform: function (matchText, regExp) {
              return Spacebars.SafeString(matchText.replace(regExp, "<b>$&</b>"))
            }
        });
    },
    formatId: function(id) {
      return id;
    },
    moFormat: function(date, format) {
        return moment(date).format(format);
    },
    isLoading: function () {
        return GuideSearch.getStatus().loading;
    }
});

Template.guide_list.events({
    "keyup #title": _.throttle(function(e) {
        var text = $(e.target).val().trim();
        GuideSearch.search(text, {/* your options here */});
    }, 200)
});

或者,使用三重括号表示法:

a(href="/guide/{{formatId _id}}") {{{title}}}

警告:请务必在执行此操作时清理matchText

出版物应该与结果无关,因为包使用自己的集合。

答案 1 :(得分:1)

我同意@MasterAM的答案,但要解决这个问题,请将其放入SearchSource函数中:

 SearchSource.defineSource('guides', function(searchText, options) {
  options = options || {}; // to be sure, that options is at least an empty object
  if(searchText) {
    var regExp = buildRegExp(searchText);
  ...