AngularJS, requireJS and ngRoute

2019-04-07 01:33发布

问题:

I'm building an Address Book to learn angular and have it working nicely until I try to use the route manager. The issue is with loading the angular route manager via require. I'm getting the following error 'Uncaught object'.

There have been questions about this but they have been removed by the user, and other answers point to not having included the ngRoute dependancy in the ng.module dependancy list, or aren't using require at all. I'm not having much luck finding an answer!

I have the an HTML file that includes a require config file:

requirejs.config({
  paths: {
    'jquery': ['//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min'],
    'angular': ['//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min','angular_1.2.16.min'],
    'angular-route': ['//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular-route.min','angular-route_1.2.16.min'],
  },
  shim: {
    'jquery': {
      exports: 'jquery'
    },
    'angular': {
      exports: 'angular'
    },
    'angular-route': {
      exports: 'ngRoute',
      deps: ['angular']
    } 
  },
  baseUrl: 'js/lib'
})

require(['modules/ContactsMod'], function() { });

and this is the ContactsMod.js file called at the end of the config file:

define(['jquery', 'angular-route','angular','controllers/ContactsCtrl','routes/ContactsRout'],function($,ngRoute,ng,controller,router) {

//  var contactsApp = ng.module('contactsApp', [ngRoute]);

//  contactsApp.config(function ( $routeProvider, $locationProvider ){
//    $log.debug( "Configuring $routeProvider...");
//
//    $locationProvider.html5Mode(true);  //?????
//
//    $routeProvider
//      .when( '/', {
//        templateUrl : "views/Contacts.html",
//        controller  : "controller"
//      })
//      .otherwise({ redirectTo: '/' })
//  })

    var contactsApp = ng.module('contactsApp', []);
    contactsApp.controller(controller);
    ng.bootstrap(document, ['contactsApp']);


});

The commented out section is the part I'm trying to figure out. The above version works, but when I try to add the ngRoute dependancy to the ng.module call in the commented out part I get the error mentioned.

I can see that all the assets have been loaded before the module is called. But I can also see that the ngRoute logs out as undefined so it makes sense that it doesn't work! I've tried a number of different config variants. Like including the angular-route as a dependancy of angular (which give the same error plus another of 'Uncaught TypeError: Cannot read property 'module' of undefined').

I can see there's a seed app that uses custom async loader instead of require... what do you recommend?

I don't know how to debug this problem, any help or pointers appreciated!

回答1:

So I took ivarni's advice and checked out the differences between my example and the github.com/tnajdek/angular-requirejs-seed repo.

Actually it wasn't that far off and the main issue was to do with the bootstrap call. When you use require the bootstrap effectively fires before the assets have loaded. The confusion comes because if you look in the network tab it appears that the assets have been loaded by require. However, Angular had already executed the bootstrap without the additional assets. Please see: https://code.angularjs.org/1.2.1/docs/guide/bootstrap#overview_deferred-bootstrap for more info on what the bootstrap needs to do when using angular with require.

My require config file now looks like:

require.config({
    baseUrl: 'js',
    paths: {
        jquery: ['//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min', 'lib/jquery/jquery_2.0.0.min.js'],
        angular: ['//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min', 'lib/angular/angular_1.2.16.min'],
        angularRoute: ['//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular-route.min', 'lib/angular-route/angular-route_1.2.16.min']
    },
    shim: {
        'angular' : {'exports' : 'angular'},
        'angularRoute': ['angular'],
    }
});

window.name = "NG_DEFER_BOOTSTRAP!";

require( ['angular', 'modules/contactsMod', 'routes/contactsRoutes'], function(angular, contactsMod, routes) {
    'use strict';

    var $html = angular.element(document.getElementsByTagName('html')[0]);

    angular.element().ready(function() {
        angular.resumeBootstrap([contactsMod.name]);
    });
});

To make this work I also had to return the included module so that I could call it as a module with dependencies in the snippet above. So my ContactsMod.js now looks like this:

define(['angular', 'controllers/contactsCtrl', 'angularRoute'], function (angular, controllers) {
    'use strict';

    // Declare app level module which depends on filters, and services
    return angular.module('contactsMod', [ 'ngRoute', controllers.name]);
});

I hope this is useful to someone... Thanks for your help folks!



回答2:

You don't need export 'ngRoute' in:

'angular-route': {
      deps: ['angular']
    } 

And you miss '' when you inject ngRoute, try this:

define(['angular','jquery', 'angular-route','controllers/ContactsCtrl','routes/ContactsRout'],function(ng) {

var contactsApp = ng.module('contactsApp', ['ngRoute']);

contactsApp.config(function ( $routeProvider, $locationProvider ){
    $log.debug( "Configuring $routeProvider...");

    $locationProvider.html5Mode(true);

    $routeProvider
      .when( '/', {
        templateUrl : "views/Contacts.html",
        controller  : "controller"
      })
      .otherwise({ redirectTo: '/' })

    contactsApp.controller(controller);
    ng.bootstrap(document, ['contactsApp']);


});