angular app plugin

Plugin Development
  • Hello,
    I'm working on a plugin that is an angular app. I started to work with nodebb 0.6.1 and everything works nicely.
    Today I upgrade to 0.7.0 Now when I click on my icon header the main template is well loaded but not the one inside my ng-view directive. If I reload the page (F5) everything is well loaded.

    All my javascprit files (angular.js, angular-route.js, controllers, etc.) are defined in the script section of my plugin.json.

    Doesn't anyone know what are the changes between 0.6.1 and 0.7.0 that causes this behaviour and how can I correct my code.

    Thanks in advance and let me know if you need to post part of the code

  • Can you paste your angular code? I'm not an expert but I have a feeling I know what the problem may be

  • Here is the angular app main file with routes, I only include the two first one

    "use strict";
     var fbapp = angular.module("francoBowlApp", 
     ["ngRoute", 
     "angularFileUpload", 
     "ngDragDrop",
     "ui.bootstrap",
     "angularUtils.directives.dirPagination",
     "services"]);
    
    // get global variable
    fbapp.run(["$rootScope", function($rootScope) {        
        $rootScope.fb_webservice = document.getElementById("fbws").textContent;}]);
    
    // configure routes
    fbapp.config(["$routeProvider'","$httpProvider",
        function($routeProvider, $httpProvider) {
           var rootFolder = "templates/angular",
           token = document.getElementById("token").textContent;
    
          $routeProvider
           // route de la page index
          .when("/", {
                templateUrl : rootFolder+"/index.tpl",
                controller  : "fbCtrl"
           })
          // route de la page mon franco bowl
         .when('/monfranco', {
               templateUrl : rootFolder+"/francobowl/index.tpl",
              controller : "fbMonFrancoIndexCtrl"
          });
         // include bearer token in each web service call
         $httpProvider.defaults.headers.common.Authorization = "Bearer"+ token;
    }]);
    

    Then the main template

    <div class="row" 
        ng-app="francoBowlApp" 
        ng-controller="fbCtrl">
        <span hidden="hidden" id="token">{token}</span>
        <span hidden="hidden" id="fbws">{fbws}</span>
        <span hidden="hidden" id="username">{username}</span>
    
        <div class="col-sm-2">
            <div class="sidebar-nav">
                <div class="navbar navbar-default" role="navigation">
                    <div class="navbar-header">
                        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".sidebar-navbar-collapse">
                            <span class="sr-only">Toggle navigation</span>
                            <span class="icon-bar"></span>
                            <span class="icon-bar"></span>
                            <span class="icon-bar"></span>
                        </button>
                        <span class="visible-xs navbar-brand">Site menu</span>
                    </div>
                    <div class="navbar-collapse collapse sidebar-navbar-collapse">
                        <ul class="nav navbar-nav">
                            <!-- IF uid -->
                            <li><a href="#/monfranco">Mon Franco Bowl</a></li>
                            <!-- ELSE -->
                            <li><a href="#">Accueil</a></li>
                            <!-- ENDIF uid -->
                            <li class="dropdown">
                                <a href="#" class="dropdown-toggle" data-toggle="dropdown">Administrer <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    <li><a href="#/admin/competition">Compétitions</a></li>
                                    <li><a href="#/admin/mot_clef">Mots clefs</a></li>
                                    <li><a href="#/admin/image">Images</a></li>
                                    <li><a href="#/admin/jeu">Jeux</a></li>
                                </ul>
                            </li>
                            <li><a href="#/equipe">Equipes</a></li>
                        </ul>
                    </div><!--/.nav-collapse -->
              </div>
            </div>
        </div>
    
        <div class="col-sm-10 col-xs-12">
            <div ng-view>         
            </div>
        </div>
    </div>
    

    And my library.js

    "use strict";
    
    var plugin = {},
        user = module.parent.require('./user'),
        async = module.parent.require('async'),
        meta = module.parent.require('./meta'),
        http = require('http'),
        jwt = require('jsonwebtoken');
    
    function renderAdminPage(req, res, next) {
        res.render('admin/plugins/francobowl', {});
    }
    
    function renderCustomPage(req, res, next) {
        var jwt = require('jsonwebtoken'),
            err,
            userInfo = {},
            url = req.body.url,
            config;
    
        // recuperer les informations sur l utilisateur
        async.parallel({
            // definition des données utilisateur
            userData : function(next) {
                if (req.user && req.user.uid) {
                    // si l utilisateur est authentifie appel a la base de donnees
                    user.getUserData(req.user.uid, next);
                } else {
                    // si l utilisateur n est pas authentifie definir comme anonyme
                    next(err, {uid : 0, username : 'anonymous'});
                }  
            },
            // verifier si l utilisateur est un administrateur
            isAdministrator : function(next) {
                if (req.user && req.user.uid) {
                    // si l utilisateur est authentifieappel a la base de donnees
                    user.isAdministrator(req.user.uid, next);
                } else {
                    // si l utilisateur n est pas authentifie definir comme 
                    // non administrateur
                    next(err, false);
                }  
            },
            // recuperer les donnees de configuration du franco bowl
            config : function(next) {
                meta.settings.get('francobowl', function(err, settings){
                    if (err) {
                        next(err);
                    }
                    config = settings;
                    next();
                });
            }
        }, function(err, data) {
            // en cas d erreur redirection vers la page d erreur
            if(err) {
                return res.redirect(url + '?error=' + err.message);
            };
    
            // definir les donnees de l utilisateur en fonction des donnees gerees
            userInfo =  {
                uid : data.userData.uid,
                username : data.userData.username,
                admin : data.isAdministrator
            };
    
            // creer le token pour les appels aux webservice
            userInfo.token = jwt.sign(userInfo, config.secret_key, {
                expiresInMinutes: 60 * 5
            });
    
            // charger l url des webservices francobowl
            userInfo.fbws = 'http://' + config.fb_ws + config.fb_root;
    
            // charger la page
            res.render('francobowl-page', userInfo);
        });
    }
    
    plugin.addNavigation = function(header, callback) {
        // ajouter le lien dans le menu de navigation principal
        header.navigation.push({
            class: '',
            route: '/francobowl',
            iconClass: 'fa fa-fw fa-shield',
            title: 'FrancoBowl',
            text: 'Franco Bowl'
        });
        callback(null, header);
    };
    
    plugin.addAdminNavigation = function(custom_header, callback) {
        // ajouter le lien dans le menu de navigation de la page d admin
        custom_header.plugins.push({
                route: '/plugins/francobowl',
                icon: 'fa-file-archive-o',
                name: 'Franco Bowl'
            });
    
        callback(null, custom_header);
    };
    
    plugin.init = function(params, callback) {
        // ajouter les routes
        var app = params.router,
            middleware = params.middleware;
    
        app.get('/FrancoBowl', middleware.buildHeader, renderCustomPage);
        app.get('/templates/FrancoBowl.tpl', renderCustomPage);
        app.get('/api/FrancoBowl', renderCustomPage);
    
        app.get('/admin/plugins/francobowl', middleware.admin.buildHeader, renderAdminPage);
        app.get('/api/admin/plugins/francobowl', renderAdminPage);
    
        callback();
    };
    
    // creer le coach dans la base du francobowl
    plugin.userData = function(newUser) {
    
        // recuperer les donnees d acces au web service du francobowl
        meta.settings.get('francobowl', function(err, settings){
            if (err) {
                next(err);
            }
            // recuperer les donnees de l adminitsrateur
            user.getUserData(1, function(err, user){
                if (err) {
                    next(err);
                }
                // definir les donnees à transferer
                var data = JSON.stringify({uid: newUser.uid}),
                    // donnees administrateur pour le JWT
                    userInfo =  {
                        uid : user.uid,
                        username : user.username,
                        admin : true
                    },
                    // les donnees pour la requête
                    options = {
                        host: settings.fb_ws,
                        path: settings.fb_root + '/coach',
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Content-Length': data.length,
                            'Authorization': 'Bearer ' + jwt.sign(userInfo, settings.secret_key, {
                                        expiresInMinutes: 60 * 5
                            })
                        }
                    },
                    // definir la requete post
                    req = http.request(options, function(res) {
                        var msg = '';
                        res.on('data', function(chunk){
                            msg += chunk;
                        });
                        res.on('end', function(){
                            if (res.statusCode !== 200) {
                                console.log('Error : ' + res.msg);
                            }
                        });
                    });
                // lancer la requete post
                req.write(data);
                req.end();            
            });
        });
    };
    
    module.exports = plugin;
    

    Hope you can help and let me know if you want something else.
    Thanks in advance

  • Ok, so to reproduce the problem I prepare a basic angular page loaded as nodebb pluging. It will certainly be easiest to check what's going wrong with the 0.7.0 version.

    Here the plugin.json
    {
    "id": "nodebb-plugin-angtest",
    "name": "Test angular app within nodebb",
    "description": "An angular app to test if it works with nodebb 0.7",
    "library": "./library.js",
    "hooks": [
    { "hook": "static:app.load", "method": "init" },
    { "hook": "filter:header.build", "method": "addNavigation" }
    ],
    "staticDirs": {
    "static": "./static"
    },
    "less": [
    "static/style.less"
    ],
    "scripts": [
    "static/lib/angular/angular.js",
    "static/lib/app.js"
    ],
    "templates": "./templates"
    }

    The library.js

    "use strict";
    
    var plugin = {};
    
    function renderCustomPage(req, res, next) {
        // charger la page
        res.render('angular-page');
    }
    
    plugin.init = function(params, callback) {
        // ajouter les routes
        var app = params.router,
            middleware = params.middleware;
    
        app.get('/angular', middleware.buildHeader, renderCustomPage);
        app.get('/templates/angular.tpl', renderCustomPage);
        app.get('/api/angular', renderCustomPage);
    
        callback();
    };
    
    plugin.addNavigation = function(header, callback) {
        // ajouter le lien dans le menu de navigation principal
        header.navigation.push({
            class: '',
            route: '/angular',
            iconClass: 'fa fa-google',
            title: 'angular',
            text: 'angular'
        });
        callback(null, header);
    };
    
    module.exports = plugin;
    

    The app.js

    'use strict';
    
    var myApp = angular.module('myApp',[]);
    
    myApp.controller('myCtrl', ['$scope',function($scope) {
        $scope.firstName= "John";
        $scope.lastName= "Doe";
    }]);
    

    With this basic example I have the same behaviour. When I click on the google icon in the head menu angular module and controller are not loaded. I need to refresh the page (F5) to load the angular part.

    Thanks in advance for your help.

  • I would love to see a fix for this and maybe a barebone angular plugin to see how it all ties together? 🙂

  • Sorry, I forgot to get back to this. Can you publish your nodebb-plugin-angtest and I'll try running it first on 0.6x and then 0.7x and see if I can isolate the problem

  • hello,
    here you will find the code https://github.com/ricoud/nodebb-plugin-angtest
    Thanks in advance

  • @psychobunny did you have time to test the plugin?
    Thanks

  • any luck? @ricoud @psychobunny

  • Same with 0.7.1
    Additional info when calling directly the page (typing the address) everything works. It seems that angular isn't loaded when calling the page through menu.

  • Same behaviour with 0.8.0 😥

  • Ok I tried to use filter:scripts.get hook to load angularjs same thing
    Then I include angularjs inside the scripts object of the js.js file find in src/meta directory, same behaviour. 😞
    Can someone help to resolve this issue as I really want to include my site as a nodebb plugin.
    Thanks in advance 😄

  • Yikes. I always forget stuff I promise on community forum haha. Your best bet always is to create an issue on our github tracker.

    "Angular not working with nodebb" or something. I'm sorry for the delay

  • Don't forget to add as much information as you can 🙂


Suggested Topics