meteor-autocomplete
meteor-autocomplete copied to clipboard
Supporting multiple collections?
Hi, I implemented this autocomplete and I love it, however it seems to only work with one collection - can it work with multiple at the same time?
So if in settings I limit to 10, and the first collection delivers 7 results and 2nd collection delivers 3, I should see all results. But I only see the results of whichever collection is first declared in the settings. Example:
if (Meteor.isClient) {
Template.autoComplete.settings = function() {
return {
position: "bottom",
limit: 10,
rules: [
{
token: '',
collection: Customers,
field: "name",
matchAll: true,
template: Template.autocompleteCustomer
},
{
token: '',
collection: Clients,
field: "title",
matchAll: true,
template: Template.autocompleteClient
}
]
}
};
}
Problem: When rules array contains 2 separate collections, and are declared together as shown above, only the first one declared in the array will deliver results. So in the example above only the customers will deliver results.
How can I use both collections at the same time?
Thanks,
We currently don't support using the same token to match multiple collections (in your case, the token is the null string). I don't think this is necessary to do in our code.
The best way to approach this is probably not by using this library directly, but by using Meteor's publication API. Either publish both collections into the same client collection so they are merged on the client, and you can use a single search above, or create a server publication that searches both collections and publishes the combined result. Because we support autocomplete from both client-side collections and server-side publications, either way works - the first method is probably simpler to implement because Meteor will do the merging for you.
See http://stackoverflow.com/a/18880927/586086 for the basics on how to do this.
thank you for your detailed reply!
i made it work with two separate tokens, that's also perfectly fine for what I need. Best,
@andreimcristof I think you should consider the merging-via-publications approach; it's a lot cleaner and will not require the user to know about tokens.
thank you for your suggestion! will give this a try
Same problem here. :-) Would be great to search in more than 1 collection without token, providing a different template for each collection. Would be a lot cleaner without workarounds. Please let me know, if you implement this issue. Thank you, Bernhard
@berfer The logic to implement this would be much more complicated than just to use Meteor's publication API to do the trick. It's not a workaround, it's the better solution.
I don't think I'll be handling this here.
So I am working with a similar issue, but here is my issue. I want one collection to use a token and the other to not use a token.
My Code:
'autofillInput': function() {
return {
position: "bottom",
limit: 1000,
rules: [
{
callback: function(doc, element) { $("#ingredientId").val(doc._id); },
collection: Ingredients,
field: "ingredient",
filter: { deleted: false },
selector: function(match) { return getIngredientExpression($("#ingredient").val()); },
template: Template.ingredientDropdown
},
{
token: '@',
callback: function(doc, element) { $("#recipeId").val(doc._id); },
collection: Recipes,
field: "recipe",
filter: { deleted: false },
selector: function(match) { return getRecipeExpression($("#ingredient").val()); },
template: Template.recipeDropdown
}
]
}
},
In this scenario only the first collection is being searched. Is this possible to do without the fix talked about further up?
@tgeene try putting the token rule first, before the non-token rule. I didn't have this use case in mind when I started this project, but I think it would work.
Sad to say, this did not work. I was hopeful that the fix would be that easy. I guess I will work on implementing the fix from further up.
Ok, so I am trying to implement the fix using the information from this link: http://stackoverflow.com/a/18880927/586086
When I do this:
'autofillInput': function() {
return {
position: "bottom",
limit: 1000,
rules: [
{
callback: function(doc, element) { $("#ingredientId").val(doc._id); },
subscription: "ingredientsXrecipes",
field: "ingredient",
filter: { deleted: false },
selector: function(match) { return getIngredientExpression($("#ingredient").val()); },
template: Template.ingredientDropdown
}
]
}
},
Or I do this:
'autofillInput': function() {
return {
position: "bottom",
limit: 1000,
rules: [
{
callback: function(doc, element) { $("#ingredientId").val(doc._id); },
collection: Ingredients,
subscription: "ingredientsXrecipes",
field: "ingredient",
filter: { deleted: false },
selector: function(match) { return getIngredientExpression($("#ingredient").val()); },
template: Template.ingredientDropdown
}
]
}
},
I get this error Uncaught Error: Collection name must be specified as string for server-side search
.
What I really don't understand from that link is how I access the information from the combined subscription on the client side so that I can implement it into my code.
Sorry if I am wasting your time, this one is just going right over my head.
I haven't worked on this for a while, but I imagine it involves removing the collection
field altogether, and using the ingredientsXrecipes
publication to push combined data into the autocompleteRecords
collection, which you can then search all at once.
Take a look at https://github.com/mizzao/meteor-autocomplete/blob/master/autocomplete-server.coffee to see what that publication would look like.
I get how to publish the data, the problem I am having is pulling the data.
Example:
Meteor.publish("ingredientsXrecipes", function () {
return [
Ingredients.find({}, { fields: { ingredient: 1, deleted: 1 }, $sort: { ingredient: 1 } }),
Recipes.find({}, { fields: { recipe: 1, deleted: 1 }, $sort: { recipe: 1 } })
];
});
But I can't just call ingredientsXrecipes.find()
. How do I call the data being joined in the publish?
-- Edit--
Sorry if I came off rude, I am just rather confused as to what to do.
You have to publish the cursors to autocompleteRecords
. Try doing the following:
Autocomplete.publishCursor(Ingredients.find( ... ), this);
Autocomplete.publishCursor(Recipes.find( ... ), this);
this.ready();
Instead of the return
cursors you have there.
You can choose whether to filter on the client or the server. I think that if you are using a subscription, you will need to make sure you are sending an appropriate selector to the server (right now your selector
function isn't returning an object even, just a string.)
Ok so I did this:
Server
Meteor.publish("ingredientsXrecipes", function () {
Autocomplete.publishCursor(Ingredients.find({}, { fields: { ingredient: 1, deleted: 1 }, $sort: { ingredient: 1 } }), this);
Autocomplete.publishCursor(Recipes.find({}, { fields: { recipe: 1, deleted: 1 }, $sort: { recipe: 1 } }), this);
this.ready();
});
Client:
'autofillInput': function() {
return {
position: "bottom",
limit: 1000,
rules: [
{
callback: function(doc, element) { $("#ingredientId").val(doc._id); },
collection: Autocomplete,
field: "ingredient",
filter: { deleted: false },
selector: function(match) { return getIngredientExpression($("#ingredient").val()); },
template: Template.ingredientDropdown
}
]
}
},
And the error I got: Uncaught ReferenceError: Autocomplete is not defined
.
tgeene, if you did not fix it yet, you need to change to:
collection: ingredientsXrecipes
in the rules array