In the following meteor code:
Template.postsList.helpers({
posts: function() {
return Posts.find();
}
});
can we not return Posts.find() directly?
posts: Posts.find()
I'm completely changing my answer based on what Pepe-LG has pointed out. The build process only takes into account the html in your templates, so helpers play no part here. In fact, what you have above is perfectly legal, and will work perfectly with reactivity, provided you have declared the Posts collection before the template helper is registered - i.e. the collection needs to be declared in a deeper directory than the helper function, or in a lib folder, as per load order.
Related
I have a feeling that it must be possible to point to template helpers from one template to another. Does anyone know how to do this?
I see in the console that I have access to the Template I want: i.e. Template.Users_edit_page.
And it looks like there is a __helpers object with all the templates defined (Template.Users_edit_page.__helpers).
How can I do something along the lines of:
Template.User_form.prototype.helpers = Template.Users_edit_page.helpers__
and then ideally any helper called from the User_form template (which is a child of the Users_edit_page) would run the Users_edit_page template helper
While I fully encourage digging into the internals of a framework to better understand what it is doing, directly linking into implementation details like this (e.g. *.__helpers) is generally not a good idea, as framework developers may change implementation details breaking your code.
When you use the public APIs you can expect less breaking changes, and advanced notice before that happens (e.g., APIs marked for future deprecation).
As I mentioned in your other question the most flexible approach to sharing helpers across templates is with Template.registerHelper.
However if you need something more targeted you can define your functions as standalone javascript functions:
passwordSecure = function(password) {
return password.length > 8;
};
validEmail = function(email) {
return email.contains('#');
};
Then include them as helpers in all the templates you want them in like this:
Template.User_form.helpers({
'passwordSecure': passwordSecure,
'validEmail': validEmail,
});
I have two update forms, one for each of two collections, which have identical before update hooks.
before:{
update: function(docId, modifier, template){
console.log(arguments);
return modifier;
}
}
One gives me:
["eEWR4xqdZjdprKGN7", Object, Blaze.TemplateInstance]
Which is exactly what I expect and all is great.
The other gives me:
[Object, Blaze.TemplateInstance]
Object here has $set and $unset keys with corresponding Objects giving me the values I expect to see that I put in my form.
Beyond that... I'm using autosave with both forms. I'm not sure what other information to post. I have a LOT of code and pretty beefy schemas, and I don't know what would cause this or where to start.
The problem it's giving me is that I have a helper function registered to update the forms on their respective templates using Meteor's awesome reactive stuff, which isn't happening on the second form. But it works on the first.
Template.updatePerson.helpers({
getDocument: function(){
return people.find(this.person_id).fetch()[0];
}
});
Again, these two forms are nearly identical except for the schemas and names, but I've tried lots of adjusting to the second schema with no change.
Anyone who can tell me why those two arguments coming back are different would be greatly appreciated.
Ends up my helper on the second template wasn't properly pulling the document ID (looking for wrong key). The results I was seeing must have been from autoform not having access to a document for its update method.
The popular accounts-entry package has an iron-router related bug in it. I believe the later versions of iron-router changed to work better as middleware and so a call to Router.routes
At line 87 of this file the following code is used:
_.each Router.routes, (route)->
exclusions.push route.name
# Change the fromWhere session variable when you leave a path
Router.onStop ->
# If the route is an entry route, no need to save it
if (!_.contains(exclusions, Router.current().route?.getName()))
Session.set('fromWhere', Router.current().path)
Unfortunately it does not seems like doing an _.each on Router.routes is a solution that works anymore because Router.routes does not return and object with .name properties in it.
How would you get the name of all the routes with the latest iron-router?
This one is a little tricky : in the latest version of iron:router, Router.routes is now defined as an array of functions.
Thing is, functions already have a default name property in JS which contains the name the function was assigned on definition.
var myFunc = function funcName(){...};
console.log(myFunc.name); // == "funcName"
Fortunately, there is a getName method defined on the route items of the array and you can use this piece of code to iterate over all routes and get their name :
_.each(Router.routes, function(route){
console.log(route.getName());
});
I'm working on a meteor app, and as part of it it would be very nice to return some static pages containing JSON.
The JSON they return is generated by running some node (connecting to the Twitter API), however it does not reflect any underlying Meteor collection, so I don't think any of the packages that allow you to build an API on your meteor app would be appropriate.
I can see that one solution is to do this part outside of meteor, however I like the idea of only having one thing to deploy and wondered if there is a solution in meteor, possibly by making a package?
Yes, as justswim already said in the comments, I think you are looking for something like this:
Router.map(function () {
this.route('serverFile', {
path: '/posts/:user',
where: 'server',
action: function () {
var user = this.params.user
// get your data from Twitter API, e.g., using the HTTP package.
this.response.end(JSON.stringify(yourobject));
}
});
});
You can easily define a meteor API using the Meteor iron-router. Just define the route that you want to serve as the call for your api. When a user hits this route, your app will render the corresponding template (in which you can place the static json).
In your Router's map function, you might have something like this:
Router.map(function () {
/**
* The route's name is "jsonTemplate"
* The route's template is also "jsonTemplate"
* The template will be rendered at http://yourapp.com/apiEndpoint
*/
this.route('jsonTemplate', {
path: '/apiEndpoint',
template: 'jsonTemplate'
});
});
I am busy creating a meteor.d.ts to support my Typescript developments on the Meteor.js platform. Current status can be found here
With that said, I am having issues abstracting two typical javascript patterns.
The first one Template.myTemplate.events(eventMap), where myTemplate can be dynamically created by the user.
Second, the ability to map this to a different interface. Meteor uses the pattern a lot. For instance, when calling Meteor.methods(..methods..), the methods are given access to this.isSimulation() which is not visible anywhere else.
Kind of difficult to explain, so a look at the meteor documentation may help
Any idea how to declare these two patterns?
Thank you.
MyTemplate solution
Provide two interfaces to the user. One that he can use to add new templates to Template. Another to allow him to specify the features of a Template:
interface ITemplate{
}
interface ITemplateStatic{
events:Function;
}
declare var Template:ITemplate;
// the user's code:
interface ITemplate{
myTemplate:ITemplateStatic;
}
Template.myTemplate.events({});
This solution
To answer your second question about this. The only way to do that is to expose the signatures as an interface. It is then the responsibility of the typescript user to get the proper type if he needs it. There is no way to implicity specify the type of this inside a function.
declare module meteor{
interface IMethod{
// A simple sample
isSimulation:boolean;
}
}
declare var Meteor;
// the user experience
Meteor.methods({
foo: function (arg1, arg2) {
var item:meteor.IMethod = this;
console.log(item.isSimulation); // now the signature is enforced
return "some return value";
}
});
Ofcourse I leave the naming convention up to you :)