Search code examples
javascriptangularjszurb-foundationangular-foundation

Angularjs Multiple Directives Asking For Transclusion when lazy loading


I'm trying to setup a simple angularjs app using ui.router, ocLazyLoad, Foundation and angular-foundation.

The app is a multi-view app with it's components lazy loaded using ocLazyLoad. I have no problem setting up the views and associated controllers. However, I am having an issue when trying to display a Foundation alert. When I try to view my alerts (route1), I get empty alerts. And the stack trace below.

Why is angular applying the alert directive twice? A plunker is available here: http://goo.gl/lhtD0c

Error: [$compile:multidir] Multiple directives [alert, alert] asking for transclusion on:        
<div class="alert-box" ng-class="(type || &quot;&quot;)" ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">
http://errors.angularjs.org/1.2.22/$compile/multidir?p0=alert&p1=alert&p2=t…lerts%22%20type%3D%22alert.type%22%20close%3D%22closeAlert(%24index)%22%3E
at https://code.angularjs.org/1.2.22/angular.js:78:12
at assertNoDuplicate (https://code.angularjs.org/1.2.22/angular.js:6933:15)
at applyDirectivesToNode (https://code.angularjs.org/1.2.22/angular.js:6353:13)
at https://code.angularjs.org/1.2.22/angular.js:6858:37
at https://code.angularjs.org/1.2.22/angular.js:8091:11
at wrappedCallback (https://code.angularjs.org/1.2.22/angular.js:11546:81)
at wrappedCallback (https://code.angularjs.org/1.2.22/angular.js:11546:81)
at https://code.angularjs.org/1.2.22/angular.js:11632:26
at Scope.$eval (https://code.angularjs.org/1.2.22/angular.js:12658:28)
at Scope.$digest (https://code.angularjs.org/1.2.22/angular.js:12470:31)

The body of my index is below:

<body>
    <div>
        <a class="button" ui-sref="route1">Route 1</a>
        <a class="button" ui-sref="route2">Route 2</a>
    </div>

    <div ui-view></div>
</body>

The javascript associated with this page is:

var myapp = angular.module('myapp', ['ui.router', 'oc.lazyLoad', 'mm.foundation'])

myapp.config(function($stateProvider, $urlRouterProvider){

  // For any unmatched url, send to /route2
  $urlRouterProvider.otherwise('/route2')

  $stateProvider
    .state('route1', {
        url: "/route1",
        controller: 'Route1',
        templateUrl: "route1.html",
        resolve: {
            loadCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
                return $ocLazyLoad.load({
                    name: 'myapp',
                    files: ['route1.js']
                })
            }]
        }
    })
    .state('route2', {
        url: "/route2",
        templateUrl: "route2.html"
    })
});

$(function() {
    Foundation.global.namespace = '';
    $(document).foundation();
})

The problems are associated with route1. Here is the route1 template.

<div ng-controller="Route1">
    Route 1 - {{ message }}

    <br/>

    <alert ng-repeat="alert in alerts"
           type="alert.type"
           close="closeAlert($index)">{{alert.msg}}</alert>
</div>

and finally the route1.js -

angular.module('myapp').controller('Route1', ['$scope', function($scope) {
    $scope.message = 'Hello, world!'

    $scope.alerts = [
        { type: 'danger', msg: 'Oh snap! Change a few things up and try submitting again.' },
        { type: 'success round', msg: 'Well done! You successfully read this important alert message.' }
    ];

}]);

Solution

  • The problem is that it's reloading your "myapp" module dependencies. Just config ocLazyLoad not to reload foundation like this:

    $ocLazyLoadProvider.config({
        loadedModules: ['mm.foundation']
    });
    

    It will be something like that:

    var myapp = angular.module('myapp', ['ui.router', 'oc.lazyLoad', 'mm.foundation'])
    
    myapp.config(function($stateProvider, $urlRouterProvider, $ocLazyLoadProvider){
    
      // For any unmatched url, send to /route2
      $urlRouterProvider.otherwise('/route2')
    
      $ocLazyLoadProvider.config({
            loadedModules: ['mm.foundation']
        });
    
      $stateProvider
        .state('route1', {
            url: "/route1",
            controller: 'Route1',
            templateUrl: "route1.html",
            resolve: {
                loadCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
                    return $ocLazyLoad.load({
                        name: 'myapp',
                        files: ['route1.js']
                    })
                }]
            }
        })
        .state('route2', {
            url: "/route2",
            templateUrl: "route2.html"
        })
    });
    
    $(function() {
        Foundation.global.namespace = '';
        $(document).foundation();
    })