Upload
pavel-kurnosov
View
296
Download
0
Embed Size (px)
Citation preview
Concepts• Client and Server
Define a route that only should run on the server, or a route that should only run on the client
• ReactivityRoute functions and most hooks are run in a reactive computation
Rendering Templates
<template name="Post"> <h1>Post: {{title}}</h1> </template>
Router.route('/post/:_id', function () { this.render('Post'); });
Rendering Templates with Data
Router.route('/post/:_id', function () { this.render('Post', { data: function () { return Posts.findOne({_id: this.params._id}); } }); });
Layouts<template name="ApplicationLayout"> <header> <h1>{{title}}</h1> </header>
<aside> {{> yield "aside"}} </aside>
<article> {{> yield}} </article>
<footer> {{> yield "footer"}} </footer> </template>
Router.route('/post/:_id', this.layout('ApplicationLayout');
// render the Post template into the "main" // {{> yield}} this.render('Post');
// render the PostAside into the yield "aside" // {{> yield "aside"}} this.render('PostAside', {to: 'aside'});
// render the PostFooter into the yield "footer" // {{> yield "footer"}} this.render('PostFooter', {to: 'footer'}); });
Setting Region Data ContextsRouter.route('/post/:_id', function () { this.layout('ApplicationLayout', { data: function () { return Posts.findOne({_id: this.params._id}) } });
this.render('Post', { data: function () { return Posts.findOne({_id: this.params._id}) });
this.render('PostAside', { to: 'aside', data: function () { return Posts.findOne({_id: this.params._id}) }); });
Route Parameters
// given the url: "/post/5?q=s#hashFrag" Router.route('/post/:_id', function () { var id = this.params._id; var query = this.params.query;
// query.q -> "s" var hash = this.params.hash; // "hashFrag" });
• Parameters• Query string • Hash
Using Links
With JavaScriptRouter.go('/one');
With RedirectsRouter.route('/one', function () { this.redirect('/two'); });
Links to Server RoutesRouter.route('/download/:filename', function () { this.response.end('some file content\n'); }, {where: 'server'});
<a href="/download/name">Download File</a>
Named Routes
Access by nameRouter.route('/posts/:_id', function () { this.render('Post'); }, { name: 'post.show' });
Router.routes[‘post.show’];
Router.go(‘post.show');
Router.go('post.show', {_id: 1}, {query: 'q=s', hash: 'hashFrag'});
Template Lookup
The router will by default look for a template named ItemsShow
Router.route('/items/:_id', {name: 'items.show'});
Router.setTemplateNameConverter(function (str) { return str; });
Set the converter
Path and Link Template Helpers
pathFor<a href="{{pathFor route='post.show' data=getPost query='q=s' hash='frag'}}">Post Show</a>
urlForFor route /posts/1 would generate http://mysite.com/posts/1
linkToThe linkTo helper automatically generates the html for an anchor tag along with the route path for the given route, parameters, hash and query.
{{#linkTo route="post.show" data=getData query="q=s" hash="hashFrag" class="my-cls"}}
SubscriptionsRouter.route('/post/:_id', function () { // add the subscription handle to our waitlist this.wait(Meteor.subscribe('item', this.params._id)); // OR this.subscribe('item', this.params._id).wait(); // OR
subscriptions: function() { // returning a subscription handle or an array of subscription handles return Meteor.subscribe('item', this.params._id); },
if (this.ready()) { this.render(); } else { this.render('Loading'); } });
The waitOn Option
Router.route('/post/:_id', { // this template will be rendered until the subscriptions are ready loadingTemplate: 'loading', waitOn: function () {
// return one handle, a function, or an array return Meteor.subscribe('post', this.params._id); },
action: function () { this.render('myTemplate'); } });
Same effect but automatically short-circuits your route action and any before hooks, and renders a loadingTemplate instead
Server RoutingRouter.route('/download/:file', function () { // NodeJS request object var request = this.request;
// NodeJS response object var response = this.response;
this.response.end('file download content\n'); }, {where: 'server'});
Restful Routes
Router.route('/webhooks/stripe', { where: 'server' }) .get(function () { // GET /webhooks/stripe }) .post(function () { // POST /webhooks/stripe }) .put(function () { // PUT /webhooks/stripe })
The waitOn Option
Router.route('/post/:_id', { // this template will be rendered until the subscriptions are ready loadingTemplate: 'loading', waitOn: function () {
// return one handle, a function, or an array return Meteor.subscribe('post', this.params._id); },
action: function () { this.render('myTemplate'); } });
Same effect but automatically short-circuits your route action and any before hooks, and renders a loadingTemplate instead
HooksHooks that are running in reactive computation, provide a way to plug into the process of running a route, typically to customize rendering behavior or perform some business logic
Router.onBeforeAction(function () { only: [‘admin'],
if (!Meteor.userId()) { this.render('Login'); } else { this.next(); } });
Available Hooks• onRun• onRerun
Must call this.next()
• onBeforeActionMust call this.next()
• onAfterAction• onStop
Controller
Betefits• Inheritance• Organization
PostController = RouteController.extend({ layoutTemplate: 'PostLayout',
template: 'Post',
waitOn: function () { return Meteor.subscribe('post', this.params._id);
},
data: function () { return Posts.findOne({_id: this.params._id}) },
action: function () { this.render(); } });
Reactive State Variables
Router.route('/posts/:_id', {name: 'post'});
PostController = RouteController.extend({ action: function () { // set the reactive state variable "postId" with a value // of the id from our url this.state.set('postId', this.params._id); this.render(); } });
controller.state.get('postId')
Legacy Browser Support
http://localhost:3000/items/5?q=s#hashFrag
http://localhost:3000/#/items/5?q=s&__hash__=hashFrag
Router.route('/items/:_id', function () { var id = this.params._id; // "5" var query = this.params.query; // {q: "s"} var hash = this.params.hash; // "hashFrag" });
Route Options
Router.route('/post/:_id', { name: 'post.show', path: '/post/:_id', controller: 'CustomController', template: 'Post', layoutTemplate: 'ApplicationLayout', yieldRegions: { 'MyAside': {to: 'aside'}, 'MyFooter': {to: 'footer'} }, subscriptions: function() { this.subscribe('items'); // add the subscription to the waitlist this.subscribe('item', this.params._id).wait(); }, waitOn: function () { return Meteor.subscribe('post', this.params._id); }, //This function can also be used by hooks and plugins. data: function () { return Posts.findOne({_id: this.params._id}); }, onRun: function () {}, onRerun: function () {}, onBeforeAction: function () {}, onAfterAction: function () {}, onStop: function () {}, action: function () { // render all templates and regions for this route this.render(); } });
Global Default Options
Router.configure({ layoutTemplate: 'ApplicationLayout',
template: 'DefaultTemplate' });
Plugins
Router.plugin('dataNotFound', {notFoundTemplate: 'notFound'});
For Specific RoutesRouter.plugin('dataNotFound', { notFoundTemplate: 'NotFound', except: ['server.route'] // or only: ['routeOne', 'routeTwo'] });
Creating Plugins
Iron.Router.plugins.loading = function (router, options) { // this loading plugin just creates an onBeforeAction hook router.onBeforeAction('loading', options); };
Packages
meteor add multiply:iron-router-progress meteor add reywood:iron-router-ga joshowens:accounts-entry …