2

I'm relatively new to AngularJS, and I decided to build a basic blog app to get familiar with MongoDB and using $http requests.

However, I'm having a bit of trouble using my Angular service to post the data a user fills out in a form on $scope to my MongoDB database.

Originally, I put the $http requests in my controller. This works for me:

mainCtrl.js

  $scope.addPost = function() {
  $http.post('/api/blogs', $scope.formData)
  .success(function(data) {
    $scope.formData = {};
    $location.path('blogs');
    console.log(data, 'Blog created.');
  })     
  .error(function(data) {
    console.log('Error: ' + data);
  })  
};

But this is done through my controller, and I understand this is not best practice, so I am attempting to put this functionality in an Angular service.

Here is the relevant parts of code that make up this part of the app including HTML views:

server.js

//Dependencies.
var express = require('express');
var router = express.Router(); 
var bodyParser = require('body-parser');
var cors = require('cors');
var mongoose = require('mongoose');
var mongojs = require('mongojs');
var http = require('http');
var path = require('path');
var fs = require('fs');
var dotenv = require('dotenv');

var port = 9001;
var mongoUri = 'mongodb://localhost:27017/blog-app';

var app = express();

app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json());

//Blog Data & Data Storage.
-----------------------------

var Schema = mongoose.Schema;

var blogSchema = new Schema({
   title : {type: String, min: 8, max: 50, required: true},
   body : {type: String, required: true},
   author : {type: String, min: 3, max: 40, required: true},
   pubdate : {type: Date, default: Date.now}
});

var Blog = mongoose.model('Blog', blogSchema);

//Routes.
----------

// GET BLOGS!

app.get('/api/blogs', function(req, res) {
    Blog.find(function (err, blogs) {
        if (err)
            res.send(err);
        res.json(blogs);
    });
});

// POST BLOG!

app.post('/api/blogs', function(req, res) {
    Blog.create({
        title: req.body.title,
        body: req.body.body,
        author: req.body.author,
        date: req.body.date
    }, function(err, blog) {
        if (err)
            res.send(err);
        Blog.find(function(err, blogs) {
            if (err)
                res.send(err);
            res.json(blogs);
        });
    });
});

mainCtrl.js

var app = angular.module("blog-app");

app.controller('MainController', ['mainService', '$scope', '$http',  '$location', '$stateParams', '$state', function(mainService, $scope, $http, $location, $stateParams, $state) { 

  $scope.formData = {};

  $scope.blog = [];

  function getBlogs() {
      mainService.getPosts().then(function(data) {
        $scope.blog = data;
        console.log(data, "The blogs.");
      });
  }

  getBlogs();

  $scope.readPost = function(id) {
      mainService.readPost(id).then(function(data) {
        $scope.readblog = data;
        console.log(data, "This is the blog you selected.")
      });
  };

  $scope.addPost = function(formData) {
      mainService.addPost(formData).then(function() {
        $scope.formData = {};
        $location.path('blogs');
        console.log(data, 'Blog created.');     
      }); 
  };

}]); //End Controller.

mainService.js

var app = angular.module("blog-app");

app.service('mainService', function($http, $q) {

    var blog = [];
    var readblog = {};
    var formData = {};

    this.getPosts = function() {
        return $http.get('/api/blogs').then(function(response){
            blog = response.data;
            return blog;
        });
    }

    this.readPost = function(id) {
        return $http.get('/api/blogs/' + id).then(function(response) {
            readblog = response.data;
            return readblog;
      });
    };

    this.addPost = function(formData) {
        $http.post('/api/blogs', formData);
    };

  });

newblog.html

<div class="newblog">
    <a ui-sref="blogs"><i class="fa fa-close fa-2x exit"></i></a>
    <div class="form">
          <form>
                <i class="fa fa-pencil-square-o fa-5x"></i><br>

                <input class="blogtitle" type="text" ng- model="formData.title" placeholder="Blog Title" required /><br>

                <textarea ng-model="formData.body" rows="15" placeholder="Write the body of your blog here." required></textarea><br>

                <label for="">by:</label><br>
                <input class="blogauthor" type="text" ng-model="formData.author" placeholder="Author Name" required /><br><br>

                <button type="submit" ng- click="addPost()">Submit</button> 
          </form>
    </div>
</div>

So...

...to be clear, I want to be able to click on the button in newblog.html with the addPost() function, and have it put the form data in my database. What is not clear to me is how to reference the data that the user inputs in the $scope, within my service, so I can actually post it to the database, or if this is even possible. Was easy enough to do this in the controller(shown in example at very of post), but I would like to do it in the service.

What I have tried:

Service Function

this.addPost = function(formData) {
    $http.post('/api/blogs', formData).then(function(response) {
        blog.push(response.data);
        return blog;
    })
};

and then...

Controller Function

$scope.addPost = function(data) {
  mainService.addPost(data).then(function(data) {
    $scope.blog.push(data);
    console.log(data, 'Blog created.');     
  }); 
};

I can't remember what else I had tried, but ultimately, it was to no avail. I'm guessing that it might be something very simple I possibly overlooked while on my Google search quest. Any help would be appreciated, will also clarify on anything that didn't quite make sense. Will continue to work on it and fix/answer question if I find anything.

1
  • Unrelated to the question, but you should definitely be careful with your if (err) and following statements in your api routes. You will still execute the success in the failure cases, which will (I believe) cause express to have a fit. I would suggest using something like return res.send(err) so you can be sure the following lines are never executed. Commented May 25, 2016 at 22:49

1 Answer 1

2

Your controller function should be:

$scope.addPost = function() {
    mainService.addPost($scope.formData).then(function() {
        $scope.formData = {};
        $location.path('blogs');
        console.log(data, 'Blog created.');     
    }); 
};

You're not passing anything from the view so essentially you were calling mainService.addPost with a null value for formData.

Update

I missed this when first reading your question, but the service method needs to return the promise:

this.addPost = function(formData) {
    return $http.post('/api/blogs', formData);
};
Sign up to request clarification or add additional context in comments.

5 Comments

I didn't think to put $scope.formData there... Thank you. But now I'm getting this error: 'angular.js:13550 TypeError: Cannot read property 'then' of undefined at Scope.$scope.addPost (mainCtrl.js:26)'
@PrincetonCollins Just updated my answer. I missed that you were not returning the promise from your service method for addPost.
Thank you, Lex. It works now. It posts to the database! Just one last thing... My ng-repeat is not updating with the new post, any ideas off the top of your head on what might be the issue with that? It will only update after refreshing the page.
At this point the exact code you may be using is lost in your original question and rather than continually expanding this one I think starting a new question and showing the relevant bits would be the best approach.
Noted. Thank you very much for the help!

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.