Search in meteor using Easy Search Error: MinimongoEngine - meteor

I am currently using this guide to perform an easy search on weather.
http://matteodem.github.io/meteor-easy-search/
It generates an error like the following:
TypeError: MinimongoEngine is not a constructor
This is how I am implementing the search:
Packages installed:
matteodem:easy-search
easy:search
easysearch:components
easysearch:core
client/searchBox.html
<template name="searchBox">
{{> EasySearch.Input index=playersIndex }}
<ul>
{{#EasySearch.Each index=playersIndex }}
<li>Name of the player: {{name}}</li>
{{/EasySearch.Each}}
</ul>
</template>
client/searchBox.js
// On Client
Template.searchBox.helpers({
playersIndex: () => PlayersIndex,
})
lib/collection.js
import { Index, MinimongoEngine } from 'meteor/easy:search'
// On Client and Server
const Players = new Mongo.Collection('players')
const PlayersIndex = new Index({
collection: Players,
fields: ['name'],
engine: new MinimongoEngine()
})
Some idea of how to solve it, I’m new to meteor, so any help would be appreciated. If I’m doing something wrong, please help.

ar, I don't know how you have solved or left that but I have solved as like using EasySearch.MongoDB & importing EasySearch
import { EasySearch } from 'meteor/easy:search'
export const EventsIndex = new EasySearch.Index({
collection: Events,
fields: ['title', 'description'],
engine: new EasySearch.MongoDB()
})

In the github example code MongoDBEngine is used instead of MinimongoEngine.
Looking at the package source it looks like both MinimongoEngine and MongoDBEngine are exported. Could it be that it wants MinimongoEngine on the client and MongoDBEngine in the server context? Is that type error showing up in the server console or in your browser console?

Related

How to get data at the beginning in Vue page

My problem is I want to get data at the beginning of the vue page. I tried to put those codes in mount() but it's still too late. After searching I think maybe created() is a good place or any places before generating the html code. But as I need to import a function so it seems that I cannot use created(). So I am wondering what's the better option to do that?
Right now my code looks like this
<template>
{{ username }}
<template>
<script>
import firebase from 'firebase';
export default {
name: 'page',
data() {
return {
username = "whatever",
}
}
mounted() {
var firebaseConfig = {
// some code
};
firebase.initializeApp(firebaseConfig);
this.username = username from firebase
},
}
</script>
But when I reload the page it shows whatever instead of the username I get from the firebase.
The firebase function needs to resolve before you set the username property. Async the mounted function & await the firebase call
The data initialization looks a bit odd to me.
Usually data should be an Object
In Your case i would suppose it to look something like this:
data: {
username: 'whatever'
}
And further on there seems to be a missing , between data and mounted.
I created a fiddle that works
It is not a sfc but i think it is enough to make things clear.

TypeError: Cannot read property <template name> of undefined when creating package

I am trying to create a package for Meteor, unsuccessfully unfortunately. I'm on Meteor 1.8.1. My goal is to make a template for a button that I can use in my application like this {{> testButton}} (I am just trying it out atm).
package.js
Package.describe({
name: 'button-test',
version: '0.0.1',
summary: '',
git: '',
documentation: 'README.md'
});
Package.onUse(function (api) {
api.use(['ecmascript']);
api.use(['session', 'templating'], ['client', 'server']);
api.mainModule('button-test.js');
});
Package.onTest(function (api) {
api.use('ecmascript');
api.use('tinytest');
api.use('button-test');
api.mainModule('button-test-tests.js');
});
button-test.js
// Variables exported by this module can be imported by other packages and
// applications. See button-test-tests.js for an example of importing.
import './testButton.js';
testButton.js
import { Template } from 'meteor/templating';
Template.testButton.events({
'click #buttonT': () =>
console.log('Clicked the button')
});
testButton.html
<template name="testButton"><button id="buttonT">TEST</button></template>
I have some problems with this;
Running the code like this returns the error TypeError: Cannot read property 'testButton' of undefined. So there is a problem with Template, but I don't know what it is, since I have added it with api.use
When I try to add import ./testButton.html to testButton.js I get the error Error: Cannot find module './testButton.html'
I looked at the source code for accounts-ui-unstyled, but this is written on an older meteor version.
Does anybody have an idea as to what I am doing wrong?
The problem was with the api.mainModule, I solved it by having my Package.onUse like this:
Package.onUse(function (api) {
api.use(['templating', 'blaze'], 'client');
api.use('ecmascript');
api.addFiles(['button-test.js'], 'client');
});
After using the addFiles instead of mainModule, I could import the html and the Template problem disappeared. I have no idea why this works and mainModule does not, but hey, it does.

VueJS rendering data from REST service

I've attempted to render data from a http request to a component which is working fine, the issue is that it's null while the data is being fetched. While the data is null the console is throwing a TypeError until all the data is loaded and committed to the Vuex store.
All is working how I'd suspect, I'm just trying to figure how I can prevent the errors being thrown and to wait until all the appropriate data is fetched. I've seen others using v-if to check if the data is null which will work. It just seems tedious and that there surly is a better way to achieve the same outcome, without an application riddled with v-if statements checking every single state.
I came across this solution but it's still not working how I thought it would, I'm still receiving the same console errors. Am I using these key words correctly and are they in the correct location? since nothing has changed with every variation I've tried.
Vuex Action:
const actions = {
getThread ({ commit }, payload) {
Vue.http
.get(`http://localhost:9000/threads/${payload.id}`)
.then(async response => {
commit(FETCH_THREAD, await response.data)
})
}
}
This is within my vue file calling upon the action:
created () {
this.$store.dispatch('getThread', {id: '59280ab5acbafb17af9da902'})
}
I assume you are trying to display something from your store in your template. The problem is, Vue cannot render something that does not exist yet. The solution is to check whether the data exists or not.
Let's take this component example:
<template>
<div>
{{ someObject.name }}
</div>
</template>
<script>
export default {
data () {
return {
someObject: null
}
},
methods: {
fetchTheObject () {
this.someObject = {
id: 1,
name: 'My object'
}
}
},
created () {
setTimeout( () => {
this.fetchTheObject()
}, 3000)
}
}
</script>
As you can see, you will get an error in your console because someObject.name does not exist until fetchTheObject() has been called.
The solution is to put some v-if attribute to control that:
<template>
<div>
<span v-if="someObject === null">Fetching the object</span>
<span v-else>{{ someObject.name }}</span>
</div>
</template>
In general, you would want to display some spinner to show the user that something is loading...
Hope this helps
EDIT: And forget about the async await in your code, you don't need that here

How can I change the subscriptions query parameters in react-komposer (meteor) from a child component?

I'm building an app with Meteor using the react-komposer package. It is very simple: There's a top-level component (App) containing a search form and a list of results. The list gets its entries through the props, provided by the komposer container (AppContainer). It works perfectly well, until I try to implement the search, to narrow down the results displayed in the list.
This is the code I've started with (AppContainer.jsx):
import { Meteor } from 'meteor/meteor';
import { composeWithTracker } from 'react-komposer';
import React, { Component } from 'react';
import Entries from '../api/entries.js';
import App from '../ui/App.jsx';
function composer(props, onData) {
if (Meteor.subscribe('entries').ready()) {
const entries = Entries.find({}).fetch();
onData(null, {entries});
};
};
export default composeWithTracker(composer)(App);
App simply renders out the whole list of entries.
What I'd like to achieve, is to pass query parameters to Entries.find({}).fetch(); with data coming from the App component (captured via a text input e.g.).
In other words: How can I feed a parameter into the AppContainer from the App (child) component, in order to search for specific entries and ultimately re-render the corresponding results?
To further clarify, here is the code for App.jsx:
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<div>
<form>
<input type="text" placeholder="Search" />
</form>
<ul>
{this.props.entries.map((entry) => (
<li key={entry._id}>{entry.name}</li>
))}
</ul>
</div>
);
}
}
Thanks in advance!
I was going to write a comment for this to clarify on nupac's answer, but the amount of characters was too restrictive.
The sample code you're looking for is in the search tutorial link provided by nupac. Here is the composer function with the corresponding changes:
function composer(props, onData) {
if (Meteor.subscribe('entries', Session.get("searchValues")).ready()) {
const entries = Entries.find({}).fetch();
onData(null, {entries});
};
};
The solution is the session package. You may need to add it to your packages file and it should be available without having to import it. Otherwise try with import { Session } from 'meteor/session';
You just need to set the session when submitting the search form. Like this for instance:
Session.set("searchValues", {
key: value
});
The subscription will fetch the data automatically every time the specific session value changes.
Finally, you'll be able to access the values in the publish method on the server side:
Meteor.publish('entries', (query) => {
if (query) {
return Entries.find(query);
} else {
return Entries.find();
}
});
Hope this helps. If that's not the case, just let me know.
There are 2 approaches that you can take.
The Subscription way,
The Meteor.call way,
The Subscription way
It involves you setting a property that you fetch from the url. So you setup your routes to send a query property to you Component.Your component uses that property as a param to send to your publication and only subscribe to stuff that fits the search criteria. Then you put your query in your fetch statement and render the result.
The Meteor.call way
Forget subscription and do it the old way. Send your query to an endpoint, in this case a Meteor method, and render the results. I prefer this method for one reason, $text. Minimongo does not support $text so you cannot use $text to search for stuff on the client. Instead you can set up your server's mongo with text indexes and meteor method to handle the search and render the results.
See what suits your priorities. The meteor.call way requires you to do a bit more work to make a "Search result" shareable through url but you get richer search results. The subscription way is easier to implement.
Here is a link to a search tutorial for meteor and read about $text if you are interested

