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

Lazy/Eager $compile on transclusion changed behavior #13652

Closed
shlomiassaf opened this issue Dec 29, 2015 · 3 comments
Closed

Lazy/Eager $compile on transclusion changed behavior #13652

shlomiassaf opened this issue Dec 29, 2015 · 3 comments

Comments

@shlomiassaf
Copy link

Hi,

This is a tricky one to explain, I`ll do my best.

Using the ui-select angular 3rd party packages does not work with 1.5.0-rc.0

I believe its related to the Lazily compile the transclude function commit

Since its not a breaking API commit everything should work as before but ui-select fails.

I've debugged deeply into angular core and found that while compiling a directive angular will try to compile child directive, and a child directive in ui-select does not compile.

When a call to "compile" is invoked on the directive the behavior is now different.
Before lazy compilation a direct call to the compile function was made:

childTranscludeFn = compile($template, transcludeFn, terminalPriority,
  replaceDirective && replaceDirective.name, {
                                          // Don't pass in:
                                          // - controllerDirectives - otherwise we'll create duplicates controllers
                                          // - newIsolateScopeDirective or templateDirective - combining templates with
                                          //   element transclusion doesn't make sense.
                                          //
                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
                                          // on the same element more than once.
                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
                                        });

Now, it is replaced with

childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
                                        replaceDirective && replaceDirective.name, {
                                          // Don't pass in:
                                          // - controllerDirectives - otherwise we'll create duplicates controllers
                                          // - newIsolateScopeDirective or templateDirective - combining templates with
                                          //   element transclusion doesn't make sense.
                                          //
                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
                                          // on the same element more than once.
                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
                                        });

The latter will send a lazy instruction hence the returning function will be a compilation invoker rather then the result of the compilation. Stepping further reveals that the compilation invoker function never gets invoked.

Again, very tricky and complex.
Whats more strange is that I have tried to mimic ui-select's behavior on simple directives with no success, I cant mimic it for some reason.

I believe that the protection implemented to prevent this case does not cover all use cases.

        if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
            || (directive.transclude && !directive.$$tlb))) {
                var candidateDirective;

                for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {
                    if ((candidateDirective.transclude && !candidateDirective.$$tlb)
                        || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
                        mightHaveMultipleTransclusionError = true;
                        break;
                    }
                }

                didScanForMultipleTransclusion = true;
        }

I debugged it and it yielded false, hence lazy compilation implemented.

See my issue on angular-ui/ui-select#1372 for extra info

I dont know where the issue is but I guess its in angular.js since it broke an old working implementation.

@shlomiassaf
Copy link
Author

@dcherman
@lgalfaso

@lgalfaso
Copy link
Contributor

this looks like a duplicate of #13527 and the issue opened on ui-select looks like a duplicate of angular-ui/ui-select#1356

Now, that said, it looks like the issue is a race condition within ui-select as it is possible to reproduce the issue with 1.4 #13527 (comment)

@shlomiassaf
Copy link
Author

👍

Spent some 2-3 hours on that but learned a lot about the transclusion core behavior.

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

No branches or pull requests

3 participants