{"action":"created","comment":{"url":"https://api.github.com/repos/emberjs/rfcs/pulls/comments/29402399","id":29402399,"diff_hunk":"@@ -0,0 +1,488 @@\n+- Start Date: 2015-02-27\n+- RFC PR:\n+- Ember Issue:\n+\n+# Summary\n+\n+Eliminates Controllers.\n+\n+# Motivation\n+\n+As Ember has evolved toward a component-centric model, controllers\n+have become redundant and vestigial. This unnecessarily burdens\n+developers with learning an additional concept and forces them to make\n+unnecessary choices.\n+\n+The goal of this design is to describe how to eliminate\n+`Ember.Controller` while maintaining sufficiently rich APIs to do all\n+the important things controllers do.\n+\n+# Scope\n+\n+- Eliminate `Controller` by designing alternative APIs for routing to\n+  a component, maintaining long-lived non-URL state, and using query\n+  parameters.\n+\n+- Simplify the behavior of `Route`'s model hooks. While this is not\n+  strictly needed to achieve the goal of eliminating controllers, it\n+  makes sense to address it while we're redesigning the API between\n+  routes & components anyway.\n+\n+- Consider how routable components relate to asynchronous components,\n+  because they may share concepts or implementation.\n+\n+- Clarify the distinction between Components and Fragments (\"tagless\n+  components\").\n+\n+# Definitions\n+\n+ - **routable component** - a component whose identity and attributes\n+   are determined from the URL at runtime. Routable components are\n+   what go inside `{{outlet}}`s.\n+\n+ - **asynchronous component** - a component with built-in support for\n+   asynchronously loading data, with a friendly API for reflecting\n+   loading and errors states.\n+\n+Both of the above are conceptual definitions for the purposes of this\n+design document. They are not necessarily actual classes or concepts\n+that would need to be taught to new Ember devs.\n+\n+# Detailed design\n+\n+## Routing to a component\n+\n+Our current API for letting a `Route` decide which things to render\n+and where they should go is fairly rich and complex. We can simplify\n+it significantly.\n+\n+### Choosing what component(s) to render\n+\n+The current `Route.render` method is where a `Route` expresses what\n+should actually get rendered. It has a fair bit of complexity that we\n+can deprecate. Today you can say things like:\n+\n+````js\n+this.render('post', {\n+  view: 'special-post',\n+  controller: 'other-controller' ,\n+  model: myPost\n+})\n+````\n+\n+Which lets you pick and choose which template, view, controller, and\n+model to render. There are fairly rich semantics for choosing defaults\n+for each of those things, and allowing views to choose their own\n+template, etc.\n+\n+Instead, we can deprecate the use of the `view`, `controller`, and\n+`model` arguments, and accept a name which will be used to lookup a\n+*component*, not a template. We will also accept arbitrary attributes\n+to set on the component.\n+\n+````js\n+this.render('post', attributes)\n+````\n+\n+The current semantics of `into` and `outlet` would still be preserved:\n+\n+````js\n+this.render('choices', attributes, { into: 'application', outlet: 'sidebar' })\n+````\n+\n+We can maintain transitional compatibility by failing to detect a\n+component and looking for a template instead, using the old behavior\n+for that case.\n+\n+Nested child routes have names like 'parent-route/child-route'. Their\n+corresponding component would also be named\n+'parent-route/child-route', implying that we must support component\n+resolution in a non-flat namespace.\n+\n+Since standalone route templates are going away in favor of\n+components, the current distinction between the `templates` and\n+`templates/components` directories becomes unhelpful. We want to put\n+all of them into just `templates`. Thanks to the introduction of\n+`<element>` and `<fragment>` (see the\n+[Element and Fragment RFC](element-and-fragment)), we can make this\n+transition gracefully.\n+\n+  - A template in `templates` with an `<element>` or `<fragment>` tag is defining a Component or Fragment.\n+  - A template in `templates` with neither is a legacy standalone template.\n+  - A template in `templates/components` with neither is a legacy component.\n+\n+### Specifying component attributes\n+\n+We will introduce a new route hook named `attributes`. It receives the\n+route's positional parameters (the same ones that are currently passed\n+to the `model` hook), plus any query parameters defined for the route,\n+and must return a POJO. The POJO's properties may be promises, which\n+will all be resolved in the same way we currently resolve the `model`\n+hook (including invoking `loading` actions as needed). The default\n+`attributes` implementation is:\n+\n+````js\n+attributes: function(params, queryParams) {\n+    return {\n+        model: this.model(params)\n+    }\n+}\n+````\n+\n+(Possible variation for this default implementation: any queryParams\n+that are present get stuffed directly into the attributes as well,\n+alongside `model`.)\n+\n+Unlike today's `model` hook, `attributes` gets called *every* time\n+your route is entered, whether or not `transitionTo` was passed a\n+preexisting model. This eliminates the need for `beforeModel` and\n+`afterModel`, because you can implement either behavior from within\n+your own `attributes` or `model` functions. Therefore, `beforeModel`\n+and `afterModel` are deprecated.\n+\n+This also means we deprecate `refresh`, because routes essentially\n+always refresh. \n+\n+### When Routes can call render\n+\n+Today, `render` is normally called from the `renderTemplate` hook, but\n+it can also be called from action handlers on the route. Calling\n+`render` from action handlers -- outside of a route transition --\n+makes routes unnecessarily stateful and introduces an additional way\n+to do things that are better off done directly from within components\n+and their templates. We will therefore deprecate calling `render`\n+outside of transitions. See Appendix A below for an example of\n+updating this old behavior.\n+\n+Today, `renderTemplate` receives the default controller and the\n+model. But since we don't intend to have controllers anymore, we will\n+deprecate `renderTemplate` in favor of `renderComponents`, which would\n+have a default implementation like:\n+\n+````js\n+renderComponents: function(attributes) {\n+    this.render(this.routeName, attributes);\n+}\n+````\n+\n+The `attributes` argument comes from the new `attributes` hook as\n+described in the previous section. It is resolved with `RSVP.hash`","path":"active/0000-routeable-components.md","position":169,"original_position":169,"commit_id":"ee754ca51cf11cf7fed30ab100f9920c631d5554","original_commit_id":"ee754ca51cf11cf7fed30ab100f9920c631d5554","user":{"login":"chadhietala","id":183799,"avatar_url":"https://avatars.githubusercontent.com/u/183799?v=3","gravatar_id":"","url":"https://api.github.com/users/chadhietala","html_url":"https://github.com/chadhietala","followers_url":"https://api.github.com/users/chadhietala/followers","following_url":"https://api.github.com/users/chadhietala/following{/other_user}","gists_url":"https://api.github.com/users/chadhietala/gists{/gist_id}","starred_url":"https://api.github.com/users/chadhietala/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chadhietala/subscriptions","organizations_url":"https://api.github.com/users/chadhietala/orgs","repos_url":"https://api.github.com/users/chadhietala/repos","events_url":"https://api.github.com/users/chadhietala/events{/privacy}","received_events_url":"https://api.github.com/users/chadhietala/received_events","type":"User","site_admin":false},"body":"Is it possible to have an escape valve for waiting on promises?   The behavior described above forces the transition to wait on the slowest call.  Currently the way you get around this is returning a hash that contains invoked promises.  If this is the default, then maybe the escape valve is \"just use an async component\".","created_at":"2015-04-30T03:58:50Z","updated_at":"2015-04-30T03:58:50Z","html_url":"https://github.com/emberjs/rfcs/pull/38#discussion_r29402399","pull_request_url":"https://api.github.com/repos/emberjs/rfcs/pulls/38","_links":{"self":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/comments/29402399"},"html":{"href":"https://github.com/emberjs/rfcs/pull/38#discussion_r29402399"},"pull_request":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/38"}}},"pull_request":{"url":"https://api.github.com/repos/emberjs/rfcs/pulls/38","id":30198413,"html_url":"https://github.com/emberjs/rfcs/pull/38","diff_url":"https://github.com/emberjs/rfcs/pull/38.diff","patch_url":"https://github.com/emberjs/rfcs/pull/38.patch","issue_url":"https://api.github.com/repos/emberjs/rfcs/issues/38","number":38,"state":"open","locked":false,"title":"Routable Components RFC","user":{"login":"ef4","id":319282,"avatar_url":"https://avatars.githubusercontent.com/u/319282?v=3","gravatar_id":"","url":"https://api.github.com/users/ef4","html_url":"https://github.com/ef4","followers_url":"https://api.github.com/users/ef4/followers","following_url":"https://api.github.com/users/ef4/following{/other_user}","gists_url":"https://api.github.com/users/ef4/gists{/gist_id}","starred_url":"https://api.github.com/users/ef4/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ef4/subscriptions","organizations_url":"https://api.github.com/users/ef4/orgs","repos_url":"https://api.github.com/users/ef4/repos","events_url":"https://api.github.com/users/ef4/events{/privacy}","received_events_url":"https://api.github.com/users/ef4/received_events","type":"User","site_admin":false},"body":"[RFC](https://github.com/ef4/rfcs/blob/routeable-components/active/0000-routeable-components.md)","created_at":"2015-02-27T20:32:33Z","updated_at":"2015-04-30T03:58:50Z","closed_at":null,"merged_at":null,"merge_commit_sha":"febf3aebb42d2dbcef08bdd5bdaa3ca17764a8a2","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/emberjs/rfcs/pulls/38/commits","review_comments_url":"https://api.github.com/repos/emberjs/rfcs/pulls/38/comments","review_comment_url":"https://api.github.com/repos/emberjs/rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/emberjs/rfcs/issues/38/comments","statuses_url":"https://api.github.com/repos/emberjs/rfcs/statuses/ee754ca51cf11cf7fed30ab100f9920c631d5554","head":{"label":"ef4:routeable-components","ref":"routeable-components","sha":"ee754ca51cf11cf7fed30ab100f9920c631d5554","user":{"login":"ef4","id":319282,"avatar_url":"https://avatars.githubusercontent.com/u/319282?v=3","gravatar_id":"","url":"https://api.github.com/users/ef4","html_url":"https://github.com/ef4","followers_url":"https://api.github.com/users/ef4/followers","following_url":"https://api.github.com/users/ef4/following{/other_user}","gists_url":"https://api.github.com/users/ef4/gists{/gist_id}","starred_url":"https://api.github.com/users/ef4/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ef4/subscriptions","organizations_url":"https://api.github.com/users/ef4/orgs","repos_url":"https://api.github.com/users/ef4/repos","events_url":"https://api.github.com/users/ef4/events{/privacy}","received_events_url":"https://api.github.com/users/ef4/received_events","type":"User","site_admin":false},"repo":{"id":31437820,"name":"rfcs","full_name":"ef4/rfcs","owner":{"login":"ef4","id":319282,"avatar_url":"https://avatars.githubusercontent.com/u/319282?v=3","gravatar_id":"","url":"https://api.github.com/users/ef4","html_url":"https://github.com/ef4","followers_url":"https://api.github.com/users/ef4/followers","following_url":"https://api.github.com/users/ef4/following{/other_user}","gists_url":"https://api.github.com/users/ef4/gists{/gist_id}","starred_url":"https://api.github.com/users/ef4/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ef4/subscriptions","organizations_url":"https://api.github.com/users/ef4/orgs","repos_url":"https://api.github.com/users/ef4/repos","events_url":"https://api.github.com/users/ef4/events{/privacy}","received_events_url":"https://api.github.com/users/ef4/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ef4/rfcs","description":"RFCs for changes to Ember","fork":true,"url":"https://api.github.com/repos/ef4/rfcs","forks_url":"https://api.github.com/repos/ef4/rfcs/forks","keys_url":"https://api.github.com/repos/ef4/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ef4/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ef4/rfcs/teams","hooks_url":"https://api.github.com/repos/ef4/rfcs/hooks","issue_events_url":"https://api.github.com/repos/ef4/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/ef4/rfcs/events","assignees_url":"https://api.github.com/repos/ef4/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/ef4/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/ef4/rfcs/tags","blobs_url":"https://api.github.com/repos/ef4/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ef4/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ef4/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/ef4/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ef4/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/ef4/rfcs/languages","stargazers_url":"https://api.github.com/repos/ef4/rfcs/stargazers","contributors_url":"https://api.github.com/repos/ef4/rfcs/contributors","subscribers_url":"https://api.github.com/repos/ef4/rfcs/subscribers","subscription_url":"https://api.github.com/repos/ef4/rfcs/subscription","commits_url":"https://api.github.com/repos/ef4/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/ef4/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/ef4/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/ef4/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/ef4/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/ef4/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ef4/rfcs/merges","archive_url":"https://api.github.com/repos/ef4/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ef4/rfcs/downloads","issues_url":"https://api.github.com/repos/ef4/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/ef4/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/ef4/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/ef4/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ef4/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/ef4/rfcs/releases{/id}","created_at":"2015-02-27T20:30:08Z","updated_at":"2015-04-17T14:45:11Z","pushed_at":"2015-03-13T15:27:20Z","git_url":"git://github.com/ef4/rfcs.git","ssh_url":"git@github.com:ef4/rfcs.git","clone_url":"https://github.com/ef4/rfcs.git","svn_url":"https://github.com/ef4/rfcs","homepage":null,"size":171,"stargazers_count":8,"watchers_count":8,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":8,"default_branch":"master"}},"base":{"label":"emberjs:master","ref":"master","sha":"a3cc226c73fdf9b29d74e85299c16388d3064729","user":{"login":"emberjs","id":1253363,"avatar_url":"https://avatars.githubusercontent.com/u/1253363?v=3","gravatar_id":"","url":"https://api.github.com/users/emberjs","html_url":"https://github.com/emberjs","followers_url":"https://api.github.com/users/emberjs/followers","following_url":"https://api.github.com/users/emberjs/following{/other_user}","gists_url":"https://api.github.com/users/emberjs/gists{/gist_id}","starred_url":"https://api.github.com/users/emberjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emberjs/subscriptions","organizations_url":"https://api.github.com/users/emberjs/orgs","repos_url":"https://api.github.com/users/emberjs/repos","events_url":"https://api.github.com/users/emberjs/events{/privacy}","received_events_url":"https://api.github.com/users/emberjs/received_events","type":"Organization","site_admin":false},"repo":{"id":22664562,"name":"rfcs","full_name":"emberjs/rfcs","owner":{"login":"emberjs","id":1253363,"avatar_url":"https://avatars.githubusercontent.com/u/1253363?v=3","gravatar_id":"","url":"https://api.github.com/users/emberjs","html_url":"https://github.com/emberjs","followers_url":"https://api.github.com/users/emberjs/followers","following_url":"https://api.github.com/users/emberjs/following{/other_user}","gists_url":"https://api.github.com/users/emberjs/gists{/gist_id}","starred_url":"https://api.github.com/users/emberjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emberjs/subscriptions","organizations_url":"https://api.github.com/users/emberjs/orgs","repos_url":"https://api.github.com/users/emberjs/repos","events_url":"https://api.github.com/users/emberjs/events{/privacy}","received_events_url":"https://api.github.com/users/emberjs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/emberjs/rfcs","description":"RFCs for changes to Ember","fork":false,"url":"https://api.github.com/repos/emberjs/rfcs","forks_url":"https://api.github.com/repos/emberjs/rfcs/forks","keys_url":"https://api.github.com/repos/emberjs/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/emberjs/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/emberjs/rfcs/teams","hooks_url":"https://api.github.com/repos/emberjs/rfcs/hooks","issue_events_url":"https://api.github.com/repos/emberjs/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/emberjs/rfcs/events","assignees_url":"https://api.github.com/repos/emberjs/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/emberjs/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/emberjs/rfcs/tags","blobs_url":"https://api.github.com/repos/emberjs/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/emberjs/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/emberjs/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/emberjs/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/emberjs/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/emberjs/rfcs/languages","stargazers_url":"https://api.github.com/repos/emberjs/rfcs/stargazers","contributors_url":"https://api.github.com/repos/emberjs/rfcs/contributors","subscribers_url":"https://api.github.com/repos/emberjs/rfcs/subscribers","subscription_url":"https://api.github.com/repos/emberjs/rfcs/subscription","commits_url":"https://api.github.com/repos/emberjs/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/emberjs/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/emberjs/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/emberjs/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/emberjs/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/emberjs/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/emberjs/rfcs/merges","archive_url":"https://api.github.com/repos/emberjs/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/emberjs/rfcs/downloads","issues_url":"https://api.github.com/repos/emberjs/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/emberjs/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/emberjs/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/emberjs/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/emberjs/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/emberjs/rfcs/releases{/id}","created_at":"2014-08-06T00:49:22Z","updated_at":"2015-04-29T12:57:42Z","pushed_at":"2015-04-20T18:29:32Z","git_url":"git://github.com/emberjs/rfcs.git","ssh_url":"git@github.com:emberjs/rfcs.git","clone_url":"https://github.com/emberjs/rfcs.git","svn_url":"https://github.com/emberjs/rfcs","homepage":null,"size":759,"stargazers_count":268,"watchers_count":268,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":55,"mirror_url":null,"open_issues_count":32,"forks":55,"open_issues":32,"watchers":268,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/38"},"html":{"href":"https://github.com/emberjs/rfcs/pull/38"},"issue":{"href":"https://api.github.com/repos/emberjs/rfcs/issues/38"},"comments":{"href":"https://api.github.com/repos/emberjs/rfcs/issues/38/comments"},"review_comments":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/38/comments"},"review_comment":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/38/commits"},"statuses":{"href":"https://api.github.com/repos/emberjs/rfcs/statuses/ee754ca51cf11cf7fed30ab100f9920c631d5554"}}}}