У меня есть приложение со сложной компоновкой, в котором пользователь может размещать (перетаскивать / оставлять) виджеты (выбирая из предопределенного набора из 100+ виджетов), где каждый виджет представляет собой настраиваемую реализацию, которая отображает набор данных (извлекаемых с помощью вызова REST) определенным образом. Я прочитал массу сообщений в блогах, вопросов о stackoverflow и официальных документов AngularJS, но я не могу понять, как мне разработать свое приложение, чтобы удовлетворить его требования. Глядя на демонстрационные приложения, есть один модуль (ng-app), и при его создании в файле .js зависимые модули объявляются как его зависимости, однако у меня большой набор виджетов, и почему-то не рекомендуется описывать их все там. Мне нужно предложение по следующим вопросам:
- Как мне разработать свое приложение и виджеты - должен ли я иметь отдельный модуль AngularJS или каждый виджет должен быть директивой для основного модуля?
- Если я проектирую свой виджет в виде директив, есть ли способ определить зависимость внутри директивы. То есть сказать, что моя директива использует в своей реализации ng-calender?
- Если я проектирую каждый виджет как отдельный модуль, есть ли способ динамически добавить модуль виджета в качестве зависимости от основного модуля?
- Как мне разработать контроллеры - возможно, один контроллер на виджет?
- Как мне разделить состояние (область действия), если у меня есть несколько виджетов одного типа в представлении?
- Есть ли лучшие практики для разработки многоразовых виджетов с помощью AngularJS?
РЕДАКТИРОВАТЬ
Полезные ссылки:
- ocLazyLoad - отличная библиотека для ленивой загрузки для AngularJS
- Seed project - модули + ленивая загрузка при изменении маршрута (ES6, systemjs, ocLazyLoad)
- Ленивая загрузка в AngularJS
- Динамическая загрузка контроллеров и представлений с помощью AngularJS и RequireJS
- Загрузка компонентов AngularJS с помощью RequireJS после начальной загрузки приложения
- Демо-проект о ленивой загрузке ресурсов AngularJS на GitHub
- Проект "Загрузить по запросу"
- Внедрить модуль динамически, только если требуется
- Еще одна ленивая загрузка в статье об Angular
- Организация кода в больших приложениях AngularJS и JavaScript
источник
Ответы:
Это просто общие советы.
Вы говорите о сотнях виджетов, кажется естественным разделить их на несколько модулей. У некоторых виджетов может быть больше общего, чем у других. Некоторые из них могут быть очень общими и подходящими для других проектов, другие - более конкретными.
Зависимости от других модулей выполняются на уровне модуля, но нет никаких проблем , если модуль
A
зависит от модуляB
и какA
иB
зависит от модуляC
. Директивы - естественный выбор для создания виджетов в Angular. Если директива зависит от другой директивы, вы либо определяете их в том же модуле, либо создаете зависимость на модульном уровне.Я не уверен, зачем вам это нужно, и не знаю, как это сделать. Директивы и службы не инициализируются до того, как они будут использованы в Angular. Если у вас есть огромная библиотека директив (виджетов) и вы знаете, что, вероятно, будете использовать некоторые из них, но не все, но вы не знаете, какие из них будут использоваться при инициализации приложения, вы можете на самом деле «лениться» load "ваши директивы после того, как ваш модуль был загружен. Я создал пример здесь
Преимущество состоит в том, что вы можете заставить свое приложение загружаться быстро, даже если у вас много кода, потому что вам не нужно загружать скрипты до того, как они вам понадобятся. Недостатком является то, что при первой загрузке новой директивы может возникнуть значительная задержка.
Виджету, вероятно, потребуется собственный контроллер. Контроллеры, как правило, должны быть небольшими, если они станут большими, вы можете подумать, есть ли какие-либо функции, которые лучше подходят для службы.
Виджеты, которым требуются переменные области видимости, без сомнения, должны иметь свои собственные изолированные области (
scope:{ ... }
в конфигурации директивы).Изолируйте область действия, сведите зависимости к необходимому минимуму.Смотрите видео Misko о лучших практиках в Angular
Брайан Форд также написал статью о написании огромного приложения на Angular.
источник
Для меня этот вопрос тоже очень важен. На домашней странице AngularJS есть несколько примеров (вы можете называть их виджетами), поэтому я просмотрел их исходный код, чтобы попытаться увидеть, как они разделяют свои виджеты.
Во-первых, они никогда не объявляют атрибут «ng-app». Они используют
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']); }); } }
чтобы убедиться, что все загружено правильно. Хорошая идея, но странно, что они так часто навязывают вам атрибут ng-app, что даже не используют его сами. В любом случае вот модуль домашней страницы, который они загружают вместе с приложением - http://angularjs.org/js/homepage.js
В нем есть директива 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); } }; })
Я буду использовать список ToDo в качестве примера. Для HTML у них есть
<div app-run="todo.html" class="well"></div>
а затем внизу страницы у них есть
<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>
У них также есть
<style type="text/css" id="todo.css"> //style stuff here </style> <script id="todo.js"> //controller stuff here </script>
Код используется, но атрибуты id в этих скриптах не важны для запуска приложения. Это только для отображения исходного кода слева от приложения.
По сути, у них есть директива appRun, которая использует функцию fetchCode.
.factory('fetchCode', function(indent) { return function get(id, spaces) { return indent(angular.element(document.getElementById(id)).html(), spaces); } })
чтобы получить код. Затем они используют angular.bootstrap () для создания нового приложения. Они также могут загружать модули через приложение. Пример проекта JavaScript инициализируется как
<div app-run="project.html" module="project" class="well"></div>
Надеюсь, это поможет. Я все еще не уверен, какой метод является «лучшим», но похоже, что домашняя страница AngularJS просто использует полностью отдельное приложение angular (ng-app) для каждого примера / виджета. Думаю, я сделаю то же самое, за исключением изменения функции fetchCode, чтобы получить что-то с AJAX.
источник
function hasModule(name) { try { angular.module(name); } catch(err) { return false; } return true; }