Using Express to render an .ejs template for AngularJS and use the data inside AngularJS $scope

1.1k views Asked by At

I hope I can explain myself with this first question I post on Stack Overflow.

I am building a small test application with the MEAN stack.

The application receives variable data from Mongoose based on an Express Route I have created.

For example the url is: localhost:3000/cities/test/Paris

Based on the name of the city the response gives me the name of the city and a description. I Know how to get this data inside the .ejs template But thats not what I want. I want to use this data inside an ngRepeat.

Maybe this is not the right way but maybe you can help me figure this out.

The reason I want to do this is because I don't want a single page application but an Angular template that can be used over and over for each city and only uses the data that gets back from the mongoose find() results and not the whole cities array.

app.js :

var cityRoutes = require('./routes/cities');
app.use('/cities', cityRoutes);
app.set('views', './views'); // specify the views directory
app.set('view engine', 'ejs'); // register the template engine

./routes/cities/cities.js :

var express = require('express');
var citiesList  = require('../server/controllers/cities-controller');

var bodyParser = require('body-parser');
var urlencode = bodyParser.urlencoded({ extended: false });

var router = express.Router();

// because this file is a fallback for the route /cities inside app.js
// the route will become localhost:3000/cities/test/:name
// not to be confused by its name in this file.
router.route('/test/:name')
    .get(citiesList.viewTest)

 module.exports = router;

../server/controllers/cities-controller.js :

var City = require('../models/cities');

module.exports.viewTest = function(request, responce){
City.find({ stad: request.params.name }, function(err, results){

    if (err) return console.error(err);
        if (!results.length) {
            responce.json( "404" );
    } else {
        responce.render('angular.ejs',  { messages:results });
        // through this point everything works fine
        // the angular.ejs template gets rendered correctly
        // Now my problem is how tho get the results from the 
        // response.render inside the Angular directive 
        // so I can use the data in a $scope
    }
    });
};

../models/cities.js

var mongoose = require('mongoose');

module.exports = mongoose.model('City', {
    stad: { type: String, required: true },
    omschrijving: String
});

AngularJS directive :

// This is where I would like to use the messages result data
// so I can create a $scope that handles data that can be different
// for each url 
// so basically I am using this directive as a template

app.directive('bestelFormulier', function () {
return {
    restrict: 'E',
    templateUrl: '/partials/bestel-formulier.html',
    controller: ['$scope', '$http', '$resource', '$cookieStore',
function($scope, $http, $resource, $cookieStore){ 


    // at this point it would be nice that the $scope gets the
    // url based results. But I don't now how to do that..
    // at this point the var "Cities" gets the REST API with 
    // all the cities...

    var Cities = $resource('/cities');

        // get cities from mongodb
        Cities.query(function(results){
            $scope.cities = results;
            //console.log($scope.products);
        });

        $scope.cities = {};

    }],
    controllerAs: 'productsCtrl'
}

});

The database is stored like this :

[
    {
        stad: 'Paris',
        omschrijving: 'description Paris',
    },
    {
        stad: 'Amsterdam',
        omschrijving: 'description Amsterdam',
    }
]

I hope these files included helps explaining my issue.

Thanks in advance for helping me out

1

There are 1 answers

0
Seabass On

I figured out a way to do it...

The following changes to my code fixed my issue.

in app.js

var cityRoutes = require('./routes/cities');
app.use('/', cityRoutes);
// removed the name cities

./routes/cities/cities.js :

router.route('/cities/test/:name')

    .get(citiesList.viewTest)

// added this route to use as an API
router.route('/api/cities/test/:name')

    .get(citiesList.viewStad)

../server/controllers/cities-controller.js :

// added this callback so that a request to this url
// only responses with the data I need
module.exports.viewStad = function(request, responce){
    City.find({ stad: request.params.name }, function(err, results){

        if (err) return console.error(err);
        if (!results.length) {
            responce.json( "404" );
        } else {
            responce.json( results );
        }
    });
};

in my AngularJS app I added the $locationDirective and changed the following in my Angular directive to :

var url = $location.url();
var Cities = $resource('/api' + url);
// now when my .ejs template gets loaded the Angular part looks at
// the current url puts /api in front of it and uses it to get the
// correct resource

That is the way how I can use it in my $scope and use al the lovely Angular functionality :-)

Hope I can help other people with this... Eventually it was a simple solution and maybe there are people out there knowing beter ways to do it. For me it works now.