2015-05-02 6 views
3

Привет, я пытаюсь создать системную панель, в которой elem.bind ('change, ...) в дочерней директиве изменяет «выбранную» родительскую директиву: http://plnkr.co/edit/gc35fuUiJVUhHF4QMAwv?p=previewВызов функции родительской директивы в дочерней директиве

(function(angular) { 
    'use strict'; 
    angular.module('docsTabsExample', []) 
    .directive('myTabs', function() { 
     return { 
     restrict: 'E', 
     transclude: true, 
     scope: {}, 
     controller: function($scope) { 
      var panes = $scope.panes = []; 

      $scope.select = function(pane) { 
      angular.forEach(panes, function(pane) { 
       pane.selected = false; 
      }); 
      pane.selected = true; 
      }; 
      $scope.next = function(pane) { 
      select(panes[panes.indexOf(pane)+1]); 
      }; 
      this.addPane = function(pane) { 
      if (panes.length === 0) { 
       $scope.select(pane); 
      } 
      panes.push(pane); 
      }; 
     }, 
     templateUrl: 'my-tabs.html' 
     }; 
    }) 
    .directive('myPane', function() { 
     return { 
     require: '^myTabs', 
     restrict: 'E', 
     transclude: true, 
     scope: { 
      title: '@' 
     }, 
     link: function(scope, element, attrs, tabsCtrl) { 
      tabsCtrl.addPane(scope); 
     }, 
     templateUrl: 'my-pane.html' 
     }; 
    }) 
    .directive('pf-data', function() { 
     return { 
     require: '^myPane', 
     restrict: 'AEC', 
     scope: { 
      title: '@' 
     }, 
     link: function(scope, element, attrs, tabsCtrl) { 
      console.log("hi"); 
      element.bind('change', function() { 
      scope.next(); 
      console.log("switch panes"); 
      }); 
     } 
     }; 
    }); 
})(window.angular); 

(Когда вы выбираете пол (мужчина или женщина), я хочу, чтобы перейти к следующей панели в последовательности, но я предполагаю, что из-за проблем Scope (я довольно ржавый с угловой), что он никогда попадает в связанный атрибут дочерней директивы.

Любые идеи?

ответ

4

Каждый из ваших директив определяет (он довольно много пуст, за исключением содержимого члена определения директивы scope. Поэтому, когда вы говорите scope.next(), он будет терпеть неудачу, если он не находится в этой коллекции или явно не привязан функцией link. используя $scope, чтобы добраться до вас Родители не собираются работать. И вы, конечно же, не хотите, чтобы были внутренние данные утечки, передавая функции через атрибуты. Это может привести к тому, что у них возникнут эти связанные директивы.

Но у вас есть что-то еще лучше.

Поскольку вы используете require, чтобы связать ваши директивы вместе, вам даже не нужно беспокоиться об этих играх. В pf-data вы определите:

require: ['^myPane', '^myTabs] 

Это даст вам прямой доступ к обоим контроллерам. Вам необходимо выставить next по директиве myTabs. Честно говоря, я бы нашел способ использовать индексы, а не прокручивать все ваши панели, устанавливая true и false. Что-то вроде:

var currentPane; 
this.next = function() { 
    select(nextPane(currentPane)); 
}; 

И теперь, в пФ-данных, у вас есть доступ через ваш link функции:

link: function(scope, element, attrs, ctrls) { 
     element.bind('change', function() { 
     $scope.$apply(function() { 
      ctrls[1].next(); 
      scope.next(); 
     }; 
     }); 
    ... 

Update

Я раздвоенный новый Plnkr от одного вы предоставили чтобы включить изменения, о которых мы говорили. Я также отказался от требования myPane от pf-data (который не работал бы в любом случае из-за transclude).

http://plnkr.co/edit/LP0RYu6AKxeKyhHY5rZP?p=preview

Обновления включают в себя:

  • pf-data был изменен на pfData - это только один из этих правил угловой. Ваши директивы называются с помощью верблюжьей кейс, но в вашем html заканчиваются как дефис.
  • Я реализовал все мелочи, о которых я говорил. scope.$apply и сменив require на использование myTabs. Как мы обсуждали в комментариях, вам нужно использовать $apply всякий раз, когда вы захватываете события, которые не являются непосредственно частью углового, чтобы сигнализировать об обновлении элементов на экране.
  • Я отскочил все ваши методы в myTabs, чтобы быть на this вместо $scope. Вы будете нуждаться в них там, так как вы собираетесь на них через механизм контроллера.
  • Я сохраняю выбранную панель в контроллере, чтобы мы могли просто сказать next(), не имея необходимости поставлять панель.
+1

@Michael_Hays настроил пример так, чтобы он использовал обновленные требования и область действия: [link] (http://plnkr.co/edit/gc35fuUiJVUhHF4QMAwv?p=preview). Пример изменен из документов AngularJS по директивам , Также вы можете объяснить, почему вы не можете просто сделать ctrls [1] .next(), почему он должен применяться к обоим областям, и почему вам нужно делать $ scope. $ Apply. –

+0

Вам вообще не нужны обе области: вам нужен только тот, который я добавил, но я не хотел уменьшать функциональность, которая уже присутствовала в случае необходимости контроллера myPane. Что касается '$ scope. $ Apply' - при запуске внешних событий они возникают за пределами угловой архитектуры, поэтому они не будут запускать какие-либо привязки, которые вы, возможно, настроили, - ваше представление не будет обновляться. В некоторых случаях Angular предоставляет обработчики '$ apply'-wrapped,' ng-click' и т. Д., Но только если вы присоедините этих обработчиков с помощью угловых директив. Это то, что наскучит всех нас время от времени. –

+0

Позвольте мне проверить ваш пример и убедиться, что он работает. Я вернусь. –

2

Вы правы - это проблема с областью. Когда вы используете изолированную область видимости, единственными переменными области видимости, которые доступны в ваших директивах, выделенной области действия из родительской области, являются те, которые вы передаете через атрибуты. Для вызова следующего(), который определяется на родительской области внутри вашей директивы, передать метод через атрибут с «&» связывания:

scope: { 
     title:'@', 
     next: '&' 
    } 

HTML:

<my-pane next="next()"></my-pane> 
+0

Я попробовал ваше решение [ссылка] (http://plnkr.co/edit/gc35fuUiJVUhHF4QMAwv?p=preview), но я до сих пор не вижу функциональности. –