Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refresh specific page with Angular, Express and Jade (using html5mode)

I'm trying to refresh a page and execute client route to open a template inside ng-view

Index.jade

extends layouts/default

block content
  section(data-ng-view)
  script(type="text/javascript").
    window.user = !{user};

default.jade

doctype html
html(lang='en', xmlns='http://www.w3.org/1999/xhtml', xmlns:fb='https://www.facebook.com/2008/fbml', itemscope='itemscope', itemtype='http://schema.org/Product')
  include ../includes/head
body
  div(data-ng-include="'static/modules/core/views/core.header.view.html'", data-role="navigation")
  div(data-ng-include="'static/modules/core/views/core.index.view.html'", data-role="navigation")
  div(data-ng-include="'static/modules/core/views/core.menu.view.html'", data-role="navigation")
  div(data-ng-include="'static/modules/core/views/core.footer.view.html'", data-role="navigation")
  include ../includes/foot

Server route

// Camera Routes
    app.get('/api/cameras', cameras.all);
    app.post('/api/cameras', auth.requiresLogin, cameras.create);
    app.get('/api/cameras/:cameraId', cameras.show);
    app.put('/api/cameras/:cameraId', auth.requiresLogin, auth.article.hasAuthorization, cameras.update);
    app.del('/api/cameras/:cameraId', auth.requiresLogin, auth.article.hasAuthorization, cameras.destroy);
    app.param('cameraId', cameras.camera);

    // Home route
    app.get('/', index.render);

express.js

/**
 * Module dependencies.
 */
var express = require('express');
var flash = require('connect-flash');
var helpers = require('view-helpers');
var config = require('./config');

module.exports = function(app, passport) {

    console.log('Initializing Express');

    app.set('showStackError', true);    

    //Prettify HTML
    app.locals.pretty = true;

    //Should be placed before express.static
    app.use(express.compress({
        filter: function(req, res) {
            return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
        },
        level: 9
    }));

    //Setting the fav icon and static folder
    app.use(express.favicon());
    app.use('/static',express.static(config.root + '/public'));

    //Don't use logger for test env
    if (process.env.NODE_ENV !== 'test') {
        app.use(express.logger('dev'));
    }

    //Set views path, template engine and default layout
    app.set('views', config.root + '/app/views');
    app.set('view engine', 'jade');

    //Enable jsonp
    app.enable("jsonp callback");

    app.configure(function() {
        //cookieParser should be above session
        app.use(express.cookieParser());

        // request body parsing middleware should be above methodOverride
        app.use(express.urlencoded());
        app.use(express.json());
        app.use(express.methodOverride());

        //express/mongo session storage
        app.use(express.session({ secret: '$uper$ecret$e$$ionKey'}));

        //connect flash for flash messages
        app.use(flash());

        //dynamic helpers
        app.use(helpers(config.app.name));

        //use passport session
        app.use(passport.initialize());
        app.use(passport.session());

        //routes should be at the last
        app.use(app.router);
        //Assume "not found" in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.

        app.all('/*', function(req, res, next) {
            res.render('index.jade', {'root': 'app/views/'});
        });

        app.use(function(err, req, res, next) {
            //Treat as 404
            if (~err.message.indexOf('not found')) return next();

            //Log it
            console.error(err.stack);

            //Error page
            res.status(500).render('500', {
                error: err.stack
            });
        });

        //Assume 404 since no middleware responded
        app.use(function(req, res, next) {
            res.status(404).render('404', {
                url: req.originalUrl,
                error: 'Not found'
            });
        });
    });
};

HTML5 ENABLE

//Setting HTML5 Location Mode
angular.module('mean').config(['$locationProvider',
    function($locationProvider) {
        $locationProvider.html5Mode(true);
        $locationProvider.hashPrefix("!");
    }
]);

Client router here, I want to show this template inside ng-view

angular.module('mean').config(['$stateProvider',
function ($stateProvider) {
    $stateProvider.
        state('viewCamera', {
            url: "/cameras/:cameraId",
            templateUrl: 'static/modules/cameras/views/cameras.camera.view.html'
        });
}

]);

Index view with ui-view tag

<section data-ng-controller="MapController" data-ng-init="find()">
    <div ui-view>
    </div>
    <div class="map-content" ng-class="{'map-content-left': cameraOpen != undefined}">
        <leaflet defaults="defaults" center="center" class="map"></leaflet>
    </div>
</section>

My html head

head
  base(href='/')

What I want? When insert this url manually: localhost:3000/cameras/12, call server and get index to call client route and open the template inside ng-view

What's the problem? When I insert this url in browser, I get the index.jade with download mode

What I already tried?

Change the server route to this (apparently this return rendered index)

  // Home route
    app.get('*', index.render);

But the client route is never called

What's wrong?

EDIT 1

My dependencies version

"angular": "latest",
"angular-resource": "latest",
"angular-cookies": "latest",
"angular-mocks": "latest",
"angular-ui-utils": "0.0.4",
"angular-translate": "~2.5.2",
"angular-translate-loader-static-files": "~2.5.2",
"ngDialog": "~0.3.7",
"angular-leaflet-directive": "~0.7.10",
"leaflet.markercluster": "~0.4.0",
"angular-loading-bar": "~0.6.0",
"angular-ui-router": "~0.2.13"

I'm using Mean-Stack-Relacional from here: https://github.com/jpotts18/mean-stack-relational

EDIT 2

I was using angular-route, so I changed to ui-router to see if the problem was solved.

EDIT 3

Client Route core

//Setting up route
angular.module('mean').config(['$stateProvider', '$urlRouterProvider',
    function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/");

        $stateProvider.
            state('login', {
                url: '/login',
                template: '',
                controller: 'SessionController',
                data: {
                    method: "login"
                }
            })
            .state('signin', {
                url: '/signin',
                template: '',
                controller: 'SessionController',
                data: {
                    method: "signin"
                }
            })
            .state('home', {
                url: '/',
                resolve: {
                    resetMap: function ($q, $location, $rootScope) {
                        $rootScope.$emit('rootScope:emit', '');
                    }
                }
            });
    }
]);
like image 505
Leandro Hoffmann Avatar asked Jan 15 '15 19:01

Leandro Hoffmann


2 Answers

@Scymex help me to find this issue:

For anybody who might be using Jade, here's a quick gotcha: div(ui-view) compiles to <div ui-view="ui-view"></div>. What you need is div(ui-view="").

So, you can have ui-view inside ng-include, but need do this trick

Font: https://github.com/angular-ui/ui-router/issues/679

like image 52
Leandro Hoffmann Avatar answered Oct 16 '22 16:10

Leandro Hoffmann


You're using HTML5 routes with a hashbang fallback. What that means is you want to set your server up so that requests to /cameras/12 redirect to /#!/cameras/12. The server will then render your Angular application, which will detect that it wants to go to your viewCamera state and will rewrite the url on the client.

You can accomplish this by simply adding the following middleware to your express app:

app.use(function (req, res, next) {
    res.set('Location', '/#!' + req.path)
       .status(301)
       .send();
});
like image 29
Hamms Avatar answered Oct 16 '22 18:10

Hamms