Developing an AngularJS application with a dynamic set of modules

I have an application with a complex layout where the user can add (drag and drop) widgets (choosing from a predefined set of 100 + widgets), where each widget is a custom implementation that displays a data set (selected using REST) ​​in a certain way. I read a lot of blog posts, stack questions, and official AngularJS docs, but I can't figure out how to come up with my application to handle the requirements there. If you look at the demo applications, there is one module (ng-app), and when it is created in the .js file, dependent modules are declared as its dependencies, however, I have a large set of widgets, and for some reason it is not recommended to describe them all there. I need a suggestion for the following questions:

  • How do I create an application and widgets - should I have a separate AngularJS module, or should each widget be a directive for the main module?
  • If I create my widget as directives, is there a way to define the dependency in the directive. That is, to say that my directive uses ng-calender in its implementation?
  • If I create each widget as a separate module, is there a way to dynamically add a widget module depending on the main module?
  • How do I design controllers - perhaps one controller per widget?
  • How can I separate a state (region) if I have several widgets of the same type in a view?
  • Are there better strategies for developing reusable widgets using AngularJS?

EDIT

Useful links:

+80
javascript angularjs
May 29 '13 at 6:26
source share
2 answers

These are just general tips.

How do I create my application and widgets - should I have a separate AngularJS module, or should each widget be a directive for the main module?

You say hundres widgets, it seems natural to divide them into several modules. Some widgets may have more in common than other widgets. Some can be very general and fit other projects, others are more specific.

If I create my widget as directives, is there a way to define the dependency in the directive. That is, to say that my directive uses ng-calender in its implementation?

Dependencies on other modules are performed at the module level, but there is no problem if module A depends on module B and both A and B depend on module C Directives are the natural choice for creating widgets in Angular. If the directive depends on another directive, you either define it in one module or create a dependency on the module level.

If I design each widget as a separate module, is there a way to dynamically add a widget module depending on the main module?

I'm not sure why you want to do this, and I don't know how to do it. Directives and services are not initialized until they are used in Angular. If you have a huge library of directives (widgets) and know that you are likely to use some of them, but not all of them, but you don’t know which ones will be used when the application is initialized, you can actually " being lazy to “upload” your directives after loading your module. I created an example here

The advantage is that you can quickly download the application, even if you have a lot of code, because you do not need to download scripts before you need them. The disadvantage is that there may be a significant delay in the first loading of a new directive.

How should I design controllers - perhaps one controller per widget?

The widget probably needs its own controller. Controllers usually need to be small, if they get large, you might think if there are any features that are better suited to the service.

How can I separate a state (region) if I have several widgets of the same type in a view?

Widgets that need scoping variables must no doubt have their own isolated scopes ( scope:{ ... } in the directive configuration).

Are there better strategies for developing reusable widgets using AngularJS?

Isolate the scope, keep the dependencies to the required minimum. Watch the Misko Best Practices Video at Angular

Brian Ford also wrote an article on writing a huge application in Angular
+60
May 29 '13 at 16:41
source share

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"> //controller stuff here </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.

+17
Jun 03 '13 at 6:15
source share



All Articles