Pass data to a dynamic template

With meteor updates up to 0.8 my old code stopped working.
Handlebars.registerHelper('getTemplate', function(id, context) {
return Template[id](context);
});
<template name="main">
....
{{{getTemplate templateName context}}}
....
</template>
//somewhere in other template
Template.main.context = {name:value};
This way I was able to render a custom template with custom data. Now I can't find the way to pass context to the dynamic template. With blaze both templateName and context is undefined. Any advice?
Meteor >= 0.8.2
You can use the UI.dynamic helper render a template with a context which are both specified dynamically. For more details, check out this issue.
Meteor < 0.8.2
Both of these issues are addressed on this page in the meteor wiki.
Handlebars.registerHelper is now UI.registerHelper as seen here.
Examples of how to dynamically render templates are shown here.
update
Actually, given the requirements, a solution doesn't seem very obvious to me. If you are willing to use session variables to set the template name and context, AND only have one dynamic template in your main template. You could do something like this:
<body>
{{> main}}
</body>
<template name="main">
{{> getTemplate context}}
</template>
<template name="dogs">
<p>There are {{animals}} dogs!</p>
</template>
<template name="cats">
<p>There are {{animals}} cats!</p>
</template>
Session.setDefault('templateName', 'dogs');
Session.setDefault('templateContext', {animals: 10});
Template.main.getTemplate = function() {
return Template[Session.get('templateName')];
};
Template.main.context = function() {
return Session.get('templateContext');
};
This was brought up on the meteor-core list and #dgreensp, MDG core dev working on Blaze, opened Ticket #2007 - How to render a template to HTML with data so they definitely know about this and I'd expect a fix to land soon after 0.8.0.
He also included the following workaround:
var toHTMLWithData = function (kind, data) {
return UI.toHTML(kind.extend({data: function () { return data; }}));
};
The github ticket has further discussion and alternate code snippets that you may find useful.

Resources