2

if I nest ui-view inside a directive with transclude=true, the view content does not load. It works fine without the intervening directive.

so with a page containing:

<body>
<div ng-controller="MainController">
        <div ui-view="sampleView"></div>
</div>
</body>

the sampleView content appears.

But if i put

<body>
<div ng-controller="MainController">
    <div sample-directive>
        <div ui-view="sampleView"></div>
    </div>
</div>
</body>

then the view content doesn't appear.

I have created a simple html page to demonstrate the problem, see below.

As far as I can see, the angular compiling process does correctly call updateView in the ui-view directive in angular-ui, and that does build the view content and insert it in the dom under the sample-directive node, but that doesn't seem to be the actual visible sample-directive node, but a clone of it. i'm guessing it has to do with the order of compilation and therefore I need to do something clever in the directive, but i can't find anything in the angular api help that covers this point.

i've tried adding a post-link function and calling $transclude from there but it makes no difference.

can anyone advise what i need to add to the directive so this will work. thanks

UPDATE New info from further investigation: It seems the cause is this (not at this point a solution, but I can see why it happens). In angular's function applyDirectivesToNode (angular.js line 5919), if a directive specifies transclude=true, then the original directive node is cloned to make the template node. ie the template is not the original node that's visible in the dom. Now, when the compile function of ui-view in angular-ui-router.js line 2204 is called, it grabs a copy of the parent of the ui-view node, storing it in parentEl. But, and here's where the problem occurs - this parent is the parent in the dom of the ui-view node. what it's most certainly not is the instance of the parent that actually ends up in the dom after linking. Later when the ui-view updates for the initial route change, it builds the view content and inserts it under parentEl (angular-ui-router.js line 2273), but as we saw earlier this isn't in the visible dom after linking. it's the source html node and not the clone created by compiling and linking the directive in which the ui-view is nested.

I think this may be a bug in ui-view.

There may be a way to add a workaround to the directive, to get the post-link view instance and put it into the directive. If I figure it out I'll add an answer.

html to demonstrate the issue as follows:

<!DOCTYPE html>
<html lang="en" ng-app="viewInDirectiveApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title>View inside a directive</title>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js"></script>

<script src="modules/angular-ui-router.js"></script>

<script>
    var viewInDirectiveApp = angular.module('viewInDirectiveApp', ['ui.router']);

    viewInDirectiveApp.config(function ($stateProvider, $urlRouterProvider) {
        $stateProvider
            .state('sampleState', {
                url: '/sampleState',
                views: {
                    sampleView: {
                        template: 'This is the view content',
                        controller: function ($scope) {
                        }
                    }
                }
            });
        $urlRouterProvider.otherwise("/sampleState");
    })
    .controller('MainController', ['$scope',
        function ($scope) {
        }])
    .directive('sampleDirective', function () {
        return {
            template: 'Start directive content <div ng-transclude></div> End directive content',
            transclude: true
        };
    });
</script>
</head>
<body>
<div ng-controller="MainController">
    Before sampleDirective
    <div sample-directive>
        Before sampleView
        <div ui-view="sampleView"></div>
        After sampleView
    </div>
    After sampleDirective
</div>
</body>
</html>
Chris H
  • 78
  • 1
  • 7
  • check out [this post on a similar issue](http://stackoverflow.com/a/20305370/547020), which may apply to your case as well. you probably just need to invoke the `$route`'s `reload()`. – Eliran Malka Feb 15 '14 at 21:29
  • thanks, however $route is from the old angular routing ngRoute module. i'm using ui.router which is different. having said that, it may be that the same principle would work in this case, although i hate the idea of loading the view twice - not very efficient!anyway, i'll see if the approach works – Chris H Feb 15 '14 at 23:09
  • ui.router works regardless of the `$route` implementation - it's a separate module. even though there were breaking changes on 1.2, your use of ui.router should make no difference (i.e. the reload should work). anyhow what i suggested is a workaround to an issue when taking a certain approach, which can be avoided entirely if you're using ui.router. – Eliran Malka Feb 16 '14 at 09:20

2 Answers2

4

Confirmed bug in ui-router 0.2.8: https://github.com/angular-ui/ui-router/issues/774

Fixed in 0.2.10: https://github.com/angular-ui/ui-router/pull/858

Chris T
  • 8,186
  • 2
  • 29
  • 39
0

Plunkers are much appreciated: http://plnkr.co/edit/TZ8hvkSbCIa0dTj0NkcG?p=preview - Seems to work in Angular-routing: http://dotjem.github.io/angular-routing/

Jens
  • 3,353
  • 1
  • 23
  • 27