Angular-styleguide: コンポーネントのスタイルガイドがありません

作成日 2016年09月01日  ·  25コメント  ·  ソース: johnpapa/angular-styleguide

ディレクティブを使用する代わりに、DOMで操作する必要のない場所でコンポーネントを使用できます。 しかし、angularjs1.5ではこのためのスタイルガイドを見つけることができません。

Angular 1 enhancement help wanted

最も参考になるコメント

個人的に私は次のスタイルを使用しています:

(function(){
  'use strict';

  angular
    .module('app')
    .component('exampleComponent', exampleComponent());

  function exampleComponent() {
    var component = {
      bindings: {
        /* bindings - avoiding "=" */
      },
      controller: ExampleComponentController,
      controllerAs: 'vm',
      templateUrl: 'path/to/example-component.html'
    };

    return component;
  }

  ExampleComponentController.$inject = ['exampleService'];

  /* <strong i="6">@ngInject</strong> */
  function ExampleComponentController(exampleService) {
    var vm = this;

    /* generic controller code */
  }
})();

全てのコメント25件

コミュニティはこれについてどのような提案をしていますか?

コンポーネントセクションが絶対に欲しい

私はそれがこのように好きです:

(function() {
    'use strict';

    angular
        .module('app.widget.activeplaces')
        .component('activePlaces', {
            bindings: {
                data: '<'
            },
            templateUrl: 'components/active-places/active-places.widget.html',
            controller: ActivePlacesController,
            controllerAs: 'vm'
        });

    function ActivePlacesController(activityService) {
        var vm = this;

        vm.activities = [];
        vm.doFunnyStuff = doFunnyStuff;

        function doFunnyStuff() {
            vm.activities.push('yolo');
        }
    }

}());

または、コンポーネントの登録を一番下に移動します。

(function() {
    'use strict';

    var activePlaces = {
        bindings: {
            data: '<'
        },
        templateUrl: 'components/active-places/active-places.widget.html',
        controller: ActivePlacesController,
        controllerAs: 'vm'
    };

    function ActivePlacesController(activityService) {
        var vm = this;

        vm.activities = [];
        vm.doFunnyStuff = doFunnyStuff;

        function doFunnyStuff() {
            vm.activities.push('yolo');
        }
    }

    angular
        .module('app.widget.activeplaces')
        .component('activePlaces', activePlaces);

}());

問題は、vmの代わりに新しい$ ctrl参照を使用することを好むことです。これにより、vm-patternの一貫性が失われます。 したがって、完全に$ ctrlに切り替えるか、単にcontrollerAs: 'vm'をコンポーネント設定オブジェクトに追加して、スタイルガイドの残りの部分と一貫性を持たせます:)

私は2番目の方法の方が好きです。 後でES6クラスに簡単に移行できるように、プロトタイプにメソッドを配置することも検討します。 また、 $ctrlがデフォルトであり、 controllerAsを宣言する必要がないため、必要な定型文が減るため、 $ctrlに切り替える時期であることに同意します。

私は最初の方法を好むfwiw:grin:
vmのコースなし:stuck_out_tongue :)

最初の方法は私のpresonalfavです。 両方のコントローラーに追加します:

// other vm vars/assigns here
vm.$onInit = activate;

// functions
function activate() {
  // initialization magic here
}

もちろん、 activate関数の名前をinitまたはonInitなどに変更できます。

これはもう少し意見があり、ES2016ですが、私のコンポーネントでは次のようにしています:

(function() {
  'use strict';
  /*
<active-places data="">
</active-places>
   */
  const componentConfig = {
    bindings: { data: '<' },
    templateUrl: 'components/active-places/active-places.widget.html',
    controller: ActivePlacesController,
  };

  /* <strong i="6">@ngInject</strong> */
  function ActivePlacesController(activityService) {
    Object.assign(this, {
      activities: [],
      doFunnyStuff, 
      $onInit,
    })

    function $onInit() {
      activityService.list()
        .then(response => { this.activities = response })
        .catch(console.error)
    }
    function doFunnyStuff() {
      this.activities.push('yolo');
    }
  }
  angular
    .module('app.widget.activeplaces')
    .component('activePlaces', componentConfig);

}());

ファイルの先頭にコピーして貼り付けることができるスニペットを配置するのが好きです。これにより、多くの時間を得ることができます。 また、モジュールおよびコンポーネントの宣言AMHOよりも、プロジェクトで開発する場合の方が明確で便利です。
また、 Object.assign (ES2015はangular.extend使用できます)呼び出しを使用して、すべてのメソッドと小道具をコンポーネントスコープにバインドし、それらすべての小さなvm.のファイルを削ります。
可能な場合は、オブジェクトにES6の省略表記を使用します。
また、 this使用するためにvmキャプチャ変数を削除しました。 ES2015以降、はるかに使いやすくなり、NG1.5 +以降、$ watchを使用しない方法を常に見つけています。 ボーナス効果、私はそれから逃げる代わりにそれを使うことを学びます。

