20

I've created a simple "modal dialog" directive, which uses transclude. I would like to place a form () inside the "modal dialog" directive. I would expect that formController of a form placed inside the directive, is going to be accessible in parent controller's scope, however it isn't. Take a look at the following fiddle, please: http://jsfiddle.net/milmly/f2WMT/1/

Complete code:

<!DOCTYPE html>
<html>
    <head>
        <title>AngJS test</title>
        <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/foundation/4.0.9/css/foundation.min.css">
        <style>
            .reveal-modal {
                display: block;
                visibility: visible;
            }
        </style>
        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular.min.js"></script>
        <script type="text/javascript">
            var app = angular.module('app', []);
            app.controller('appCtrl', function ($scope) {
                $scope.model = {
                    id: 1, name: 'John'
                };
                $scope.modal = {
                    show: false
                };
           });
           app.directive('modal', function () {
               return {
                   scope: {
                       show: '='
                   },
                   transclude: true,
                   replace: true,
                   template: '<div class="reveal-modal small" ng-show="show"><div class="panel" ng-transclude></div></div>'
               }
           });
       </script>
    </head>
    <body ng-app="app">
        <div ng-controller="appCtrl">
            <div class="panel">
                Id: {{ model.id }}<br>
                Name: {{ model.name }}<br>
                Controller formController: {{ form }}<br>
                Directive formController: {{ myForm }}<br>
            </div>

            <form name="form" class="panel">
                <input type="text" ng-model="model.name">
            </form>

            <a ng-click="modal.show=!modal.show">toggle dialog</a>

            <div modal show="modal.show">
                <form name="myForm">
                    <input type="text" ng-model="model.name">
                </form>
            </div>

        </div>
    </body>
</html>

So my question is how to access or is it possible to access directive's formController from parent controller?

Thank you for answers.

-Milan

5
  • Is that the right fiddle? No reference to $scope.myForm anywhere. Commented Apr 10, 2013 at 20:01
  • There's a {{ myForm }} in HTML, which is same as $scope.myForm, I guess. Commented Apr 10, 2013 at 20:22
  • There's also {{ form }}, which references a form inside controller but outside of directive. This one works as expected, but myForm does not get to parent scope - appCtrl's scope :-( Commented Apr 10, 2013 at 20:32
  • I really think you linked the wrong fiddle. There's no myForm, there's no appCtrl, and there's no formController in that fiddle. Commented Apr 10, 2013 at 20:45
  • Yes, you're right, I forgot to update fiddle, thank you for notice. I updated the post with complete source as well as correct fiddle link. Thank you again :-) Commented Apr 10, 2013 at 20:51

2 Answers 2

28

Because you are using transclude, the directive will create a child transcluded scope. There is no easy path from the controller scope (003) to the directive's transcluded scope (005):

enter image description here

(The hard/not recommended path is to go via private property $$childHead on the controller scope, find the isolate scope, then use $$nextSibling to get to the transcluded scope.)


Update: From insights from this answer, I think we can get the formController inside the directive, then use = to get it to the parent.

scope: { show: '=', formCtrl: '=' },
...
link: function(scope, element) {
   var input1 = element.find('input').eq(0);
   scope.formCtrl = input1.controller('form');
}

HTML:

<div modal show="modal.show" form-ctrl="formCtrl">

Fiddle

enter image description here

Sign up to request clarification or add additional context in comments.

6 Comments

What generated those beautiful graphics?
Perfect! :) Thank you Mark. I forked your fiddle to make it more general, so it looks for the form element instead of the first input: jsfiddle.net/milmly/utnd6
@Langdon, I have a tool that I wrote/am writing. I use GraphViz's dot to generate the pictures. I have a directive that figures out the scope properties, and some Python code to generate the dot files.
@apaidnerd, here's a sample .dot file. If you want to add a label, see stackoverflow.com/a/15707752/215945
@apaidnerd, the tool is finished and on github: Peri$scope.
|
10

Here is my solution: I create such method in parent controller :

$scope.saveForm = function(form) {
  $scope.myForm = form;
};

Then I call it in transcluded content:

<my-directive>
  <form name="myForm">
     <div ng-init="saveForm(myForm)"></div>
  </form>
</my-directive>

After creating directive instance i have form controller instance in parent scope.

2 Comments

No really actually. Angular supposes controllers to deal with only data model. But anyway it is the best hack i found.
This method works great when you cannot edit the directive, such as when using Angular UI Bootstrap directives. See my issue here which was resolved with your method: stackoverflow.com/questions/37727443/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.