동적 모듈 세트로 AngularJS 앱 개발


81

사용자가 미리 정의 된 100 개 이상의 위젯 세트에서 선택하여 위젯을 배치 (드래그 / 드롭) 할 수있는 복잡한 레이아웃이있는 애플리케이션이 있습니다. 여기서 모든 위젯은 데이터 세트 (REST 호출을 사용하여 가져옴)를 표시하는 사용자 정의 구현입니다. 특정 방식으로. 많은 블로그 게시물, 스택 오버플로 질문 및 공식 AngularJS 문서를 읽었지만 요구 사항을 처리하기 위해 애플리케이션을 어떻게 설계해야하는지 알 수 없습니다. 데모 앱을 살펴보면 단일 모듈 (ng-app)이 있으며 .js 파일에서이를 구성 할 때 종속 모듈이 종속성으로 선언되지만 많은 위젯 세트가 있으며 어떻게 든 모두를 설명하는 것은 바람직하지 않습니다. 그곳에. 다음 질문에 대한 제안이 필요합니다.

  • 앱과 위젯을 어떻게 디자인해야하나요? 별도의 AngularJS 모듈이 있어야하나요? 아니면 각 위젯이 메인 모듈에 대한 지시문이어야하나요?
  • 내 위젯을 지시문으로 디자인하면 지시문 내에서 종속성을 정의하는 방법이 있습니까? 즉, 내 지시문이 구현에 ng-calender를 사용한다고 말합니까?
  • 각 위젯을 별도의 모듈로 디자인하는 경우 위젯 모듈을 기본 모듈에 대한 종속성으로 동적으로 추가하는 방법이 있습니까?
  • 컨트롤러를 어떻게 설계해야합니까? 위젯 당 하나의 컨트롤러 일 가능성이 높습니다.
  • 뷰에 동일한 유형의 위젯이 여러 개있는 경우 상태 (범위)를 어떻게 분리해야합니까?
  • AngularJS로 재사용 가능한 위젯을 디자인하기위한 모범 사례가 있습니까?

편집하다

유용한 참고 자료 :


1
내 첫 번째 생각은 각 위젯을 ng-include를 통해 렌더링 된 별도의 HTML / JS 파일 쌍으로 만드는 것입니다. 트릭은 필요한 컨트롤러 JS 파일 만로드하는 것입니다.
Shmiddty 2013 년

ng-include가 포함 된 html을 동적으로 추가 할 수 있습니까?
Adrian Mitev 2013 년

1
나는 그렇게 믿는다. 메인 컨트롤러에는 어떤 위젯이 활성화되어 있는지 정의하는 컬렉션이 있고, 컬렉션의 마크 업에서 해당 위젯의 뷰 HTML src를 가리키는 일부 속성에 ng-include 바인딩이 있습니다. 나는 이것이 효과가 있다고 확신하지만 실제로 이와 같은 것을 한 적이 없습니다.
Shmiddty

답변:


61

이것은 일반적인 조언 일뿐입니다.

앱과 위젯을 어떻게 디자인해야하나요? 별도의 AngularJS 모듈이 있어야하나요? 아니면 각 위젯이 메인 모듈에 대한 지시문이어야하나요?

수백 개의 위젯에 대해 이야기하고 있는데, 여러 모듈로 분할하는 것이 자연스러워 보입니다. 일부 위젯은 다른 위젯보다 공통점이 더 많을 수 있습니다. 일부는 매우 일반적이고 다른 프로젝트에 적합 할 수 있으며 다른 일부는 더 구체적 일 수 있습니다.

내 위젯을 지시문으로 디자인하면 지시문 내에서 종속성을 정의하는 방법이 있습니까? 즉, 내 지시문이 구현에 ng-calender를 사용한다고 말합니까?

다른 모듈에 대한 종속성은 모듈 수준에서 수행되지만 A모듈이 모듈 B과 둘 모두 AB의존 하고 모듈에 의존하는 경우 문제가 없습니다 C. 지시문은 Angular에서 위젯을 만들기위한 자연스러운 선택입니다. 지시문이 다른 지시문에 종속 된 경우 동일한 모듈에서 정의하거나 모듈 수준에서 종속성을 만듭니다.

각 위젯을 별도의 모듈로 디자인하는 경우 위젯 모듈을 기본 모듈에 대한 종속성으로 동적으로 추가하는 방법이 있습니까?

왜 이렇게 하려는지 잘 모르겠고 어떻게해야하는지 모르겠습니다. 지시문과 서비스는 Angular에서 사용되기 전에 초기화되지 않습니다. 지시문 (위젯)의 방대한 라이브러리가 있고 일부는 사용할 수 있지만 전부는 아님을 알고 있지만 응용 프로그램이 초기화 될 때 어떤 것이 사용 될지 모르면 실제로 "게으른"수 있습니다. 모듈이로드 된 후 지시문을로드 "합니다. 여기 에 예제를 만들었습니다.

이점은 스크립트가 필요하기 전에 스크립트를로드 할 필요가 없기 때문에 코드가 많더라도 애플리케이션을 빠르게로드 할 수 있다는 것입니다. 단점은 새 지시문이 처음로드 될 때 상당히 지연 될 수 있다는 것입니다.

컨트롤러를 어떻게 설계해야합니까? 위젯 당 하나의 컨트롤러 일 가능성이 높습니다.

위젯에는 아마도 자체 컨트롤러가 필요할 것입니다. 컨트롤러는 일반적으로 작아야합니다. 컨트롤러가 커지면 서비스에 더 적합한 기능이 있는지 고려할 수 있습니다.

뷰에 동일한 유형의 위젯이 여러 개있는 경우 상태 (범위)를 어떻게 분리해야합니까?

범위 변수가 필요한 위젯은 의심 할 여지없이 자신의 격리 된 범위를 가져야 scope:{ ... }합니다 (디렉티브 구성에서).

AngularJS로 재사용 가능한 위젯을 디자인하기위한 모범 사례가 있습니까?

범위를 분리하고 종속성을 필요한 최소한으로 유지하십시오. Angular의 모범 사례에 대한 Misko의 비디오를 참조하십시오.

Brian Ford는 Angular에서 거대한 애플리케이션을 작성하는 방법에 대한 기사도 작성했습니다.


놀라운 답변에 감사드립니다!
Adrian Mitev 2013 년

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);
      }
    };
  })

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 속성은 앱 실행에 중요하지 않습니다. 이는 앱 왼쪽에있는 소스 코드 표시를위한 것입니다.

기본적으로 fetchCode 함수를 사용하는 appRun이라는 지시문이 있습니다.

  .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)을 사용하는 것처럼 보입니다. AJAX로 물건을 얻기 위해 fetchCode 함수를 변경하는 것을 제외하고는 똑같이 할 것이라고 생각합니다.


3
이것에 대해 +1. : 나는 당신이 도움을 줄 수있을 것 같아요 여기에 비슷한 질문이 stackoverflow.com/questions/17557088/...
댄 간제

당신은 나를 올바른 방향으로 가리 켰습니다. 누구든지 모듈 포함 기능에 관심이있는 동안 나는 여기에 내 구현을 떠날거야 :function hasModule(name) { try { angular.module(name); } catch(err) { return false; } return true; }
아시에르 파스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.