zachsnow / ng-multi-transclude

ng-multi-transclude
MIT License
79 stars 19 forks source link

Require check fails for directive as transclude content #19

Closed sasyomaru closed 9 years ago

sasyomaru commented 9 years ago

I'm using ng-multi-transclude in a website and find an issue on the disconnection of transclude content and the context. For example,

    <!doctype html>
    <html ng-app="myApp">
    <head>
      <script src="./angular.js"></script>
      <script src="./multi-transclude.js"></script>
      <script>
          angular.module('myApp', ['multi-transclude'])
                  .directive('myTemplate', function() {
                    return {
                        transclude: true,
                        template: [
                            '<div ng-multi-transclude-controller>',
                                '<h1>Some template A</h1>',
                                '<div ng-multi-transclude="some-block-a"></div>',
                                '<div ng-multi-transclude="another-block-a"></div>',
                            '</div>'].join('')
                    };
                  })
                  .directive('belowForm', function() {
                    return {
                      require: '^form',
                      template: '<div>This should be put in a form tag</div>',
                      link: function() { /* Trigger require checking */ }
                    };
                  });
      </script>
    </head>
    <body>
      <form>
          <my-template>
              <below-form name="some-block-a"></below-form>
              <below-form name="another-block-a"></below-form>
          </my-template>
          <div ng-multi-template="some-template">
              <below-form name="some-block-b"></below-form>
              <below-form name="another-block-b"></below-form>
          </div>
      </form>
      <script type="text/ng-template" id="some-template">
          <h1>Some template B</h1>
          <div ng-multi-transclude="some-block-b"></div>
          <div ng-multi-transclude="another-block-b"></div>
      </script>
    </body>
    </html>

When running the code, there will be an error "[$compile:ctreq] Controller 'form', required by directive 'belowForm', can't be found!" and the template is not filled correctly. This is because the controller doesn't append the transclude content into its context until ctrl.transclude is called, but the link of directive happens in $transclude, which makes the content lost the context.

sasyomaru commented 9 years ago

I've created a pull request to fix this problem (#20). Hopefully it will fix the issue. Would appreciate very much if you could have a look at it.

zachsnow commented 9 years ago

Thanks @sasyomaru! I believe this is the source of various the issues with controllers others have been having.

rainboxx commented 9 years ago

We're in need of a fix for this. Is the PR #20 the way a fix should be, @zachsnow?

At least it seems to work for the issue above (which is the same we have) :).

zachsnow commented 9 years ago

@sasyomaru I played with this a little and it seems that we don't even need the hidden container, we can simply attach the transcluded content directly to the element, and then the link functions will move the content into the correct places.

@rainboxx it does indeed work, I just want to find the minimal solution possible (which this may well be).

rainboxx commented 9 years ago

@zachsnow I appreciate your investigation!

I found out that this PR will not fix all issues that we're having. Our directive using the multi-transclude also adds a form to the DOM. With a normal transclude we're able to access the form from within the transcluded content. Using the multi-transclude we cannot access that scope and therefor are unable to get our hands to the FormController.

zachsnow commented 9 years ago

@rainboxx interesting, any chance you can sketch out more precisely what you mean?

rainboxx commented 9 years ago

I can try to make a jsfiddle tomorrow, I'm about to leave for bed now (UTC+1).

zachsnow commented 9 years ago

@rainboxx thanks very much.

zachsnow commented 9 years ago

@sasyomaru I suppose we could add ng-hide during the initial transclude and then remove it when moving the individual components to the correct place if there's a worry about flashing content perhaps? It seems it should be batched though.

sasyomaru commented 9 years ago

The flashing content is also what I concerned most. But adding ng-hide may have conflict if the directive user already add ng-hide (for example, to show the template only under some condition).

zachsnow commented 9 years ago

@sasyomaru you make a good point re: ng-hide. Ok, we'll use a nested container with ng-hide and remove the container when all of its content has been moved to the right position.

zachsnow commented 9 years ago

It seems we should be able to get rid of this:

$scope.$on('$destroy', function(){
  if(toTransclude){
    toTransclude.remove();
    toTransclude = null;
  }
});

Because toTransclude stays in the DOM now, and so already be removed when the scope is destroyed, no?

zachsnow commented 9 years ago

I've updated master to include these ideas.

rainboxx commented 9 years ago

@zachsnow Sorry for the delay, kids got sick and we had to work on some different stuff first. I no longer think my issue is related to this so I opened another issue, #23. Thanks!