6

次のディレクティブを検討してください: (ライブ デモ)

app.directive('spinner', function() {
  return {
    restrict: 'A',
    scope: {
      spinner: '=',
      doIt: "&doIt"
    },
    link: function(scope, element, attrs) {
      var spinnerButton = angular.element("<button class='btn disabled'><i class='icon-refresh icon-spin'></i> Doing...</button>");
      element.after(spinnerButton);

      scope.$watch('spinner', function(showSpinner) {
        spinnerButton.toggle(showSpinner);
        element.toggle(!showSpinner);
      });
    }
  };
}); 

これは次のように使用されます:

<button ng-click="doIt()" spinner="spinIt">Spin It</button>

spinnerの値 (つまり、$scope.spinItこの例では の値) がの場合true、要素は非表示になり、spinnerButton代わりに表示されます。spinnerの値が の場合false、要素を表示して非表示にspinnerButtonする必要があります。

ここでの問題はdoIt()、分離されたスコープにないため、クリック時に呼び出されないことです。

このディレクティブを実装するための「Angular の方法」は何でしょうか?

4

7 に答える 7

8

私の提案は、これらのスピナーで何が起こっているかを見ることです。もう少し API に重点を置いてください。

関連する部分が続きます。完了したことを示すために通常のコールバックを使用するため、スピナーはボタンの状態をリセットする必要があることを認識しています。

function SpinDemoCtrl($scope, $timeout, $q) {
  $scope.spinIt = false;

  $scope.longCycle = function(complete) {
    $timeout(function() {
      complete();
    }, 3000);
  };

  $scope.shortCycle = function(complete) {
    $timeout(function() {
      complete();
    }, 1000);
  };
}

app.directive('spinnerClick', function() {
  return {
    restrict: 'A',
    scope: {
      spinnerClick: "=",
    },
    link: function(scope, element, attrs) {
      var spinnerButton = angular.element("<button class='btn disabled'><i class='icon-refresh icon-spin'></i> Doing...</button>").hide();
      element.after(spinnerButton);

      element.click(function() {
        spinnerButton.show();
        element.hide();

        scope.spinnerClick(function() {
          spinnerButton.hide();
          element.show();
        });
      });
    }
  };
});

の使用を期待するものを次に示します$q。Angular スタイルの非同期操作でより適切に機能し、約束の履行時にスピナーをリセットする代わりにコールバック関数を排除します。

于 2013-05-28T10:54:51.537 に答える
2

これは、誰かを助ける場合に備えて、最終的に完成したディレクティブの洗練されたバージョンです (Yuki の提案に基づく): (CoffeeScript)

app.directive 'spinnerClick', ->
  restrict: 'A'
  link: (scope, element, attrs) ->
    originalHTML = element.html()
    spinnerHTML = "<i class='icon-refresh icon-spin'></i> #{attrs.spinnerText}"

    element.click ->
      return if element.is('.disabled')

      element.html(spinnerHTML).addClass('disabled')

      scope.$apply(attrs.spinnerClick).then ->
        element.html(originalHTML).removeClass('disabled')

次のように使用します。

<button class="btn btn-primary" spinner-click="createNewTask()" 
                                spinner-text="Creating...">
  Create
</button>

コントローラーのコード:

TasksNewCtrl = ($scope, $location, $q, Task) ->
  $scope.createNewTask = ->
    deferred = $q.defer()

    Task.save $scope.task, ->
      $location.path "/tasks"
    , (error) ->
      // Handle errors here and then:
      deferred.resolve()

    deferred.promise
于 2013-05-29T00:08:19.573 に答える
1

AngularJS ドキュメント ( http://docs.angularjs.org/guide/directive ) から:

& または &attr - 親スコープのコンテキストで式を実行する方法を提供します。属性名が指定されていない場合、属性名はローカル名と同じであると見なされます。指定されたスコープのウィジェット定義: { localFn:'&myAttr' } の場合、分離スコープ プロパティ localFn は、count = count + value 式の関数ラッパーを指します。分離されたスコープから式を介して親スコープにデータを渡すことが望ましい場合がよくあります。これは、ローカル変数名と値のマップを式ラッパー fn に渡すことで実現できます。たとえば、式が increment(amount) の場合、localFn を localFn({amount: 22}) として呼び出して金額の値を指定できます。

スコープ宣言に含めると、分離されたスコープでdoItdoIt: "&doIt"を関数として使用できます。

于 2013-05-28T01:14:31.023 に答える