Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Can't access ng-controller inside of a template transluded by a custom directive #1307

Closed
ghost opened this issue Aug 28, 2012 · 14 comments
Closed

Comments

@ghost
Copy link

ghost commented Aug 28, 2012

I need to use a Controller scope inside a custom directive which doesn't work:

http://plnkr.co/edit/30MrSh?p=preview

However, putting it outside of the custom directive worked:

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

Related: https://groups.google.com/forum/?fromgroups=#!topic/angular/_cjJaJPWzww

@ceymard
Copy link

ceymard commented Mar 1, 2013

I have encountered the same problem.

Having to create divs specifically to put ng-controller kind of downplays the advantages of creating your custom XML for your application.

Is there any work-around for this ?

Specifically, I found that directives using transclude were the ones most prone to this problem.

@ceymard
Copy link

ceymard commented Mar 28, 2013

From what I understood in the end, the behavior of transclude is perfectly normal in that it creates its creates a new scope. So does ng-controller, which results in having them each have a distinct scope and thus not be able to interact together.

In practice, the custom directive has the last say (iirc), and so its own scope is the one used by the DOM elements that are transcluded, which means that the one the controller was bound to is lost and does not interact with the DOM.

There is a solution, which is not a work-around but the intended mecanism (I guess), which is to not use ng-transclude (which creates a scope) and manually transclude your elements directly to the created element.

See http://jsfiddle.net/Nu5hn/

Also note that it is possible to use the transclude function in your linker like so ;

 ...
 compile: function (elt, attr, transclude) {
    // The link function
    return function (scope, elt, attr) {
      transclude(scope, function (clone) {
        // We append here the transcluded elements bound to the parent scope, which means we don't get in ng-controller's way.
        elt.append(clone);
      }
    }
  }

In short, to be able to have ng-controller working on your custom transcluding directives, do not use ng-transclude, but transclude manually !

@barakka
Copy link

barakka commented Jul 22, 2013

I've had the same problem, and this post finally helped me out. However, I first tried the solution provided in the fiddle and, in my case, it didn't work 'cos the controller specified via ng-controller was created after the directives in child elements were linked.

Instead, the solution of the post (using the transclude from the compile function) worked correctly, respecting the expected order of instantiation.

In any case, this makes creating a custom directive that plays nice with ng-controller quite complex and counterintuitive, a thing that I believe should at least be explained in the doc.

@jasonkuhrt
Copy link

Running into this issue myself. I believe this issue points to the fact that more work needs to be done to get directives-combinations working predictably. Further it would be helpful if warnings were issued to help developers know something wonky like this issue is happening. It seems unacceptable that nothing in this issue warrants a warning to the end-user. Of course, the ideal case is needing no warning given the root problem is resolved with better API "ergonomics".

@caitp
Copy link
Contributor

caitp commented Dec 6, 2013

ngController creates a child scope, but the transcluded content inherits from the parent scope rather than the ngController's child scope... is this what you're referring to?

I suppose it would be reasonable to solve that... Although I think #4421 (comment) might make more sense --- actually, I am not sure why we aren't throwing with the creation of two new scopes here, which is slightly different from #4421

@Domiii
Copy link

Domiii commented Jul 3, 2014

Bump. Same issue here. Debugged for half an hour a custom directive on which I need a controller (every entry of an accordion-group from the Bootstrap<->Angular UI package has it's own), until I found out that controllers won't work on custom directives. This is rather upsetting because it means that I cannot use the accordion (and other UI elements) as-is.

@btford btford removed the gh: issue label Aug 20, 2014
@IgorMinar
Copy link
Contributor

@caitp can you take a look at this one in the next few days and see if it's fixable?

@IgorMinar
Copy link
Contributor

vmware guys came across this and pinged me. I asked them to post a better repro so let's wait for that.

@IgorMinar
Copy link
Contributor

cc: @magizh

@magizh
Copy link

magizh commented Oct 17, 2014

Thanks @IgorMinar

Here is a very simple example plunker to refer to and repro the issue.

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

@caitp
Copy link
Contributor

caitp commented Nov 5, 2014

I don't think we can really fix this --- it would have a lot of unintentional consequences. We could say "if we see a directive with a new scope, make it the new scope that we use" --- but that would break a ton of other cases.

We are supposed to be throwing an error if we try to create a new scope and an isolate scope on the same element, so it's not clear why we're not doing that here.

@caitp caitp removed this from the 1.3.2 milestone Nov 7, 2014
@caitp caitp modified the milestones: 1.3.3, 1.3.2 Nov 7, 2014
@caitp
Copy link
Contributor

caitp commented Nov 10, 2014

@IgorMinar this is one of the issues I'm talking about that I don't think we can really fix --- even emitting an error in this case is challenging to do consistently, depending on properties of different directives on the same element.

It would be good to get this fixed (because this rightfully should be an error), but it's a maze to make that work properly.

@caitp caitp assigned IgorMinar and unassigned caitp Nov 10, 2014
@IgorMinar
Copy link
Contributor

ok. I understand now. The problem really is that we are creating two new scopes per element, which is something we historically tried to prohibit and this is one of the cases where our error detection failed to notice it and report it to the developer.

If we could improve the error detection that would be great (but as @caitp suggest it's not a trivial change), but I'm going to close this issue since we will never support this use case.

Sorry about that @magizh and @ghost.

@Domiii
Copy link

Domiii commented Nov 15, 2014

As far as work-arounds go: Is there at least a way to piggyback, or modify the controller or link function on existing directives (that you don't want to temper with)?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.