2

I'm trying to get my ng-repeat to update after I create a new item in my Mongo DB. From what I've researched, this should happen automatically. I know that for every view a new $scope is made for that view, and to share data between all of your $scopes, you would use a service, which I beleive is what I'm doing... but maybe not.

Any help is appreciated, here is my code:

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>

Here is the form for the new blog a user creates.

main.html

<div class="wrapper"> 
    <div class="blog-container" ng-repeat="data in blog | orderBy: '-pubdate'" ng-click="readPost(data._id)" ui-sref=".readblog">  
        <p><i class="fa fa-sticky-note"></i>&nbsp;<b>{{ data.title }}</b></p>
        <p>by {{ data.author }}</p> 
        <p>{{ data.pubdate | date }}</p>
        <br>
        <div>
            <p>{{ data.body }}</p>
        </div>
        <br><br>
    <div class="button-box">
        <div id="deletePost" ng-click="deletePost(data._id)"><i class="fa fa-trash-o fa-2x"></i></div>
    </div>
</div>

Here is the view with the ng-repeat.

Below is my controller and service.

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 = mainService.blog;

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

getBlogs();

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

}]); //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) {
        return $http.post('/api/blogs', formData).then(function(response) {
            blog = response.data;
        })
    };

});

And my server.js...

    //Dependencies.
var express = require('express');
var router = express.Router();
// var sendgrid  = require('sendgrid')(process.env.U, process.env.PASSWORD)
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);
    });
});

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);
        });
    });
});

mongoose.connect(mongoUri);
mongoose.connection.once('open', function() {
  console.log("Hey there! We are now connected to MongoDB at: ", mongoUri);
});

app.listen(port, function() {
  console.log('Magic! Listening on port: ', port);
});

I've been working on this going on two days, any help is much appreciated!

6
  • first you don't need to declare blog, readblog and formData on top of your service. Just return response.data from the then callbacks Commented May 27, 2016 at 15:51
  • why are you doing a $location.path('blogs');? Commented May 27, 2016 at 15:55
  • @jack.the.ripper I have a default ui-view called blogs, which returns the user to a home view after he submits the blog. Commented May 27, 2016 at 16:07
  • In your main.html beneath the <div class="wrapper">...</div>, if you display the blog data: {{ blog }}, can you see the newly added blog item? Commented Jul 14, 2016 at 12:27
  • Sorry I haven't visited this issue in awhile. @avn Yes I can see he data when I put in {{ blog }}. Commented Jul 21, 2016 at 15:48

3 Answers 3

1

One issue could be that you are not waiting for a new post to be posted before retrieving the blogs.

try to move the getBlogs() call inside the callback of your addPost call:

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

    getBlogs();   
  }); 
};
Sign up to request clarification or add additional context in comments.

7 Comments

I had it there to begin with like your example, and moved it outside method call. But it didn't seem to effect a change.
@PrincetonCollins can you log $scope.blog for instance after 10s in a timeout and check if this is up to date. So we will know if that's a problem of rendering or logic.
This is what I got with the log on a setTimeout: VM2848:1 Uncaught ReferenceError: data is not defined
You need to use $timeout. Using setTimeout will call the function outside the context of your controller and none of the variables will be available.
You need to write the setTimeout in the callback as well, just under getBlogs in my answer for instance. @Lex the methods are available and we can totally inspect the scope. However updating what is in the scope would not be reflected in the DOM until a next digest cycle. But here we do read only.
|
0

In your addPost() handler, you either add the new post to the blog array via push() or reload the blogs by calling getBlogs(), any of these calls should be after the promise is completed.

First Approach: Using formData

  $scope.addPost = function(data) {
      mainService.addPost($scope.formData).then(function(data) {

        var newItem = jQuery.extend({}, $scope.formData); // copy the new inserted item from formData
        // newItem._id = data; // uncomment this to set the id
        $scope.blog.push(newItem); // this should be enough to update the repeater
        $scope.formData = {}; // clear formData
      }); 

  };

Second Approach: Reloading all the posts

  $scope.addPost = function(data) {
      mainService.addPost($scope.formData).then(function(data) {
        getBlogs();
        $scope.formData = {};
      }); 

  };

8 Comments

So it works now, but it doesn't dynamically change the ng-repeat. I have to refresh the page for it to show up in the ng-repeat. What needs to be done so that it will show the update to the ng-repeat without having to refresh the page?
Try calling $scope.$digest(); and see if it makes any difference, answer updated.
Also, what is the return value for the addPost() promise? what do yo see in console.log(data, 'Blog created.');? you should return the new blog post.
It is not returning the new blog post. Currently says undefined "Blog created." Would a return on the .then callback in the addPost method in my service fix that?
Tried $scope.$digest(). Says that $digest is already in progress.
|
0

So, this might be a hacky way to do it but it performs exactly how I want it to. In my controller, in the addPost function, I added

$state.go('blogs).then(function() {
  $state.reload('blogs');
});

...so it looks like this...

$scope.addPost = function(newBlog) {
  mainService.addPost(newBlog).then(function(data) {
    $scope.blog = data;
    console.log(data, 'Blog created.');
    $state.go('blogs').then(function() {
      $state.reload('blogs');
    })
  }); 
};

I'm basically just going back to the scope where the ng-repeat is and then reloading it. It works great. But if there are any other alternatives, which I'm sure there are, I would love and greatly appreciate it if anyone would share theirs.

And would also appreciate it if anyone could enlighten me to possible bugs or future bugs this method might create. So far, I haven't seen any, but I'm still fairly green with AngularJS, so any ideas/comments are welcome.

Comments

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.