{"id":17772743,"url":"https://github.com/jamesplease/backbone-architecture-101","last_synced_at":"2025-04-01T15:21:36.997Z","repository":{"id":66133725,"uuid":"41527751","full_name":"jamesplease/backbone-architecture-101","owner":"jamesplease","description":"A short, opinionated guide to Backbone architecture.","archived":false,"fork":false,"pushed_at":"2015-09-02T13:45:11.000Z","size":152,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-07T09:42:02.850Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamesplease.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-28T04:50:18.000Z","updated_at":"2023-03-10T08:28:26.000Z","dependencies_parsed_at":"2023-02-19T23:15:34.517Z","dependency_job_id":null,"html_url":"https://github.com/jamesplease/backbone-architecture-101","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesplease%2Fbackbone-architecture-101","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesplease%2Fbackbone-architecture-101/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesplease%2Fbackbone-architecture-101/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesplease%2Fbackbone-architecture-101/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesplease","download_url":"https://codeload.github.com/jamesplease/backbone-architecture-101/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246660089,"owners_count":20813339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-26T21:40:38.433Z","updated_at":"2025-04-01T15:21:36.978Z","avatar_url":"https://github.com/jamesplease.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# backbone-architecture-101\n\nA short, opinionated guide to Backbone architecture.\n\n### The Basic Interaction\n\n![](https://cldup.com/Nk908IzFJx.png)\n\nThe \"Basic Interaction\" is a simple pattern that occurs many times throughout a Backbone application. In fact, the\nmajority of your application will likely be the Basic Interaction. The basic interaction describes how two objects\ncan directly communicate with one another. These two objects will be referred to as the \"Parent\" and the \"Child.\"\n\nThe parent and child objects have a single defining quality each: the parent creates the child, and the child\nis created by the parent.\n\nAn example of this are two views. Imagine a view that is a tab navigation bar. When a user clicks a tab, the view\ncreates a child view that displays the tab contents. In this example, the tab navigation bar is the parent,\nand the tab contents view is the child.\n\n**Principles of the basic interaction**\n\n- The parent creates the child\n- The child can itself also be a parent, by creating its own children\n\n- The parent can directly access \"public\" methods on the child\n- The child should not directly access any methods on the parent\n\n- The parent should listen to, and react to, events emitted by the child\n- The child should not listen to, or react to, events emitted by the parent\n\nHere's an example of the basic interaction, using a custom API for rendering children and listening\nto child events (note that nither of these are included in Backbone out-of-the-box).\n\n```js\n// The `TabNavView` is the parent of our `TabContentsView`.\nvar TabNavView = BaseView.extend({\n\n  // When the tab is clicked, the contents view is created\n  onClickTabContents() {\n    this.showChildView('.tab-contents', new TabContentsView());\n  },\n\n  // Listen to when the child view is destroyed, and show a default\n  // \"SelectTabsView\"\n  childEvents: {\n    'destroy': 'showSelectView'\n  },\n\n  // Shows a default view that might tell the user about the different tabs\n  showSelectView() {\n    this.showChildView('.tab-contents', new SelectTabsView());\n  }\n});\n```\n\n**Deeply nested trees**\n\nSometimes a child needs to communicate an event up several levels of views. \"Event forwarding\" is one way to do this.\nEvent forwarding is when an object listens to another object's event, then forwards it along for the sole purpose of\nanother object getting that event. Event forwarding requires a lot of boilerplate code, which I try to avoid. Instead,\nI use Backbone.Radio to \"jump\" up and down view trees.\n\nHere's an example of what event forwarding might look like:\n\n```js\n// If your event handler just re-emits the event, then you're doing event forwarding.\n// I do not like event forwarding.\nthis.listenTo(myChild, 'some:event', () =\u003e {\n  this.trigger('some:event');\n});\n```\n\nHere's an example of using Backbone Radio instead:\n\n```js\n// deeply-nested-child.js\nvar DeeplyNestedChild = View.extend({\n  someMethod() {\n    // Use a channel with a relevant name; probably related to the feature that the views are for\n    var viewChannel = Radio.channel('view-tree');\n    // Emit the event on the channel\n    viewChannel.trigger('some:event');\n  }\n});\n\n// great-grandparent.js\nvar GreatGrandparent = View.extend({\n  initialize() {\n    // Access the channel from this view, too\n    var viewChannel = Radio.channel('view-tree');\n    // Listen and respond to events on the channel\n    this.listenTo(viewChannel, 'some:event', this.onSomeEvent);\n  }\n});\n```\n\n### The \"root\" parent\n\nIn the above section, I outlined a few tips on how two objects typically interact in Backbone. The foundation of the basic\ninteraction described above is that parents create children. But where does the first parent come from?\n\nThe solution is the router. Or, more specifically, a \"route.\"\n\nAll client side applications follow the same underlying algorithm. Simply, it looks like this:\n\n1. The user navigates to a URL\n2. The Router matches the URL to a Route\n3. The Route optionally fetches data\n4. The Route shows a view\n\nEach of these sections can be broken down further:\n\n#### The user navigates\n\nThis is one of two things:\n\n1. The user loads the application at a given URL\n2. The user clicks a link\n\nIn the first situation, the router recognizes the URL, and sends it off to the corresponding Route. In the second case, I strongly\nrecommend that you build a system that automatically hooks your links up to the Router. Ember's `link-to` helper is the best\nsystem I know of that does this, and similar constructs can be found in Angular and React.\n[Backbone.Intercept](https://github.com/jmeas/backbone.intercept) is the current solution I use, as it was quicker to write than a link-to\nabstraction.\n\nAlthough the 'inputs' in either situation are distinct, the \"output\" is the same: a URL is passed off to the Router.\n\n#### The Router matches the URL to a Route\n\nBackbone is the last remaining popular client side application to not used nested routes. Because of this, and because of the messy way\nthat Backbone's Router works, \n\n#### The Route optionally fetches data\n\nAt this point, the route was matched. The first thing that the route does is fetch data, if it needs to. This should be done through a data\nlayer. The goal of the data layer is to manage caching. The route is ignorant as to whether the data is cached or not: it simply requests it\nand resolves a Promise when it gets it back.\n\n#### The Route shows a view\n\nWe now have all of the data that we need for the route, so the last thing to do is to show a view. This is the first parent that begins our\nbasic interaction. This view can go on to make children views and wire up interactions.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesplease%2Fbackbone-architecture-101","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesplease%2Fbackbone-architecture-101","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesplease%2Fbackbone-architecture-101/lists"}