2

The "form aka ngForm" directive can be accesed via form name.

<form name="testForm"> </form>

Then in controller we can do something like this:

$scope.testForm.$valid 

And in HTML:

<button ng-show="testForm.$valid>

This makes "form" directive really a UI component with accessible properties and methods (just like in non-html world)

Is there a standard way to achieve this kind of componentization for own directives? For example I would love to have directive "list" with all methods like "selectElement", "scrollToTop", "scrollToElement", "doSomething" etc. and use it like this

<list name="myList></list>

<button ng-click="myList.doSomething()">

and in some other controller:

$scope.myList.scrollToTop();

I wrote some simple hack for this based what "form" directive does - it publishes directive's public api in the scope in variable defined by name attribute:

app.directive('list', function () {
        return {
            restrict: 'E',
            controller: function ($scope, $element, $attrs) {

                // check if name of component does not pollute scope
                if ($attrs.name) {
                    if (angular.isDefined($scope[$attrs.name])) {
                        throw "Error component already defined with name: " + $attrs.name;
                    } else {

                      // publish controller object aka public API

                      scope[$attrs.name] = {
                               date: new Date(), 
                               myFunction: function(){}
                      };
                    }
                }
            },
            template: '<ul></ul>'
        }
    });

So:

<list name="myList"></list>
<button ng-click="myList.myFunction()">

and

$scope.myList.myFunction();

But it's not working with isolated scope directive - workaround would be passing api object as an attribute with two way binding like in this question: How to call a method defined in an AngularJS directive?.

I also thought about defining api in service but it's really ugly - service has to be somehow attached to correct DOM element of directive.

So my question is - what is the best pattern to access directives methods and properties both from HTML and other controllers making directives real UI components?

Or simpler question - how to access directive controller from another controller or from another expression in HTML like we can do from another directive via "require".

Community
  • 1
  • 1
Yoorek
  • 1,003
  • 1
  • 12
  • 30

2 Answers2

0

You should use directive controller and publish it via controllerAs. watch this

Matjaz Lipus
  • 702
  • 1
  • 5
  • 10
  • I am familiar with "as" syntax but how can i use it for directive controller? and how would i access it from another controller (not from html)? – Yoorek Feb 10 '14 at 17:59
  • I see. Actually controller is not the right way. You should create a service and share common code between controllers via service. Please update question what is your original problem. – Matjaz Lipus Feb 10 '14 at 19:55
0

Even if a scope is isolate, it still has the $parent property that points to the parent scope. So regarding to your question, the solution might look like this:

angular.module('sample', []).directive("foo", function() {
  return {
    controller: function($scope, $element, $attrs) {
      $scope.$parent[$attrs.foo] = this;
      this.apiMethodName = function() {
          // ...
      };
    },
    scope: {},
    restrict: 'A'
  };
});

Try it on Plunker: http://plnkr.co/edit/qmGcAY?p=preview

thorn0
  • 9,362
  • 3
  • 68
  • 96