興味のある方は、ES6を使用したリビジョンをご覧ください。

https://github.com/rwwagner90/angular-styleguide-es6

これも意見がありますが、私はそれをシンプルに保つのが好きです。 vmはなく、$ ctrlだけです。 ビューに公開する対象の分割はありません。 考え?

    (function(){
        'use strict';

        angular
            .module('app.shared')
            .component('buttonList', {
                bindings: {
                    data: '<',
                },
                template: `<span ng-repeat="button in $ctrl.buttons">
                                <button class="btn btn-default" ng-click="$ctrl.removeButton(button)">{{ ::button.name }}</button>
                            </span>`,
                controller: MyDataController
            });

        function MyDataController(dataService) {

            this.$onInit = function () {
                this.buttons = [];
                this.loadData();
            };

            this.removeButton = function (button) {
                var index = this.buttons.indexOf(button);
                this.buttons.splice(index, 1);
            };

        }

    })();

私はA1の.component機能のためにチームをプッシュするのを手伝いました...そして私は彼らがこれをしたことに興奮しています。

また、A1バージョンの.componentを継続するために、 vm.*に非常に公に投票しました。 しかし、コミュニティはこの問題に$ctrl投票しました。 スタイルガイドの精神では、一貫性が最も重要です。 そのため、ここでは$ctrlが最適なオプションであり、上記のメモに記載されているデフォルトと一致していると思います。

