AngularJS - ngClick, прыстасаваныя дырэктывы, і ізаляваная праблема сферы

Consider the following directive: (Live Demo)

app.directive('spinner', function() {
  return {
    restrict: 'A',
    scope: {
      spinner: '=',
      doIt: "&doIt"
    },
    link: function(scope, element, attrs) {
      var spinnerButton = angular.element("<button class='btn disabled'> 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>

Калі кок 's значэнне (г.зн. значэнне $ scope.spinIt у дадзеным прыкладзе) True , элемент павінен быць схаваныя і <�код > spinnerButton павінен з'явіцца замест гэтага. Калі кок 's значэнне хлусня , элемент павінен быць бачны і spinnerButton павінен быць скрыты.

Праблема тут у тым, што Doit() не ў ізаляваным аб'ёме, такім чынам, ня выклікаецца па пстрычцы.

Што б «Кутні шлях», каб рэалізаваць гэтую дырэктыву?

6
Ваш plunker тут не працуе (пераключэнне)
дададзена аўтар Ven, крыніца

7 адказы

Мая прапанова, каб паглядзець на тое, што адбываецца з гэтымі блешнямі. быць трохі больш 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'> Doing...</button>").hide();
      element.after(spinnerButton);

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

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

Here's one that expects use of $q. It'll work better with Angular-style asynchronous operations, and eliminates the callback functions by instead having the spinner reset on fulfilment of the promise.

8
дададзена
Гэта сапраўды карысна! Вялікі дзякуй!
дададзена аўтар Misha Moroshko, крыніца

Вось паліраваная версія дырэктывы я скончыў з (на падставе прапановы Юкі), у выпадку, калі гэта дапаможа каму-то: (CoffeeScript)

app.directive 'spinnerClick', ->
  restrict: 'A'
  link: (scope, element, attrs) ->
    originalHTML = element.html()
    spinnerHTML = " #{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
2
дададзена

Так, ён будзе выклікаць Doit ў вашай ізаляванай вобласці.

Вы можаце выкарыстоўваць $ parent.doIt у гэтым выпадку

<button ng-click="$parent.doIt()" spinner="spinIt">Spin It</button>
1
дададзена

З дакументацыі AngularJS ( http://docs.angularjs.org/guide/directive ):

& or &attr - provides a way to execute an expression in the context of the parent scope. If no attr name is specified then the attribute name is assumed to be the same as the local name. Given and widget definition of scope: { localFn:'&myAttr' }, then isolate scope property localFn will point to a function wrapper for the count = count + value expression. Often it's desirable to pass data from the isolated scope via an expression and to the parent scope, this can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22}).

so inlclude doIt: "&doIt" in your scope declaration, then you can use doIt as a function in your isolated scope.

1
дададзена

Я не ведаю, пра «кутняй» спосаб рабіць рэчы, але я прапаную не выкарыстоўваць ізаляваную сферу, але замест таго, каб проста стварыць даччыную сферу. Затым вы робіце ATTRS. $ Назіраць , каб атрымаць якія-небудзь ўласцівасці, неабходныя для вашай дырэктывы.

І.Я. :

app.directive('spinner', function() {
    return {
        restrict: 'A',
        scope: true, //Create child scope not isolated scope
        link: function(scope, element, attrs) {
            var spinnerButton = angular.element("<button class='btn disabled'> Doing...</button>");
            element.after(spinnerButton);

            //Using attrs.$observe
            attrs.$observe('spinner', function(showSpinner) {
            spinnerButton.toggle(showSpinner);
            element.toggle(!showSpinner);
            });
        }
    };
});

Я знаходжу гэты спосаб лепш, чым выкарыстанне «$ бацькі", каб пазбегнуць ізаляванай вобласці ў іншых дырэктывах (напрыклад, ngClick або ngModel) у якасці канчатковага карыстальніка вашай дырэктывы не патрэбен ведаць, ці з'яўляецца ці не патрабуе іх выкарыстанне з дапамогай дырэктывы «$ бацька або няма на ядры angularjs дырэктывы.

0
дададзена
Мне падабаецца ідэя дзіцячай сферы, але гэта выглядае як $ назіраць правярае, ці з'яўляецца кок атрыбут змяніўся (які заўсёды фальшыва, так як ён застаецца spinIt ), а не ацэньваць яго і назіраючы яго значэнне. Паглядзіце тут: plnkr.co/edit/D9y5f36vKQtR4bPXeOpZ?p=preview
дададзена аўтар Misha Moroshko, крыніца
Я мяркую, што я мог бы зрабіць кок = "{{spinIt}}" , і ён будзе працаваць: plnkr.co/edit/rSmsEWJG94BtQ39sxExN?p=preview . Але мне цікава, як я мог бы пазбегнуць {{}} і выкарыстоўваць яго як круцёлка = "spinIt" .
дададзена аўтар Misha Moroshko, крыніца
Вы можаце выкарыстоўваць $ сінтаксічнага аналізу для гэтага. г.зн. вар газопоглотитель = $ сінтаксічнага аналізу (attrs.spinIt); scope.spinner = газопоглотитель (маштаб) . Гэта аналагічна таму, як ngModel працуе ў вуглавым ядры
дададзена аўтар Clark Pan, крыніца

Выкарыстанне <�моцны> CoffeeScript і надпіс <�моцны> FontAwesome .

  • No need to manually specify the spinner-text
  • It will just add the spinner content left of the text while loading
  • We must use finally instead of then for the promise otherwise the spinner will stay there on failure?
  • I must use $compile because the contents of the button is dynamically compiled as I am using https://github.com/angular-translate/angular-translate

app.directive 'spinnerClick', ["$compile", ($compile) ->
    restrict: 'A'
    link: (scope, element, attrs) ->
        originalHTML = element.html()
        spinnerHTML = " "

        element.click ->
            return if element.is('.disabled')
            element.html(spinnerHTML + originalHTML).addClass('disabled')
            $compile(element.contents())(scope)
            scope.$apply(attrs.spinnerClick).finally ->
                element.html(originalHTML).removeClass('disabled')
                $compile(element.contents())(scope)
]
0
дададзена

Я заблытаўся, чаму вы не пакаваць усё, у дырэктыве, як быццам гэта аўтаномны модуль. Гэта, прынамсі тое, што я хацеў бы зрабіць. Іншымі словамі, у вас ёсць пстрычка-апрацоўшчык ў HTML, некаторы паводзіны ў дырэктыве і некаторы паводзіны ў вонкавым кантролеры. Гэта робіць ваш код значна менш партатыўным і больш дэцэнтралізаваным.

Ва ўсякім выпадку, вы можаце мець прычыны для гэтага, якія не з'яўляюцца агульнымі, але маё прапанова была б паставіць усё «раскруціць» родавае рэчыва ў дырэктыве круцільніка. Гэта азначае, што клік-апрацоўшчыку Doit() <�код /> функцыі і шаблон матэрыял ўсё ў функцыі сувязі.

Такім чынам, няма неабходнасці турбавацца аб сферу абмену і код заблытванне. Ці я нешта выпусціў?

0
дададзена
Я думаю, што вы блізкія да адзнакі. AFAICT там будзе нейкім параметризованные паводзіны ( Doit гэта фіктыўная праца), і прадзенне з'яўляецца часткай мы хочам радавымі. Так што прыходзіць патрэба ў спосабе, каб сігналізаваць мы зрабілі.
дададзена аўтар Ashe, крыніца
Гэта здаецца, што ён можа атрымаць грувасткім з некалькімі асобнікамі на адной старонцы.
дададзена аўтар Ashe, крыніца
Для сувязі паміж кампанентамі, проста выкарыстоўвайце $ шырокавяшчальны на $ rootScope ад таго, што трэба звольніць поспех падзея, а затым выкарыстоўваць $ scope.on() на дырэктыву, каб спажываць гэтую падзею і дзейнічаць на ім. Такім чынам, вы можаце цалкам аддзяліць свой код у модульным, але ўсё яшчэ ёсць спосаб, каб гэтыя асобныя кампаненты размаўляць адзін з адным.
дададзена аўтар Justin L., крыніца
Даволі справядліва. Я, відавочна, не ў поўнай меры зразумець намеры гэтай функцыі, так што я проста выйсці з гэтага абмеркавання. Ура!
дададзена аўтар Justin L., крыніца