Serving 'static' node pages with Meteor - meteor

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'
});
});

Related

Meteor page reload with Roles

I am having a problem with Roles in my application when I reload the page. If I use the buttons and so on and navigate like you should on a website the problem is not there.
But what is the problem? In my meteor template, I should show a different view for admins and normal users, so in my template onRendered function I check the role and react on that. Here follows the code:
/* Predefined changes to current html are done in this function!*/
Template.Planning.onRendered(function () {
var userid = Meteor.userId();
if (Roles.userIsInRole(userid,'admin', Roles.GLOBAL_GROUP)){
//do something
}
});
For a specific reason the code inside the if-block is not executed when I am logged in as admin but reload the page. It does work when I visit it using the navigationbar, so I guess the Roles are not yet loaded when the onRendered-function is called. How can I fix this issue?
The package alanning:roles works in a way, that it "autopublishes" the roles definitions to the client, so that you are able to have them available "immediately".
Immediately means in this case, when their subscription is ready. Until then the function Roles.userIsInRole will not return anything truthy.
In order to check of they are available use the reactive Roles.subscription.ready() method.
If you have trouble with reactivity in onRendered you may check for the roles in autorun of onCreated.
For example:
Template.Planning.onCreated(function () {
const instance = this
instance.state = new ReactiveDict()
instance.autorun(() => {
if (Roles.subscription.ready()) {
var userid = Meteor.userId()
if (Roles.userIsInRole(userid,'admin', Roles.GLOBAL_GROUP)){
instance.state.set('isAdmin', true) // reactive data source
}
}
})
})
Using it in a router
You can even use this method on the router level in order to "wait" for all the roles to be loaded. This makes sense especially when your client routing logic makes heavy use of roles to manage access.
Note on Security
Don't forget, that this is just UI Candy. Roles (as well as routes) on the client can be bypassed. Re-check every method call and subscription that are sensitive twice in side the methods / publications using Roles.userIsInRole.

Symfony (a bit more dynamic ?) routing

I am new to symfony. As an exersice I`m trying to make some basic cms.And I was wondering is this aproach of routing wrong:
/**
* #Route("/back-office/", name="back-office")
*/
public function indexAction(Request $request,$page="")
{
switch($page){
case "":
return $this->render('CmsBundle:BackOffice:index.html.twig');
break;
default:
return $this->render('CmsBundle:BackOffice:site-map.html.twig');
break;
}
}
This is my yaml confing:
back_office_pages:
path: /{page}
defaults: { _controller: CmsBundle:BackOffice:index}
By using this aproach I wont have to configure each route in the yaml file. Since routes may vary. But I am not quite sure this is the symfony way of doing things so I decided to ask for advice..
What I`m trying to achive:
Lets say we have a user that have less back-end programing expirience or not at all and he stumbuled upon the CMS. The goal is to add front end pages using some user interface. Then we store the pages(slug) in the database. In the index action we retrive this data. From the database we can also assing template to a page (we need the user to have at least some html+css+twig).
So what we do is get the pages that user added :
ex : Gallery, Contacts
we check the request url
and if the page requested is in the array from the database we return the template related to the page.
NOTE:
If you disagree with this method please do not bash me but eplain why is this wrong. Because as I said I am still new with the framework.
Try setting your routing to:
back_office_pages:
resource: "#CmsBundle/Controller/"
type: annotation
to set up Routing Annotations inside your CmsBundle.
Then, your action should be working using the url "/back-office/{page}"

Returning meteor collection in helper function

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.

List Meteor methods registered with Meteor.methods()?

Wondering if there was a way to get a list of the current Meteor.methods that have been registered.
for example if a post method is registered like so:
Meteor.methods({
post: function() {
//code
}
});
Is there a way to access a list of these methods? Ideally it would be via a method but if it was stored in an accessible variable like Meteor.__methods that would work as well.
I've combed through the documentation and the Meteor global in the browser but did no find anything useful. Any Ideas?
After Digging more on the Server side of meteor, it appears that the methods are stored in an array Meteor.default_server.method_handlers which is accessible on the server but not on the client.
Only way to expose it client side seems to be registering a method server side and then returning a list of the keys.
On the client you can do:
Meteor.connection._methodHandlers
It gives you a dictionary of function names to functions.

Using async configuration in AngularJS directive

I have a directive that looks at configuration to figure out what template to use. It used to work great; I had a Config service that just returned an object with config values, and then I did something like this:
if (Config.Values.ReleaseVersion < 1.0) {
template = 'partials/pagebeta.html';
}
else {
template = 'partials/page.html';
}
templateUrl: template
Recently a problem was introduced. My Config service has to get values from a json file. Now because getting config is async, I am now passing back a promise from the Config service. This is creating problems for me in my directive - I can't do this:
var template;
Config.then(function(config) {
if (config.Values.ReleaseVersion < 1.0) {
template = 'partials/pagebeta.html';
}
else {
template = 'partials/page.html';
}
});
templateUrl: template
Any suggestions are appreciated!
If your templateUrl depends on the value computed asynchronously you can't use the directive's templateUrl property anymore and you will be obliged to use lower-level API, namely $http and $compile.
Roughly what you need to do (only possible in the linking function) is to retrieve template's content using $http (don't forget to involve $templateCache!) and then compile template's content "manually".
It might sound like it is a lot of work but in practice it is rather straightforward. I would suggest having a look at the ngInclude directive sources where this pattern is used.

Resources