This question is also very important to me. There are several examples on the AngularJS main page (you could call them widgets), so I went, although their source code tried to see how they separated their widgets.
First, they never declare the "ng-app" attribute. They use
function bootstrap() { if (window.prettyPrint && window.$ && $.fn.popover && angular.bootstrap && hasModule('ngLocal.sk') && hasModule('ngLocal.us') && hasModule('homepage') && hasModule('ngResource')) { $(function(){ angular.bootstrap(document, ['homepage', 'ngLocal.us']); }); } }
to make sure everything is loaded correctly. Not a bad idea, but it’s strange that they click on the ng-app attribute on you, so they don’t even use it themselves. In any case, here is the start page module, which they load using the application - http://angularjs.org/js/homepage.js
The directive is called appRun
.directive('appRun', function(fetchCode, $templateCache, $browser) { return { terminal: true, link: function(scope, element, attrs) { var modules = []; modules.push(function($provide, $locationProvider) { $provide.value('$templateCache', { get: function(key) { var value = $templateCache.get(key); if (value) { value = value.replace(/\#\//mg, '/'); } return value; } }); $provide.value('$anchorScroll', angular.noop); $provide.value('$browser', $browser); $locationProvider.html5Mode(true); $locationProvider.hashPrefix('!'); }); if (attrs.module) { modules.push(attrs.module); } element.html(fetchCode(attrs.appRun)); element.bind('click', function(event) { if (event.target.attributes.getNamedItem('ng-click')) { event.preventDefault(); } }); angular.bootstrap(element, modules); } }; })
As an example, I will use the ToDo list. For html they have
<div app-run="todo.html" class="well"></div>
and then at the bottom of the page
<script type="text/ng-template" id="todo.html"> <h2>Todo</h2> <div ng-controller="TodoCtrl"> <span>{{remaining()}} of {{todos.length}} remaining</span> [ <a href="" ng-click="archive()">archive</a> ] <ul class="unstyled"> <li ng-repeat="todo in todos"> <input type="checkbox" ng-model="todo.done"> <span class="done-{{todo.done}}">{{todo.text}}</span> </li> </ul> <form ng-submit="addTodo()"> <input type="text" ng-model="todoText" size="30" placeholder="add new todo here"> <input class="btn-primary" type="submit" value="add"> </form> </div> </script>
They also have
<style type="text/css" id="todo.css"> //style stuff here </style> <script id="todo.js"> </script>
The code is used, but the id attributes for these scenarios are not important for starting the application. This is only for the source code displayed to the left of the application.
Basically, they have a directive called appRun that uses the fetchCode function
.factory('fetchCode', function(indent) { return function get(id, spaces) { return indent(angular.element(document.getElementById(id)).html(), spaces); } })
to extract the code. They then use angular.bootstrap () to create a new application. They can also load modules, although they can run applications. Sample JavaScript project initialized as
<div app-run="project.html" module="project" class="well"></div>
Hope this helps. I'm still not sure what the “best” technique is, but it looks like the AngularJS page just uses a completely separate angular app (ng-app) for each example / widget. I think I'm going to do the same thing except changing the fetchCode function to get material with AJAX.