Розробка програми AngularJS з динамічним набором модулів


80

У мене є програма зі складним макетом, куди користувач міг розміщувати (перетягувати) віджети (вибираючи із заздалегідь визначеного набору 100+ віджетів), де кожен віджет є спеціальною реалізацією, яка відображає набір даних (отриманих за допомогою виклику REST) певним чином. Я прочитав багато публікацій у блогах, запитання щодо stackoverflow та офіційні документи AngularJS, але не можу зрозуміти, як слід розробляти свою програму, щоб відповідати вимогам. Дивлячись на демонстраційні програми, існує єдиний модуль (ng-app), і при його створенні у файлі .js залежні модулі оголошуються як його залежності, однак у мене великий набір віджетів, і чомусь не доцільно описувати всі там. Мені потрібна пропозиція щодо наступних питань:

  • Як я повинен розробляти свій додаток та віджети - чи повинен я мати окремий модуль AngularJS, або кожен віджет повинен бути директивою для головного модуля?
  • Якщо я розробляю свій віджет як директиви, чи є спосіб визначити залежність всередині директиви. Тобто сказати, що моя директива використовує ng-calender у своїй реалізації?
  • Якщо я розробляю кожен віджет як окремий модуль, чи є спосіб динамічно додати модуль віджету як залежність від основного модуля?
  • Як мені розробити контролери - напевно, один контролер на віджет?
  • Як слід відокремлювати стан (область дії), якщо у мене є кілька віджетів від одного типу у поданні?
  • Чи є найкращі практики для проектування віджетів, які можна багаторазово використовувати з AngularJS?

РЕДАГУВАТИ

Корисні посилання:


1
Моєю першою думкою було б створити кожен віджет у вигляді пари окремих файлів HTML / JS, які відображаються за допомогою ng-include. Фокус полягає у завантаженні лише необхідних файлів JS контролера.
Шмідді

Я можу динамічно додавати html, який містить ng-include?
Адріан Мітев,

1
Я так думаю. У вашому головному контролері у вас буде колекція, яка визначає, які віджети активні, у розмітці колекції ви маєте ng-include прив'язати до деякої властивості, яка вказує на перегляд HTML відбитка цього віджета. Я майже впевнений, що це працює, але насправді я не робив чогось подібного.
Shmiddty

Відповіді:


60

Це лише загальні поради.

Як я повинен розробляти свій додаток та віджети - чи повинен я мати окремий модуль AngularJS, або кожен віджет повинен бути директивою для головного модуля?

Ви говорите про віджети, це природно, якщо розділити їх на кілька модулів. Деякі віджети можуть мати більше спільного, ніж інші віджети. Деякі можуть бути дуже загальними та вписуватися в інші проекти, інші більш конкретні.

Якщо я розробляю свій віджет як директиви, чи є спосіб визначити залежність всередині директиви. Тобто сказати, що моя директива використовує ng-calender у своїй реалізації?

Залежності від інших модулів виконуються на рівні модуля, але немає проблем, якщо модуль Aзалежить від модуля Bі обох, Aі Bзалежить від модуля C. Директиви - це природний вибір для створення віджетів у Angular. Якщо директива залежить від іншої директиви, ви або визначаєте їх у тому самому модулі, або створюєте залежність на модульному рівні.

Якщо я розробляю кожен віджет як окремий модуль, чи є спосіб динамічно додати модуль віджету як залежність від основного модуля?

Я не впевнений, чому ви хочете це зробити, і я не знаю, як це зробити. Директиви та служби не ініціалізуються до того, як вони використовуються в Angular. Якщо у вас є величезна бібліотека директив (віджетів) і ви знаєте, що, ймовірно, будете використовувати деякі з них, але не всі - але ви не знаєте, які з них звикнуть, коли додаток ініціалізується, ви можете насправді "лінуватися завантажте "ваші директиви після завантаження вашого модуля. Я створив тут приклад

Перевага полягає в тому, що ви можете швидко завантажити свою програму, навіть якщо у вас багато коду, оскільки вам не потрібно завантажувати сценарії, перш ніж вони вам знадобляться. Недоліком є ​​те, що може бути значна затримка при першому завантаженні нової директиви.

Як мені розробити контролери - напевно, один контролер на віджет?

Віджету, ймовірно, знадобиться власний контролер. Контролери, як правило, повинні бути маленькими, якщо вони стають великими, ви можете подумати, чи є якась функціональність, яка краще підходить для послуги.

Як слід відокремлювати стан (область дії), якщо у мене є кілька віджетів від одного типу у поданні?

Віджети, яким потрібні змінні області, без сумніву, повинні мати власні ізольовані області ( scope:{ ... }у конфігурації директиви).

Чи є найкращі практики для проектування віджетів, які можна багаторазово використовувати з AngularJS?

Ізолюйте сферу застосування, зведіть залежності до необхідного мінімуму. Дивіться відео Місько про найкращі практики в Angular

Брайан Форд також написав статтю про написання величезної програми в Angular


Дякую за дивовижну відповідь!
Адріан Мітев

17

Це питання для мене також дуже важливе. На домашній сторінці 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);
      }
    };
  })

Я буду використовувати приклад списку завдань як приклад. Для 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 просто використовує абсолютно окрему кутову програму (ng-app) для кожного прикладу / віджета. Я думаю, я збираюся зробити те саме, за винятком зміни функції fetchCode, щоб отримати речі з AJAX.


3
+1 за це. У мене є подібне запитання тут, я думаю, ви могли б допомогти: stackoverflow.com/questions/17557088/…
Ден Канце

ти вказав мені в правильному напрямку. Для тих, хто цікавиться функцією hasModule, я залишу свою реалізацію тут:function hasModule(name) { try { angular.module(name); } catch(err) { return false; } return true; }
Asier Paz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.