Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using OpenLayers with RequireJS and AngularJS

I'm trying to get an app running that uses both AngularJS and RequireJS. I'm having problems getting my OpenLayers lib to work in this setup.

I set the main AMD-modules in the main.js:

require.config(
    {
        baseUrl: 'scripts',
        paths: {
            // Vendor modules
            angular: 'vendor/angular/angular',
            openLayers: 'vendor/openlayers-debug',
            other modules.....
        },
        shim: {
            angular: {
                exports: 'angular'
            },
            openLayers: {
                exports: 'OpenLayers'
            },
            other modules....
        }
    }
);

require(['openLayers',
        'angular',
        'app',
        'controllers/olMapController',
        'directives/olMap',
        other modules...
    ], function(OpenLayers) {
        return OpenLayers;
    }
);

Then in the angular controller I use for the initialisation of OpenLayers, I try to indicate that openlayers-debug.js is a dependency:

define(['openLayers'],
    function(OpenLayers) {
        controllers.controller('olMapController', ['$scope', function(scope) {
            console.log('Loaded olMapController. OpenLayers version: ' + OpenLayers.VERSION_NUMBER);
        }]);
    }
);

Well, this doesn't work. SOMETIMES the olMapController function is executed, but mostly not. The console then just displays an error stating:

Error: [ng:areq] Argument 'olMapController' is not a function, got undefined

So, I think OpenLayers hasn't finished loading yet, but somehow require thinks it has and continues loading code that depends on OpenLayers, in this case the olMapController. It then can't find its dependency, whereupon Angular returns this error message. Or something like that...? Sometimes something happens that makes OpenLayers load fast enought for it to be present when it is loaded as a dependency. What that is, I can't tell.

I left out other libraries and modules require and define to keep the code readable. I hope the example is still understandable.

Any ideas on what I could do to get openlayers to load well? The error message disappears when I leave the ['openLayers'] dependency out of olMapController.

Thanks in advance for any help.

Best regards, Martijn Senden

like image 271
Martijn Avatar asked Dec 26 '22 14:12

Martijn


2 Answers

Well, just for reference my final solution. The comment by angabriel set me off in the right direction.

Like i said, I'm using the domReady module provided by RequireJS to bootstrap Angular. This is still being called to early, because OpenLayers isn't loaded yet when angular starts. RequireJS also provides a callback property in require.config. This is a function that is triggered when all the dependencies are loaded. So I used that function to require the angular bootstrap module. My config now looks like this:

require.config(
    {
        baseUrl: 'scripts',
        paths: {
            // Vendor modules
            angular: 'vendor/angular/angular',
            domReady: 'vendor/domReady',
            openLayers: 'vendor/openlayers-debug',
            etcetera....

        },
        shim: {
            angular: {
                deps: ['jquery'],
                exports: 'angular'
            },
            openLayers: {
                exports: 'OpenLayers'
            },
        },
        deps: ['angular',
            'openLayers',
            'app',
            'domReady',
            'controllers/rootController',
            'controllers/olMapController',
            'directives/olMap'
        ],
        callback: function() {
            require(['bootstrap']);
        }
    }
);

And the bootstrap module looks like this:

define(['angular', 'domReady', 'app'], function(angular, domReady) {
    domReady(function() {
        angular.bootstrap(document, ['GRVP']);
    });
});

Thanks for the help. @angabriel: I upvoted your comment. It's not possible to accept a comment as an answer, is it? Your initial answer wasn't really the answer to my question, but the comment helped a lot...

Regards, Martijn

like image 143
Martijn Avatar answered Dec 28 '22 07:12

Martijn


Sorry this answer will only contain text as your code is too big for a small example.

I would suggest to write a directive that utilizes head.js to load libraries you need at a specific context. One could also think of a directive that initializes openLayers this way.

I guess your error is a timing problem, because the require.js and angular.js module loading gets out of sync - more precisely there seems to be no sync at all between them.

update
To repeat my comment which lastly helped to lead the OP in the right direction:

You have to decide which framework gives the tone. If you go with requireJS, then require everything and bootstrap angular manually. (Remove ng-app="" from index.html) and do `angular.bootstrap()´ when requirejs has completed. So the problem most likely is, that angular starts too early.

like image 29
angabriel Avatar answered Dec 28 '22 05:12

angabriel