0

I'm totally new to modern web development and have been learning the MEAN stack from online tutorials. I'm just writing a simple todo app that allows CRUD operations. This is with the MEAN stack (Mongo database via Mongolab) and npm and bower as package managers - no scaffolding tools or cloning an existing app. This is my first time with Node and Angular.

I'm running into problems with displaying my HTML page using Angular. Here are the relevant files:

app.js for the backend (including only the relevant sections):

var express = require('express');
var path = require('path');
var app = express();
var morgan = require('morgan');
var db = require('./db');
var bodyParser = require('body-parser');

app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({'extended' : 'true'}));

require('./backend/todo_rest')(app);

module.exports = app;

todo_rest.js:

var TodoSchema = require('./todo_schema');
var path = require('path');

module.exports = function(_app) {
    _app.get('/api/todos', function(req, res) {
         TodoSchema.find({}, function(err, todos) {
            console.log('API GET; data: ' + todos);
            if(err)
                return res.status(500).send("The todos could not be retrieved from the database!");
            return res.json(todos);
        });
    });

    _app.get('*', function(req, res){
         res.sendFile(path.resolve(__dirname + '/../client/views/index.html'));
     });
};

app.js for the front end:

var app = angular.module('todosApp', []);

app.controller('todosController', function($scope, $http) {
    $scope.todos = {};

    $http({
        method: 'GET',
        url: '/api/todos'
    }).then(function (success) {
        console.log(success.data);
    }, function (error) {
        console.log('Angular GET error: ' + error.data);
    });
});

and index.html:

<!DOCTYPE html>
<html ng-app="todosApp">
<head>
    <meta charset="UTF-8">
    <title>Todos App</title>
    <script src="../../bower_components/jquery/dist/jquery.min.js"></script>
    <script src="../../bower_components/angular/angular.min.js"></script>
    <script src="../app.js"></script>     // <-- this is the frontend's app.js
</head>
<body ng-controller="todosController">
<div>
    <span>Total: {{todos.length}}</span>
    <ul ng-repeat="todo in todos">
        <li>Name: {{todo.title}}, {{todo.completed}}</li>
    </ul>
</div>
</body>
</html>

Although I do want to support full CRUD, right now I just want the HTML to display all the todos from the database. Here are the current problems:

  • When I launch the page via localhost:3000, I get the HTML but Angular elements like {{todos.length}} are displayed as is, instead of being replaced by the evaluated values. Basically, when I launch that page, I want all the todos to be displayed as a list by calling the /api/todos endpoint that I've exposed in my backend. I've checked that the console.log in the frontend's app.js isn't triggered.
  • When I launch localhost:3000/api/todos, the JSON result is displayed in the browser instead of any HTML. Do I need to use routing in Angular to display a different view for each end point in the same page?
2
  • are you getting angualr is undefined error or something like this at your console? Commented Jun 2, 2017 at 3:15
  • @Pengyy Nope, nothing like that. I actually see messages which show that the js files in the <script> lines have been retrieved. Commented Jun 2, 2017 at 3:16

2 Answers 2

1

{{todos.length}} are displayed as is, instead of being replaced by the evaluated values.

If you see this, it means your angularjs app is not bootstraped successfully. See errors at your console for further fix actions.

add app.use(express.static(__dirname)); to your app.js(nodejs) in order to serve static files.

I want all the todos to be displayed as a list by calling the /api/todos

you have to set result from $http.get to $scope.todos

$http({
  method: 'GET',
  url: '/api/todos'
}).then(function (success) {
  console.log(success.data);
  $scope.todos = success.data;      // <-------- set result to $scope.todos
}, function (error) {
  console.log('Angular GET error: ' + error.data);
});

move ng-repeat to li

<ul>
    <li ng-repeat="todo in todos">Name: {{todo.title}}, {{todo.completed}}</li>
</ul>

When I launch localhost:3000/api/todos, the JSON result is displayed in the browser instead of any HTML. Do I need to use routing in Angular to display a different view for each end point in the same page?

You mean access localhost:3000/api/todos at your browser directly? you don't have to this, $http.get will do the work and retrieve the result. And currently you don't need routing since you just have one simple page.

Sign up to request clarification or add additional context in comments.

8 Comments

I tried this, still the same result. On the console, I see several GET statements for files listed in index.html's <script> tags. The console.log before $scope.todos isn't triggered either.
@Cygnus have you checked @Mukesh Sharma's answer? maybe your app.js isn't loaded to browser at all. you can add console.log() before $scope.todos={} to confirm.
@Cygnus also make sure there isn't 404 errors at network tag.
yeah, that console.log isn't executed either. I've added a comment to Mukesh's answer.
No luck :( I tried express.static(__dirname + '/client') as well as express.static('client') in addition to just __dirname as the argument. Does it have to be the path of app.js or index.html?
|
1

You have not configured your Express server to serve static content, that's why your browser is not able to load app.js. Hence, angular app is not initialized.

Use express.static to load static content.

3 Comments

Hmm, based on @Pengyy's comment above, this seems to be the case. Could you add an example of how to use express.static? I've added this - app.use('/', express.static(path.join(__dirname, '/client/views'))); - but it doesn't help. Do I have to provide a REST path for it?
can you share your directory structure?
I was able to get it to work, express.static was needed as you mentioned. Thanks a lot!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.