Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular-Meteor - How can I include ng template in package-based design?

I have an Angular-Meteor application working. I would like to package Angular templates and associated controller into a Meteor package, and inject these templates into my main application by adding that package.

What is best approach?

Update 2015-08-26 - I figured out how to add a template, documented below. But how to have a Meteor package inject the template's Angular controller into the base application?

A key tie-in is Angular UI-router.

I have a base application that includes my package named packageprefix:packagename. Inside this package I have my code in the root of the package folder: myPackagedPage.ng.html - the Angular HTML template myPackagedPage.js - the associated Angular controller

From my main application, I tried creating a route to my Angular template like so:

angular.module('parentModule',[
    'angular-meteor',
    'ui.router',
    'angularify.semantic.sidebar'
])

.config(['$urlRouterProvider', '$stateProvider', '$locationProvider',
function($urlRouterProvider, $stateProvider, $locationProvider){
    console.log("app.js config!");
    $locationProvider.html5Mode(true);

    $stateProvider
        .state('home', {
            url: '/',
            templateUrl: 'client/views/home/home.ng.html',
            controller: 'HomeCtrl'
        })

        .state('myPackagedPage', {
            url: '/myPackagedPage',
            templateUrl: 'packageprefix_packagename/myPackagedPage.ng.html',
            controller: 'MyPackagedPageCtrl'
        })
    ;

    $urlRouterProvider.otherwise('/');

}])

The application successfully finds the myPackagedPage.ng.html file and renders it. But how to add the controller?

I tried adding this in my package but the controller functions does not get called.

console.log("myPackagedPage.js loaded");
angular.module('parentModule')

.controller('MyPackagedPageCtrl', ['$scope',
    function($scope){
        console.log("MyPackagedPageCtrl");
    }])
;

I get an error:

Argument 'MyPackagedPageCtrl' is not a function, got undefined
like image 577
davedonohue Avatar asked Sep 27 '22 22:09

davedonohue


1 Answers

I have this working now. Here is the approach that works for me, to inject an Angular Controller + template in a Meteor package, into the containing application.

In my package.js, I have this

Package.onUse(function(api) {
    api.versionsFrom('1.1.0.3');
    api.use('angular:[email protected]', 'client');
    api.use("urigo:[email protected]", 'client');
    api.use("[email protected]", 'client');

    //api.use('angularui:[email protected]', 'client');
    api.addFiles('interests.js', 'client');
    api.addFiles('interests.ng.html', 'client');

    api.export("InterestsCtrl", "client")
});

Note you must export your controller, so that the parent application may access it.

In my package, called ramshackle:bigd-interests, I have these files at the root level: package.js, interests.ng.html, and interests.js. interests.js injects the Angular controller, the Anguilar UI-router route to the template, and a sidebar link into the parent application. It accomplishes this by using the Meteor Session. I played with other means of doing this but Session was the only thing that worked. Just be careful to properly scope your session variable names.

//add controllers
var controllers = Session.get("BIGD.controllers");
if (!controllers) controllers = {};

var interestsCtrlSpec = "'$scope', InterestsCtrl";

InterestsCtrl = function($scope){
    console.log("InterestsCtrl running");
};
controllers.InterestsCtrl = interestsCtrlSpec;
Session.set("BIGD.controllers", controllers);

//add routes
var routes = Session.get("BIGD.routes");
if (!routes) routes = {};
routes.interests = {
    url: '/interests',
    templateUrl: 'ramshackle_bigd-interests_interests.ng.html',
    controller: 'InterestsCtrl'
};
Session.set("BIGD.routes", routes);

//add sidebar links
//the key determines sorting order
var sidebar = Session.get("BIGD.sidebar");
if (!sidebar) sidebar = {};
sidebar["interests"] = {
    url: '/interests',
    templateUrl: 'ramshackle_bigd-interests_interests.ng.html',
    controller: 'InterestsCtrl',
    rank: 5
};
Session.set("BIGD.sidebar", sidebar);

var interestsItem = {label: 'Interests', link: '/interests', icon: "rocket"};

In my parent application's app.js , I dynamically loaded the controllers and routes from the session like this:

angular.module('bigdam',[
    'angular-meteor',
    'ui.router',
    'angularify.semantic.sidebar',
    'nvd3',
    'leaflet-directive',
    'ui.router.history'
])

    .config(['$urlRouterProvider', '$stateProvider', '$locationProvider',
    function($urlRouterProvider, $stateProvider, $locationProvider){
        //console.log("app.js config!");
        $locationProvider.html5Mode(true);

        //add a static state
        $stateProvider
            .state('home', {
                url: '/',
                templateUrl: 'client/views/home/home.ng.html',
                controller: 'HomeCtrl'
            });

        //add the dynamic routes/states from other Meteor packages
        for (var stateId in routes) {
            var route = routes[stateId];
            $stateProvider
                .state(stateId, route);
        }

        $urlRouterProvider.otherwise('/');
    }])
;

//Declare the controllers from plugins
for (var controllerId in controllers) {
    var controllerSpec = controllers[controllerId];
    var controllerSpecArray = eval("[" + controllerSpec + "]")
    angular.module('bigdam').controller(controllerId, controllerSpecArray);
}

So now, when I create a new Meteor package, and follow the convention described above, its controllers, routes, and sidebar links get loaded into the main application.

like image 84
davedonohue Avatar answered Sep 30 '22 08:09

davedonohue