考慮すべき他の事柄は

  1. 構成を定義する方法
  2. コンポーネントにプロパティを設定する方法( thisvm$ctrl
    2b。 this (上記の#2を参照)を使用する場合、新しいクロージャ(例:self)の処理方法... yuk
  3. 関数の命名(コンポーネントまたはコントローラー)
  4. バインディングでコールバックを処理する方法
  5. バインディングの命名

これらは、これまでに.componentを見て、使用した多くの方法から私がつかんだほんの一例です。

これらと他の関連するものでチャットを続けましょう。

私は、コンポーネントを一番上に宣言する最初のフォーマットに熱心です。 その理由は、2番目のバージョンでは新しい変数activePlaces導入されており、その名前について議論する必要があり、ファイルの読み取りがさらに複雑になるためです。

また、プロトタイプにコントローラーメソッドを配置したいと思っています。 サービスとは異なり、特にコンポーネントで使用する場合は、コントローラーの複数のインスタンスを取得できます。インスタンスごとにすべてのメソッドの新しいコピーを作成しない方が有利なようです。

コンポーネントにはコントローラーが必要なので、デフォルトの$ctrlが私の好みのオプションであるため、コントローラーメソッドのコンテキストフリー関数呼び出しを頻繁に取得しない傾向があります。

コンポーネントのコントローラーであるため、私は常に関数[ComponentName]Controller呼び出してきました。 A2に移行するとこれらの名前が変わるという事実にもかかわらず、これをお勧めします。これは単純なリファクタリングです。

コンポーネントでは、コントローラーコンストラクターではなく、ライフサイクルフックを利用することが重要です。

  • constructor -注入されたサービスをプロパティにアタッチするなど、プロパティの単純な初期化のみ。 今後、バインディングはここに割り当てられないため、ここで実際の作業を行う必要はありません。
  • $onInit -この時点で、バインディングと必要なコントローラーが割り当てられています。 ここで、実際の初期化作業を行う必要があります。
  • $onChanges -これは、入力( < )および補間( @ )バインディングのいずれかが変更されるたびに呼び出されます。 入力オブジェクトの変更は補間をトリガーしないことを理解することが重要です。 ただし、これは入力の変更に反応するコードを配置するのに適した場所であり、時計の作成を節約できます。 「一方向のデータフロー」アプローチを採用する場合は、渡されたオブジェクトを誤って変更しないように、入力オブジェクトが変更されたときにコピーを作成するのに適した場所であることをお勧めします。
  • $onDestroy -このメソッドの唯一の理由は、コンポーネントの存続期間中に取得または開かれた長時間実行リソースを解放または閉じることです。 コンポーネントの分離スコープを手動で破棄した場合、またはDOMからコンポーネント要素を手動で削除した場合、このフックは呼び出されないことに注意してください。 このコンポーネントが存在するスコープである包含スコープが破棄された場合にのみ、破棄されます。

出力バインディングについてbuttonClick(button) 、実際に出力onButtonClick({$event: button})トリガーするハンドラーメソッドbuttonClick(button)を使用するというアプローチに従っています。 また、出力のペイロードは常に$eventプロパティに配置されます。 これは、外側でAngular 2に表示されるものと同様の<button-list on-button-click="$ctrl.doStuff($event)">を実行できることを意味します。

したがって、すべて次のようになります。

    (function(){
        'use strict';

        angular
            .module('app.shared')
            .component('buttonList', {
                bindings: {
                    buttons: '<',
                    onButtonClick: '&'
                },
                template: `<span ng-repeat="button in $ctrl.buttons">
                                <button class="btn btn-default" ng-click="$ctrl.buttonClick(button)">{{ ::button.name }}</button>
                            </span>`,
                controller: ButtonListController
            });

        function ButtonListController(dataService) {
            this.dataService = dataService;
        }

        ButtonListController.prototype = {
            $onInit: function () {
                this.dataService.loadData().then(function(data) {
                  this.data = data;
                }.bind(this));
            },
            $onChange: function(changes) {
                if (changes.buttons) {
                    this.buttons = angular.copy(this.buttons);
                }
            },
            buttonClick: function (button) {
              this.onButtonClick({ $event: { button });
            }
        };
    })();

@petebacondarwin私はあなたがいくつかの変更を加えたものが好きです。

コンポーネントの構成に{ }を埋め込むのではなく、変数を使用することをお勧めします。 これは読みやすく、デバッグしやすいと思います。 名前は私には関係ありません...

var componentConfig = { ... };
angular
            .module('app.shared')
            .component('buttonList', componentConfig);

私のより大きな懸念は、 thisと、関数がコントローラーのプロパティにアクセスする方法についてです。 コントローラは、状態を持つことになります...あなたが持っている$ctrl.buttonsテンプレートにし、私たちは持っているだろうと仮定this.buttonsコントローラでを。 関数(プロトタイプまたはその他)を作成するとき、クロージャがあり、それらのいくつかには独自のthis参照があります。 これは、たとえば、 $timeout()を使用した場合に発生します。 これらが解決されるのをどのように見ていますか?

私の例では、promise thenhandlerでこの問題が発生しました。 .bindを使用することにしました

ええ、でもそれは面白くないです:)

これが、A1コントローラーでvmを使用したもう1つの理由です。

その場合はいつでも$ ctrlを使用できます

2016年9月14日19:05、「JohnPapa」 [email protected]は次のように書いています。

ええ、でもそれは面白くないです:)

これが、A1コントローラーでvmを使用したもう1つの理由です。


あなたが言及されたのであなたはこれを受け取っています。
このメールに直接返信し、GitHubで表示してください
https://github.com/johnpapa/angular-styleguide/issues/766#issuecomment -247103228、
またはスレッドをミュートします
https://github.com/notifications/unsubscribe-auth/AAA9J5DE4qIUEOEuPEIPLKobfDKT_Bbjks5qqDeEgaJpZM4Jyo-5

今私はこのようにやっています($ ctrlで行く):

( function() {
  'use strict';

  var component = {
    bindings: {
      data: '='
    },
    controller: controller,
    templateUrl: '/breadcrumbs.html'
  };

  angular.module( 'app' ).component( 'breadcrumbs', component );


  function controller( $log, $state ) {
    var logger = $log.getLogger( 'breadcrumbs' );
    var $ctrl = this;

    logger.log( $ctrl );

    $ctrl.goToState = goToState;


    function goToState( breadcrumb ) {
      logger.log( 'goToState()', breadcrumb );
      $state.go( breadcrumb.state, breadcrumb.data );
    }
  }
} )();

皆さんはどう思いますか?

Todd Mottoスタイルガイドからインスピレーションを得られると思いますか?
https://github.com/toddmotto/angular-styleguide

はい、でもそれはES2015です。 ES2015以前に固執している人々はどうなりますか?

個人的に私は次のスタイルを使用しています:

(function(){
  'use strict';

  angular
    .module('app')
    .component('exampleComponent', exampleComponent());

  function exampleComponent() {
    var component = {
      bindings: {
        /* bindings - avoiding "=" */
      },
      controller: ExampleComponentController,
      controllerAs: 'vm',
      templateUrl: 'path/to/example-component.html'
    };

    return component;
  }

  ExampleComponentController.$inject = ['exampleService'];

  /* <strong i="6">@ngInject</strong> */
  function ExampleComponentController(exampleService) {
    var vm = this;

    /* generic controller code */
  }
})();

ディレクティブのようにコンポーネントに一意のプレフィックスを提供するのはどうですか? 必要と思われますか?

@petebacondarwin私はあなたの例が好きです。それは、一方向のデータバインディングと、それらを$onChangeライフサイクルフックにコピーして、真に一方向のデータを実現する必要があることを強調しているためです(つまり、子が伝播する方法で変更されない可能性があることを示します親へ)。 いくつかの質問:

  1. $onInitフック内でthis.dataService.loadData()を呼び出したのはなぜですか? 私が理解している限り、 dataServiceはコントローラーパラメーターとして依存性として宣言されているため、angularの依存性注入メカニズムにより、コントローラーオブジェクトの構築時にそのような(シングルトン)サービスを利用できるようになります。 コンポーネント/ディレクティブAPIのrequire部分を利用して、代わりに$onInit保証を紹介するのは理にかなっていますか?
  2. 特にButtonListControllerが動作を失うことなく、コンストラクター関数自体の中にこれらのメソッドを同じように簡単に追加できるのに、なぜButtonListControllerprototypeに追加するのでしょうか。継承のいくつかの典型的なチェーンの一部として使用されます。 ここで強調しようとしていることはありますか?

@texonidas

  1. $inject ables」をパラメーターとして参照するコンストラクター関数に明示的にアタッチする必要がありますか?
  2. コンポーネント構成(オブジェクトリテラル)をパラメーターとしてcomponentメソッドに直接渡すことができるのに、なぜexampleComponent()導入するのですか? 特に、 componentという名前の変数を導入していますが、これは同じ変数を返し、同じ名前のメソッドにのみ使用します。

@jbmilgrom

  1. コンストラクターに「実際の」作業を入れない場合は、単体テストを制御する方がはるかに簡単です。 コンストラクターがロードなどの動作をする場合、テスト内でこれが発生する(または遅延する)のを防ぐことはできません。 インスタンス化を行うDIシステムの複雑さが増すと、タイミングをさらに制御できなくなります。

  2. このコンポーネントを1つのアプリで何度も使用できることを考えると、インスタンス間で共有されるメソッドをプロトタイプに配置する方がメモリ効率が高くなります。

@petebacondarwin応答に感謝します、理にかなっています。

コンストラクター関数のスコープ内で宣言された変数を参照するメソッドをコンストラクター関数のスコープ内で宣言することにより、(クロージャを介して)一種のプライベート状態を取得できます。 少しやりすぎの可能性があるコントローラーの場合、これは、特に、テンプレート内で直接変更される可能性のある状態と、間違いなく変更できない状態を区別するのに役立ちます。 それはあなたのセットアップでは不可能のようです。 代わりに、すべての状態をthisバインドし、プライバシーが必要な場合はサービスに委任しますか?

@jbmilgrom

  1. $ injectは、縮小の安全性のためにあります。 絶対に必要というわけではありません。これがスタイルガイドに含まれる場合は、縮小に関するセクションでさらに明示的に説明されているため、削除します。

  2. スタイルガイドがサービスに推奨するのと同じ構文を使用しました。

/* recommended */
function dataService() {
    var someValue = '';
    var service = {
        save: save,
        someValue: someValue,
        validate: validate
    };
    return service;

    ////////////

    function save() {
        /* */
    };

    function validate() {
        /* */
    };
}

変数に明示的に名前を付けてから返します。

私はtexonidasと同様のアプローチを使用していますが、htmlでデフォルトの$ ctrlを維持することにしました(controllerAsを使用していません)。

ファイル名:example.component.js

    .module('app.moduleName')
    .component('exampleComponent', componentConfig());

function componentConfig () {
    return{
        bindings: {
            /*bindings*/
        },
        templateUrl: 'path/to/example.html',
        controller: exampleController
    };    
};

exampleController.$inject = ['exampleService'];

function exampleController (exampleService){
    var ctrl = this;
    ctrl.someFunction = someFunction;
    ctrl.$onInit = function(){
        ctrl.someVar = 'initial values';
   }
   .
   .
   .
};

コンポーネントをモジュールに登録する必要がありますか?

私のチームによるv1スタイルガイドの解釈では、すべてのコントローラーをモジュールに登録し、名前で参照する必要があります。

    .module('app.moduleName')
    .controller('exampleController', exampleController)
    .component('exampleComponent', componentConfig());


function componentConfig () {
    return{
        bindings: {
            /*bindings*/
        },
        templateUrl: 'path/to/example.html',
        controller: 'exampleController'
    };    
};
このページは役に立ちましたか?
0 / 5 - 0 評価