Hey all,
I’ve submitted a pull request for Ember to have integration to handle the document.title
of the app (see: https://github.com/emberjs/ember.js/pull/3689). I’ll describe in short the goals that I have and how to implement various patterns using the approach that I’ve created in this post. Any feedback on this proposal is very welcome, as I’m fairly sure that I’ve overlooked a fair bit of use cases.
The app that I’m currently working on is mostly forms that, upon saving the form, I’d like to update the title of the document to keep the page of the title as fresh as possible. Some apps use the show
/ edit
pattern; ours doesn’t. The approach taken for managing the title of the page doesn’t care which approach you take, and allows you to configure various bits about the title and to also completely override the title implementation.
For a basic app like discuss, the implementation would be as follows:
var Discuss = Ember.Application.create();
Discuss.Router = Ember.Router.extend();
Discuss.Router.map(function () {
this.resource('list');
this.resource('topic');
});
Discuss.ApplicationRoute = Ember.Route.extend({
title: Ember.computed.oneWay('controller.name') // The name of the forum
});
Discuss.TopicRoute = Ember.Route.extend({
title: Ember.computed.oneWay('controller.title') // The name of the topic
});
This requires only that the associated controller has the property that the title needs on it. If data from another controller is needed, it should be provided via the needs
property on the controller associated with the route.
For a less trivial example of a REST-like application, I’m going to use Ravelry’s title design.
var Ravelry = Ember.Application.create();
Ravelry.Router = Ember.Router.extend({
title: function () {
var tokens = this.get('titleTokens'),
title = tokens.unshift(),
subject = tokens.join(" "),
divider = ": ";
if (subject === "") {
subject = "a knit and crochet community";
divider = " - ";
}
return title + divider + subject;
}.property('titleTokens')
});
Ravelry.Router.map(function () {
this.resource('user', function () {
this.route('stash');
this.route('projects');
this.route('queue');
this.route('favorites');
});
}):
Ravelry.ApplicationRoute = Ember.Route.extend({
title: "Ravelry"
});
Ravelry.UserRoute = Ember.Route.extend({
title: function () {
return this.get('controller.name') + "'s";
}.property('controller.name')
});
Ravelry.UserIndexRoute = Ember.Route.extend({
title: "Profile"
});
Ravelry.UserProjectsRoute = Ember.Route.extend({
title: "Projects"
});
Ravelry.UserStashRoute = Ember.Route.extend({
title: "Stash"
});
Ravelry.UserQueueRoute = Ember.Route.extend({
title: "Queue"
});
Ravelry.UserFavoritesRoute = Ember.Route.extend({
title: "Favorites"
});
Upon visiting /
in this application, the title would be: Ravelry - a knit and crochet community
. Visiting a user’s page, you would see Ravelry: purrrl's Profile
; their stash Ravelry: purrrl's Stash
and so on…
If you have a more complex use case and would like titles to be custom per route, then the following recipe would do quite well:
App.Router = Ember.Router.extend({
title: Ember.computed.oneWay('titleTokens.lastObject')
});
This would make the title dependent on the title of your route, allowing fine-grained control over your route.
Another useful recipe to consider is notifications using the document.title
(for IM applications, for example.):
App.Router = Ember.Router.extend({
notification: null,
shouldShowNotification: false,
title: function () {
if (this.get('shouldShowNotification')) {
return this.get('notification');
} else {
return this._super();
}
}.property('titleTokens', 'shouldShowNotification')
});
App.ApplicationRoute = Ember.Route.extend({
actions: {
notify: function (message) {
var self = this.get('router');
self.set('notification', message);
if (message) {
this._timer = setInterval(function () {
self.toggleProperty('shouldShowNotification');
}, 500);
self.set('shouldShowNotification', true);
} else {
self.set('shouldShowNotification', false);
clearInterval(this._timer);
}
}
}
});
Using this pattern, you can send an action called notify
with a message and it will flash every half second until you call notify
with a falsy value.
Any more patterns would be welcome, and please poke any holes you can in the proposal :D.
Cheers~