AngularJS - Templates not working

angularjs, mean-stack, restangular, route-provider, templating

Solution

You have same routes for angular and express.

.when('api/todos/:todo_id',{
    templateUrl: 'edit.html',
    controller: 'EditController'
});

and in express

app.get('/api/todos/:todo_id', function(req, res) {

Hence, there is ambiguity. You can remove the 'api' part from angular urls.

.when('/todos/:todo_id', {
     templateUrl: 'edit.html',
     controller: 'EditController'
 })

And in server, you can add a catchall route which will handle all the non-api urls. For doing that you can move your `app.get('/', function(req,res) {..})` call at the bottom after defining your api routes.

// < Define APi Routes here >

//catch all route for serving the html template
app.get('/*', function(req, res ) {
      res.sendfile('./public/index.html')
});

Also, in your app.js EditController, you forgot to initialise value of id.

var id = $routeParams.todo_id;

Problem

I am using Restangular to create a simple API using MEAN stack. Here is my code: index.html ``` <!DOCTYPE html> <html data-ng-app="scotchTodo"> <head> <!-- META --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"><!-- Optimize mobile viewport --> <title>Node/Angular Todo App</title> <!-- SCROLLS --> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"><!-- load bootstrap --> <style> html{ overflow-y:scroll; } body{ padding-top:50px; } </style> <!-- SPELLS --> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-route.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/restangular/1.4.0/restangular.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script> <script src="app.js"></script> </head> <body> <div data-ng-view> </div> </body> </html> ``` app.js ``` var scotchTodo = angular.module('scotchTodo', ['restangular','ngRoute']); //config scotchTodo.config(['$routeProvider','$locationProvider', function($routeProvider, $locationProvider) { $routeProvider .when('/',{ templateUrl: 'list.html', controller: 'ListController' }) .when('api/todos/:todo_id',{ templateUrl: 'edit.html', controller: 'EditController' }); $locationProvider.html5Mode(true); }]); //controllers scotchTodo.controller('ListController', ['$scope', 'Restangular', function($scope, Restangular) { //GET ALL var baseTodo = Restangular.all('api/todos'); baseTodo.getList().then(function(todos) { $scope.todos = todos; }); //POST -> Save new $scope.save = function() { var baseTodo = Restangular.all('api/todos'); var newTodo = {'text': $scope.text}; baseTodo.post(newTodo).then(function(todos) { $scope.todos = todos; $scope.text = ''; }); }; //DELETE $scope.delete = function(id) { var baseTodo = Restangular.one('api/todos', id); baseTodo.remove().then(function(todos) { $scope.todos = todos; }); }; }]); scotchTodo.controller('EditController', ['$scope', 'Restangular','$routeParams', function($scope, Restangular, $routeParams) { var baseTodo = Restangular.one('api/todos', id); baseTodo.getList().then(function(todo) { $scope.todo = todo[0]; window.test = "dev"; }); //PUT -> Edit $scope.update = function(id){ var baseTodo = Restangular.one('api/todos', id); baseTodo.text = "Edited"; baseTodo.put().then(function(todos) { $scope.todos = todos; }); }; }]); ``` list.html ``` <div> <div data-ng-repeat="todo in todos"> {{todo.text}}<a href="api/todos/{{todo._id}}">Edit</a><button data-ng-click="delete(todo._id)">X</button> </div> <input type="text" data-ng-model="text"/> <button data-ng-click="save()">Add</button> </div> ``` edit.html ``` <div> <input type="text" data-ng-model="text" value="{{todo.text}}" /> <button data-ng-click="update(todo._id)">Save</button> </div> ``` server.js ``` // setup ======================== var express = require('express'); var app = express(); var mongoose = require('mongoose'); var bodyParser = require('body-parser'); //configuration ================= mongoose.connect('mongodb://127.0.0.1:27017/sl', function(err, db) { if (!err) { console.log("We are connected to " + db); } }); app.use(express.static(__dirname + '/public')); app.use(bodyParser()); // application ------------------------------------------------------------- app.get('/', function(req, res) { res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end) }); //listen ======================== app.listen(8080); console.log('App started on the port 8080'); //define model ================== var Todo = mongoose.model('Todo', { text: String }); // routes ====================================================================== // api --------------------------------------------------------------------- //get one todo app.get('/api/todos/:todo_id', function(req, res) { // use mongoose to get all todos in the database Todo.find({ _id: req.params.todo_id },function(err, todos) { // if there is an error retrieving, send the error. nothing after res.send(err) will execute if (err){ res.send(err); } res.json(todos); // return all todos in JSON format }); }); // get all todos app.get('/api/todos', function(req, res) { // use mongoose to get all todos in the database Todo.find(function(err, todos) { // if there is an error retrieving, send the error. nothing after res.send(err) will execute if (err){ res.send(err); } res.json(todos); // return all todos in JSON format }); }); // create todo and send back all todos after creation app.post('/api/todos', function(req, res) { // create a todo, information comes from AJAX request from Angular Todo.create({ text: req.body.text, done: false }, function(err, todo) { if (err){ res.send(err); } // get and return all the todos after you create another Todo.find(function(err, todos) { if (err) res.send(err); res.json(todos); }); }); }); // update todo and send back all todos after creation app.put('/api/todos/:todo_id', function(req, res) { // create a todo, information comes from AJAX request from Angular Todo.update({ _id: req.params.todo_id }, { text:req.body.text }, function(err, todo) { if (err){ res.send(err); } // get and return all the todos after you create another Todo.find(function(err, todos) { if (err) res.send(err); res.json(todos); }); }); }); // delete a todo app.delete('/api/todos/:todo_id', function(req, res) { Todo.remove({ _id: req.params.todo_id }, function(err, todo) { if (err){ res.send(err); } // get and return all the todos after you create another Todo.find(function(err, todos) { if (err){ res.send(err); } res.json(todos); }); }); }); ``` The first page of my app loads perfectly fine. Here is the screenshot. But when I click on either of the edit link it is supposed to load edit.html template. But it shows a blank page with no errors in console. Here is the screenshot. I am unable to figure out what's wrong. Please help. Please ask if any other piece of code is needed. I added almost everything that I did. I know it is annoying and not recommended but I am not sure what part of my code is causing this issue. EDIT 1: My farthest guess is that the url for edit.html might not be getting resolved correctly. But I am not sure how to test that! Any help will be appriciated. EDIT 2: Directory structure SOLUTION : Courtesy @ashu The issue was this line in index.html ``` <script src="app.js"></script> ``` It should be: ``` <script src="/app.js"></script> ``` However, I am not clear why! Page was including app.js either way. It is weird.

Original source