2

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.' }
    ];

}]);
Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
jaime
  • 2,234
  • 1
  • 19
  • 22

3 Answers3

5

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();
})
Olivier
  • 1,270
  • 1
  • 10
  • 24
0

Replace this code

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

by

<div ng-repeat="alert in alerts">
  <alert type="alert.type" close="closeAlert($index)">{{alert.msg}}</alert>
</div>
Alexey
  • 1,257
  • 7
  • 13
  • That doesn't change anything. You can actually see the ng-repeat / alert code working here -> http://embed.plnkr.co/rRJKPEOrW594iEnkJ0Kj/preview – jaime Sep 17 '14 at 19:26
  • I forked your plunk & with my changes the code works well http://plnkr.co/edit/hMWQFdAN6BMt9Nr6EGxk?p=preview – Alexey Sep 17 '14 at 19:36
  • The alerts should be "styled" in nice colored boxes. Your plunker has a syntax error in route1.html -> alerttype="alert.type" which should read alert type="alert.type" The bug is nasty. I do not understand why the alert directive is being gathered twice. – jaime Sep 17 '14 at 19:50
0

I finally managed to make this work. The problem was that ocLazyLoad was reloading the 'myapp' module. This caused the dependencies to reload. One of the dependencies was mm.foundation which reprocessed all the directives creating a clone of each pair.

To prevent this,I did not tie the second controller to myapp. Instead I created a new app 'route1app'. You can see the updated plunker here: http://goo.gl/lhtD0c

jaime
  • 2,234
  • 1
  • 19
  • 22