I am completely new to programming and at this stage of developing my website I need to set up a simple long polling request to get the newest messages from the db and then show them to the client.
I created a messaging system last day and now it saves the messages with all needed relations between messages and users...
Here is what I did :
var express = require('express');
var router = express.Router();
var Conversation = require('../models/conversation');
var Promise = require('promise');
// Get Homepage
router.get('/', function(req, res){
res.render('index');
});
var messages = [];
router.get('/inbox', function(req, res){
var promise = new Promise(function (resolve, reject) {
req.user.conversations.forEach(function(id){
Conversation.getConversationById(id, function(err, conv){
if (conv){
messages.push(conv);
if(messages.length == req.user.conversations.length){
resolve(messages);
messages = [];
}
} else {
console.log(err);
}
});
});
}).then(function(object){
res.render('inbox', {convers: object});
}).catch(function(err){
console.log(err);
});
});
// Add new messages to messagesArray -> mesgArray to display them
var mesgArray = [];
var userIdFor = "";
router.post('/messages', function(req, res){
var convId = req.body.conversationId;
userIdFor = req.user.id;
var promise = new Promise(function(resolve, reject){
Conversation.getConversationById(convId, function(err, conver){
if (err){
console.log(err);
} else {
conver.messages.forEach(function(messa){
mesgArray.push({msg: messa.msg, owner: messa.msgOwner, ownerName: messa.msgOwnerName});
if(mesgArray.length == conver.messages.length){
resolve(mesgArray);
}
});
}
});
}).then(function(object){
res.send({allMessages: object, userId: userIdFor});
mesgArray = [];
userIdFor = "";
}).catch(function(err){
console.log(err);
});
});
// Save posted message to existent conversation
router.post('/saveMsg', function(req, res){
var conversationId = req.body.conversationId;
var messageToSave = req.body.message;
console.log(messageToSave);
console.log(conversationId);
Conversation.getConversationById(conversationId, function(err, conversation){
if (err){
console.log(err);
} else {
Conversation.getConversationById(conversationId, function(err, conversation){
if(err){
console.log(err)
} else {
conversation.messages.push({
msg: messageToSave,
msgOwner: req.user.id,
msgOwnerName: req.user.firstName
});
conversation.save(function(err){
if(err){
console.log(err);
}
})
}
});
}
});
});
module.exports = router;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<!-- REPLAY MESSAGE BOX -->
<div class="contact-form-container hidden-mode">
<div class="row hide-contact text-right">
<img src="/images/close.png">
</div>
<form>
<div class="inbox-all-messages-container">
<div class="row inbox-all-messages">
<!-- Here will be all the messages -->
</div>
<div class="row text-center inbox-send-input">
<div class="col-lg-11 col-md-11 col-sm-11">
<textarea class="inbox-message-response-txt" placeholder="Type your message here"></textarea>
</div>
<div class="col-lg-1 col-md-1 col-sm-1 text-center inbox-message-send-btn">
<p class="inbox-message-send-msg-btn">Send</p>
</div>
</div>
</div>
</form>
</div>
<script>
$(document).ready(function(){
var convId = "";
$('.inbox-messager').on('click', function(){
$('.inbox-all-messages').empty();
var conversationId = this.getAttribute("data-conv-id");
convId = conversationId;
$.ajax({
url: '/messages',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({conversationId: conversationId}),
success: function(response){
response.allMessages.forEach(function(message){
if(message.owner == response.userId){
$('.inbox-all-messages').append(
'<div class="row inbox-message-structure-meNot">'+
'<div class="row inbox-message-header">'+
'<div class="inbox-message-ava col-lg-1 col-md-1 col-sm-1">'+
'<img src="/images/avatar.jpg" class="inbox-message-header-ava-img">'+
'</div>'+
'<div class="inbox-message-header-senderName col-lg-3 col-md-3 col-sm-3">'+
'<p>' + message.ownerName + '</p>'+
'</div>'+
'<div class="col-lg-3 col-lg-offset-5 col-md-3 col-md-offset-5 col-sm-3 col-sm-offset-5 inbox-message-header-sentTime text-right">'+
'<p>24/05/2016</p>'+
'</div>'+
'</div>'+
'<div class="row inbox-message-body">'+
'<div class="col-lg-9 col-lg-offset-1 col-md-9 col-md-offset-1 col-sm-9 col-sm-offset-1 text-left">'+
'<p>' + message.msg + '</p>'+
'</div>'+
'</div>'+
'</div>'
);
} else {
$('.inbox-all-messages').append(
'<div class="row inbox-message-structure-me">'+
'<div class="row inbox-message-header">'+
'<div class="inbox-message-ava col-lg-1 col-md-1 col-sm-1">'+
'<img src="/images/client.jpg" class="inbox-message-header-ava-img">'+
'</div>'+
'<div class="inbox-message-header-senderName col-lg-3 col-md-3 col-sm-3">'+
'<p>' + message.ownerName + '</p>'+
'</div>'+
'<div class="col-lg-3 col-lg-offset-5 col-md-3 col-md-offset-5 col-sm-3 col-sm-offset-5 inbox-message-header-sentTime text-right">'+
'<p>24/05/2016</p>'+
'</div>'+
'</div>'+
'<div class="row inbox-message-body">'+
'<div class="col-lg-9 col-lg-offset-1 col-md-9 col-md-offset-1 col-sm-9 col-sm-offset-1 text-left tester">'+
'<p>' + message.msg + '</p>'+
'</div>'+
'</div>'+
'</div>'
);
}
});
$('.inbox-all-messages').append('<div id="bottom"></div>');
$('.inbox-all-messages').scrollTo('#bottom', 100, "max");
}
});
$('.contact-form-container').removeClass('hidden-mode');
$('.messenger-contaner').addClass('stop-scroll');
});
$('.hide-contact').on('click', function(){
$('.contact-form-container').addClass('hidden-mode');
$('.messenger-contaner').removeClass('stop-scroll');
});
$('.inbox-message-send-msg-btn').on('click', function(){
var messageToSend = $('.inbox-message-response-txt').val();
$.ajax({
url: '/saveMsg',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({message: messageToSend, conversationId: convId}),
success: function(response){
alert('le message a bien ete enregistree');
}
});
});
})
</script>
Now I can send messages and store them in my mongoDB but I need to refresh the page to get the new messages... So I am trying to set up a long polling request but can't find a solution because each time I set a loop in my jQuery code it breaks the whole page and it can't open a conversation no more... If someone can help me to improve my code and set up a simple no technology to get the message without refreshing the page it would be so wonderful!
Sorry for my bad English! And thank you a lot for geing there for us!
If you are completely new to programming as you said, then instead of trying to create the functionality from scratch that you have trouble with, maybe using a working solution would be a better idea.
You can use Socket.io for that sort of thing. It uses long polling and tries to upgrade to WebSocket if it's supported. It's very simple to use. Here is an entire working example of a server that sends requests to the client:
var path = require('path');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'si.html'));
});
io.on('connection', s => {
for (var t = 0; t < 3; t++)
setTimeout(() => s.emit('message', 'message from server'), 1000*t);
});
http.listen(3002, () => console.error('listening on http://localhost:3002/'));
And here is the entire JavaScript code on the client:
var l = document.getElementById('l');
var log = function (m) {
var i = document.createElement('li');
i.innerText = new Date().toISOString()+' '+m;
l.appendChild(i);
}
log('opening socket.io connection');
var s = io();
s.on('connect_error', function (m) { log("error"); });
s.on('connect', function (m) { log("socket.io connection open"); });
s.on('message', function (m) { log(m); });
For more examples and better explanation see the project on GitHub which I created to demonstrate the usage of sending messages to the client.
See also other related questions for more details:
Differences between socket.io and websockets
socket.io no communication between server and client
why web socket behave differently on nodejs ?
getting an error when trying to use socket.io
How to use Socket.io combined with Express.JS
Related
I wrote the file upload codes with Ajax and they work fine, but I could not write the percentage of file upload progress. I want to use a progress bar for the percentage of progress. Please write a sample of my code with the progress bar. Thanks
I wrote the file upload codes with Ajax and they work fine, but I could not write the percentage of file upload progress. I want to use a progress bar for the percentage of progress. Please write a sample of my code with the progress bar. Thanks
<td class="d-flex justify-content-around">
<div>
<label asp-for="mostanadPath" class="btn btn-outline-info">
انتخاب تصویر
<span class="oi oi-file h5 text-dark"></span>
</label>
<span class="text-center mt-2" id="spnImageCartMlie" style="color: black;font-size: 12px"></span>
</div>
<div>
<input type="button" onclick="UploadImage()" value="آپلود فایل" class="btn btn-outline-danger" id="btnUpLoad" />
<div id="divmessage" class="text-center hidden m-2"></div>
<input class="d-none" value="#ViewBag.proID" name="id" />
</div>
<input id="newCartMlieImagePathName" name="newCartMlieImagePathName" hidden />
<input id="mostanadPath" asp-for="mostanadPath" type="file" class="d-none">
<div class="mt-5 col-6">
<div class="progress">
<div class="progress-bar progress-bar-success progress-bar-striped
active" role="progressbar"
aria-valuemin="0" aria-valuemax="100" style="width:0%">0%</div>
</div>
</div>
</td>
<script>
$("#mostanadPath").change(function () {
var filename = this.files[0].name;
$("#spnImageCartMlie").html(filename);
});
</script>
<script>
var UploadImage = function () {
var data = new FormData;
var file = $("#mostanadPath").get(0);
var files = file.files;
//کنترل سایز فایل
if (files[0].size >= 5120000) {
$("#spnImageCartMlie").removeClass('hidden');
$("#spnImageCartMlie").text('حجم فایل بیش از 500 کیلوبایت است');
$("#spnImageCartMlie").css("color", "red");
return false;
}
for (var i = 0; i < files.length; i++) {
data.append('filearray', files[i]);
data.append('filesize', files[i].size);
}
data.append('path', "img\\mostandat\\");
$.ajax({
xhr: function () {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
percentComplete = parseInt(percentComplete * 100);
$('.progress-bar').width(percentComplete + '%');
$('.progress-bar').html(percentComplete + '%');
}
}, false);
return xhr;
},
url: '#Url.Action("UploadImageFile", "Project")',
type: "POST",
data: data,
contentType: false,
processData: false }).done(function (result) {
if (result.status == "success") {
toastr.success('فایل با موفقیت آپلود شد', {
timeOut: 2000,
closeButton: true,
});
$("#newCartMlieImagePathName").val(result.imagename);
}
}).fail(function (result) {
if (result.status != "success") {
toastr.warning('در حین آپلود مشکلی بوجود آمد', {
timeOut: 2000,
closeButton: true,
});
}
});
}
</script>
public IActionResult UploadImageFile(IEnumerable<IFormFile> filearray, String path)
{
String fileName = _uploadFiles.UploadFilesFunc(filearray, path);
return Json(new { status = "success", imagename = fileName });
}
You can use this JQuery code in your <script>:
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
percentComplete = parseInt(percentComplete * 100);
$('.progress-bar').width(percentComplete+'%');
$('.progress-bar').html(percentComplete+'%');
}
}, false);
return xhr;
},
url: yoururl,
type: "POST",
data: data,
contentType: false,
processData: false
success: function(result) {
console.log(result);
}
});
and Add this code in your page
<div class="progress">
<div class="progress-bar progress-bar-success progress-bar-striped
active" role="progressbar"
aria-valuemin="0" aria-valuemax="100" style="width:0%">0%</div>
</div>
then you can see the progress bar when you upload file.
===============================================
If you want only one button,you can use this code:
<input type="file" id="files" />
<script>
$("#files").change(function () {
$.ajax({
//........
});
})
</script>
=================================================
I just add the code I gave you above to ajax
<div class="container mt-4 col-2">
<table class="table table-bordered">
<tbody class="text-center">
<tr>
<td>
<label asp-for="mostanadPath" class="btn btn-outline-info">
Image selection
<span class="oi oi-file h5 text-dark"></span>
</label>
</td>
</tr >
<tr>
<td>
<span class="text-center" id="spnImageCartMlie" style="color: black;font-size: 12px"></span>
<input id="newCartMlieImagePathName" name="newCartMlieImagePathName" hidden />
</td>
</tr>
<tr>
<td>
<input type="button" onclick="UploadImage()" value="Upload and display the image" class="btn btn-outline-danger" id="btnUpLoad" />
</td>
</tr>
<tr>
<td>
<div id="divmessage" class="text-center hidden"></div>
</td>
</tr>
</tbody>
</table>
<input asp-for="mostanadPath" type="file" class="d-none" >
</div>
<div class="progress">
<div class="progress-bar progress-bar-success progress-bar-striped
active" role="progressbar"
aria-valuemin="0" aria-valuemax="100" style="width:0%">0%</div>
</div>
#section Scripts {
<script>
$("#mostanadPath").change(function () {
var filename = this.files[0].name;
$("#spnImageCartMlie").html(filename);
});
</script>
<script>
var UploadImage = function () {
var data = new FormData;
var file = $("#mostanadPath").get(0);
var files = file.files;
//File size control
if (files[0].size >= 512000) {
$("#spnImageCartMlie").removeClass('hidden');
$("#spnImageCartMlie").text('The file size is more than 500 KB');
$("#spnImageCartMlie").css("color", "red");
return false;
}
for (var i = 0; i < files.length; i++) {
data.append('filearray', files[i]);
data.append('filesize', files[i].size);
}
data.append('path', "img\\mostandat\\");
$.ajax({
//add here......
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
percentComplete = parseInt(percentComplete * 100);
$('.progress-bar').width(percentComplete+'%');
$('.progress-bar').html(percentComplete+'%');
}
}, false);
return xhr;
},
type: "post",
url: '/Home/UploadImageFile',
data: data,
contentType: false,
processData: false
}).done(function (result) {
if (result.status == "success") {
$("#divmessage").text("Upload was successful.");
$("#divmessage").css("color", "green");
$("#divmessage").removeClass("hidden");
$("#newCartMlieImagePathName").val(result.imagename);
}
}).fail(function (result) {
if (result.status != "success") {
$("#divmessage").css("color", "red");
$("#divmessage").removeClass("hidden");
$("#divmessage").text("There was a problem uploading.");
}
});
}
</script>
}
please see my code that I'am not sure what I'm doing wrong? when the search input is empty then it shows all data from db how to fix, vue lenght doesnt work??
var app = new Vue({
el: '#newsearch',
data: {
qry: '',
bUrl: 'http://localhost:8000',
results: [],
},
methods: {
autoComplete(){
this.results=[];
axios.post(this.bUrl + '/search', {
qry: this.qry
})
.then ( (response) => {
app.results = response.data;
})
}
}
});
html
<p class="control is-expanded has-icons-right">
<input class="input" v-model="qry" v-on:Keyup="autoComplete" type="text" placeholder=">.<"/>
</p>
<p class="control">
<a class="button is-dark">
<i class="fa fa-search"></i>
</a>
</p>
<div v-show="results.length">
<p v-for="result in results">
#{{result.anime_name}}
</p>
</div>
</div>
Send axios request only when qry isn't empty.
methods: {
autoComplete(){
this.results=[];
if(this.qry !== '') {
axios
.post(this.bUrl + '/search', {
qry: this.qry
})
.then ( (response) => {
app.results = response.data;
})
}
}
}
I am using code as follow
server.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
users = [];
connections = [];
server.listen(process.env.PORT || 3000);
console.log('Server Running...');
app.get('/',function (req, res)
{
res.sendFile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket){
connections.push(socket);
console.log('Connected to %s sockets connection', connections.length);
// Disconnect
socket.on('disconnect', function (data){
if(!socket.username) return;
users.splice(users.indexOf(socket.username), 1);
updateUsernames();
connections.splice(connections.indexOf(socket), 1);
console.log('Disconnected: %s socket connected', connections.length);
});
//Send Message
socket.on('send message', function(data){
console.log(data);
io.sockets.emit('new message', {msg: data});
});
// New user
socket.on('new user', function(data, callback){
callback(true);
socket.username = data;
console.log(socket.username);
users.push(socket.username);
updateUsernames();
});
function updateUsernames(){
io.sockets.emit('get users', users);
}
});
index.html -> Client
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://immodernafrican.move.pk:3000/socket.io/socket.io.js"></script>
<style type="text/css">
body{
margin-top: 30px;
}
#messageArea{
display: none;
}
</style>
</head>
<body>
<div class="container">
<div id="userFormArea" class="row">
<div class="col-md-12">
<form id="userForm">
<div class="form-group">
<label>Enter Username</label>
<input class="form-control" id="username"/>
<br/>
<input type="submit" class="btn btn-primary " value="Login">
</div>
</form>
</div>
</div>
<div class="row" id="messageArea">
<div class="col-md-4">
<div class="well">
<h3>Online Users</h3>
<ul class="list-group" id="users"></ul>
</div>
</div>
<div class="col-md-8">
<div class="chat" id="chat"></div>
<form id="messageForm">
<div class="form-group">
<label>Enter Message</label>
<textarea class="form-control" id="message"></textarea>
<br/>
<input type="submit" class="btn btn-primary " value="Submit">
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(function(){
var socket = io.connect('http://immodernafrican.move.pk:3000');
var $messageForm = $('#messageForm');
var $message = $('#message');
var $chat = $('#chat');
var $messageArea = $('#messageArea');
var $userFormArea = $('#userFormArea');
var $userForm = $('#userForm');
var $users = $('#users');
var $username = $('#username');
$messageForm.submit(function(e){
e.preventDefault();
socket.emit('send message', $message.val());
$message.val('');
});
socket.on('new message', function(data){
$chat.append('<div class="well">'+data.msg+'</div>')
});
$userForm.submit(function(e){
e.preventDefault();
socket.emit('new user', $username.val(), function(data){
if(data){
$userFormArea.hide();
$messageArea.show();
}
});
$username.val('');
});
socket.on('get users', function(data){
var html = '';
for(i=0; i<data.length; i++)
{
html += '<li class="list-group-item">'+data[i]+'</li>';
}
users.html(html);
});
});
</script>
</body>
</html>
This is running accurately on localhost but as soon as i upload it to online hosting it gives an error. These are the error i am getting i have seen in console
(index):7 GET http://immodernafrican.move.pk:3000/socket.io/socket.io.js net::ERR_CONNECTION_TIMED_OUT
(index):58 Uncaught ReferenceError: io is not defined
at HTMLDocument.<anonymous> (http://immodernafrican.move.pk/:58:17)
at n (https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js:2:14784)
at Object.fireWith (https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js:2:15553)
at Function.ready (https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js:2:9773)
at HTMLDocument.B (https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js:2:14348)
i have tried to change
var socket = io.connect('http://immodernafrican.move.pk:3000');
to
var socket = io.connect();
but invain can anyone please help me regarding this issue so my chatroom can work
Thanks
I am trying to do this tutorial and at first it was all fine but after using the angular ui-router when i run the server all I get is a blank page. I can insert into db via terminal and the jason data are all working fine but the page is loading to a blank page...
public/javascripts/angularApp
var app = angular.module('flapperNews', [require('angular-ui-router')]);
app.factory('posts', ['$http',function($http){
var o = {
posts: []
};
return o;
o.getAll = function() {
return $http.get('/posts').success(function(data){
angular.copy(data, o.posts);
});
};
}]);
app.controller('MainCtrl', [
'$scope',
'posts',
function($scope, posts){
$scope.posts = posts.posts[$stateParams.id];
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
$scope.posts.push({title: $scope.title, link: $scope.link, upvotes: 0});
$scope.title = '';
$scope.link = '';
};
$scope.incrementUpvotes = function(post) {
post.upvotes += 1;
};
}]);
app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/home.html',
controller: 'MainCtrl'
resolve: {
postPromise: ['posts', function(posts){
return posts.getAll();
}]
}
});
.state('posts', {
url: '/posts/{id}',
templateUrl: '/posts.html',
controller: 'PostsCtrl'
});
$urlRouterProvider.otherwise('home');
}]);
app.controller('PostsCtrl', [
'$scope',
'$stateParams',
'posts',
function($scope, $stateParams, posts){
$scope.addComment = function(){
if($scope.body === '') { return; }
$scope.post.comments.push({
body: $scope.body,
author: 'user',
upvotes: 0
});
$scope.body = '';
};
}]);
routes/index.js`
var mongoose = require('mongoose');
var express = require('express');
var router = express.Router();
var Post = mongoose.model('Post');
var Comment = mongoose.model('Comment')
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/posts', function(req, res, next) {
Post.find(function(err, posts){
if(err){ return next(err); }
res.json(posts);
});
});
/* for saving post into db */
router.post('/posts', function(req, res, next) {
var post = new Post(req.body);
post.save(function(err, post){
if(err){ return next(err); }
res.json(post);
});
});
/* for retriving one post from db */
router.param('post', function(req, res, next, id) {
var query = Post.findById(id);
query.exec(function (err, post){
if (err) { return next(err); }
if (!post) { return next(new Error('can\'t find post')); }
req.post = post;
return next();
});
});
/* for retriving one comment from db */
router.param('comment', function(req, res, next, id) {
var query = Post.findById(id);
query.exec(function (err, comment){
if (err) { return next(err); }
if (!comment) { return next(new Error('can\'t find comment')); }
req.comment = comment;
return next();
});
});
/*for displaying the retrieved post*/
router.get('/posts/:post', function(req, res) {
res.json(req.post);
});
/*for displaying the post upvote*/
router.put('/posts/:post/upvote', function(req,res,next){
req.post.populate('comment',function(err,post){
if(err){return next(err);}
res.json(post);
});
});
/*saving comment*/
router.post('/posts/:post/comments',function(req, res, next){
var comment = new Comment(req.body);
comment.post = req.post;
comment.save(function(err,comment){
if(err){return next(err);}
req.post.comments.push(comment);
req.post.save(function(err,post){
if(err){return next(err);}
res.json(comment);
});
});
});
/*display comment upvote*/
router.put('/posts/:post/comments/:comment/upvote', function(req,res,next){
req.comment.upvote(function(err,comment){
if(err){return next(err);}
res.json(comment);
});
});
module.exports = router;
views/index.ejs
<html>
<head>
<title>My Angular App!</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
<script src="/javascripts/angularApp.js"></script>
<style> .glyphicon-thumbs-up { cursor:pointer } </style>
</head>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<ui-view></ui-view>
</div>
</div>
<script type="text/ng-template" id="/home.html">
<div class="page-header">
<h1>Flapper News</h1>
</div>
<div ng-repeat="post in posts | orderBy: '-upvotes'">
<span class="glyphicon glyphicon-thumbs-up" ng-click="upvote(post)"> </span>
{{post.upvotes}}
<span class="glyphicon glyphicon-thumbs-down" ng-click="downvote(post)"></span>
<span style="font-size:20px;margin-left:10px">
<a ng-show="post.link" href="{{post.link}}">
{{post.title}}
</a>
<span ng-hide="post.link">
{{post.title}}
</span>
<span ng-show="post.author">
posted by <a>{{post.author}}</a> |
</span>
</span>
<span>
Comments
({{post.comments.length}})
</span>
</div>
<form ng-submit="addPost()" ng-show="isLoggedIn()" style="margin-top:30px">
<h3>Add a new post:</h3>
<div class="form-group">
<input type="text" class="form-control" placeholder="Title" ng-model="title">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="Link" ng-model="link">
</div>
<button type="submit" class="btn btn-primary">Post</button>
</form>
<div ng-hide="isLoggedIn()">
<h3>You need to Log In or Register before you can add a post.</h3>
</div>
</script>
<script type="text/ng-template" id="/posts.html">
<div class="page-header">
<h3>
<a ng-show="post.link" href="{{post.link}}">
{{post.title}}
</a>
<span ng-hide="post.link">
{{post.title}}
</span>
</h3>
</div>
<div ng-repeat="comment in post.comments | orderBy:'-upvotes'">
<span class="glyphicon glyphicon-thumbs-up" ng-click="upvote(comment)"></span>
{{comment.upvotes}}
<span class="glyphicon glyphicon-thumbs-down" ng-click="downvote(comment)"></span>
- by {{comment.author}}
<span style="font-size:20px; margin-left:10px;">
{{comment.body}}
</span>
</div>
<form ng-submit="addComment()"
style="margin-top:30px;">
<h3>Add a new comment</h3>
<div class="form-group">
<input type="text"
class="form-control"
placeholder="Comment"
ng-model="body"></input>
</div>
<button type="submit" class="btn btn-primary">Post</button>
</form>
</script>
</body>
app.js
var mongoose = require('mongoose');
require('./models/Posts');
require('./models/Comments');
mongoose.connect('mongodb://localhost/news');
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
I had the same problem as well. They need to fix it in the tutorial, but in in your angularApp.js file you have this:
var app = angular.module('flapperNews', [require('angular-ui-router')]);
For ui-router, you actually have to inject it like so:
var app = angular.module('flapperNews', ['ui.router']);
Hope that helps!
Personally, I also just created separate files for my views so that I could add to it later a little neater since I don't like having all that on my index page.
In your Angularapp file, try moving your return o statement below the o.getAll() function so you actually get the posts loaded in the array before it is returned. This worked for me.
app.factory('posts', ['$http', function($http){
var o = {
posts: []
};
o.getAll = function() {
return $http.get('/posts').success(function(data){
angular.copy(data, o.posts);
});
};
return o;
}]);
I have been scrambling my brains for hours trying to implement this code in the Firebase Documentation with my own solution.
I have a Posts.json as a data source in Firebase with the following structure example:
{
Title: "Cheese Fondling",
Body: "I love cheese, especially paneer mozzarella. Roquefort cheeseburger cut the cheese fondue edam taleggio cheese slices gouda. Dolcelatte croque monsieur cottage cheese camembert de normandie cheese slices st. agur blue cheese bavarian bergkase swiss. Edam cheesecake parmesan.",
}
I am not sure if I need to update its records via set() as the file already exists but as it does not work I attempted with Push, which still does not work.
My HTML form view looks as follows:
<form class="form-horizontal" ng-submit="AddPost()">
<fieldset>
<!-- Form Name -->
<legend>{{addp.title}}</legend>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="txtTitle">Title</label>
<div class="col-md-4">
<input id="txtTitle" name="txtTitle" type="text" placeholder="placeholder" class="form-control input-md" ng-model="post.Title">
</div>
</div>
<!-- Textarea -->
<div class="form-group">
<label class="col-md-4 control-label" for="txtPost">Post</label>
<div class="col-md-4">
<textarea class="form-control" id="txtPost" name="txtPost" ng-model="post.Body"></textarea>
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="singlebutton"></label>
<div class="col-md-4">
<input id="singlebutton" ng-disabled="!post.Title || !post.Body" name="singlebutton" class="btn btn-primary" type="submit" value="Publish" />
</div>
</div>
</fieldset>
</form>
The controller is added separately via state:
.state('AddPost', {
url: '/blog',
controller: 'AddPostCtrl as addp',
templateUrl: 'blog.html',
title: 'Blog'
})
This is the controller code:
controllersModule.controller('AddPostCtrl', ["$scope", '$firebaseArray',
function($scope, $firebaseArray){
$scope.AddPost = function() {
var title = $scope.post.Title;
var post = $scope.post.Body;
$scope.refPosts = postsArray;
var ref = new Firebase('https://<DATASOURCE>.firebaseio.com/');
var refPosts = ref.child("Posts")
var postsArray = $firebaseArray(refPosts);
postsArray.$add({ Title: Title, Body: Body }).then(function(ref) {
console.log(ref);
console.log("It worked");
}, function(error) {
console.log("Error:", error);
console.log("It did not work");
});
}
}]);
EDITED ABOVE. AND ALSO ADDED THIS IN THE POSTS VIEW:
<div class="meeting" ng-repeat="post in refPosts">
<h5>{{post.Title}}</h5>
<p>{{post.Body}}</p>
</div>
While AngularFire and Firebase's JavaScript SDK interact with each other fine, you cannot call methods from one on objects from the other. You either have a Firebase JavaScript reference, on which you call ref.push() or you have an AngularFire $firebaseArray, on which you call array.$add().
With Firebase.push()
$scope.AddPost = function() {
var title = $scope.post.Title;
var post = $scope.post.Body;
var ref = new Firebase("https://<DATA SOURCE>.firebaseio.com/");
var refPosts = ref.child("Posts")
refPosts.push({ Title: title, Body: body }, function(error) {
if (error) {
console.log("Error:", error);
}
else {
console.log("It worked");
}
});
}
With $firebaseArray.$add()
$scope.AddPost = function() {
var title = $scope.post.Title;
var post = $scope.post.Body;
var ref = new Firebase("https://<DATA SOURCE>.firebaseio.com/");
var refPosts = ref.child("Posts")
var postsArray = $firebase(refPosts);
postsArray.$add({ Title: title, Body: body }).then(function(ref) {
console.log(ref);
console.log("It worked");
}, function(error) {
console.log("Error:", error);
console.log("It did not work");
});
}
So here is the final code. It does help to have other people's feedback:
controllersModule.controller('AddPostCtrl', ["$scope", '$firebaseArray',
function($scope, $firebaseArray){
var ref = new Firebase('https://<DATASOURCE>.firebaseio.com/Posts');
var myPosts = $firebaseArray(ref);
$scope.myPosts = myPosts;
$scope.AddPost = function() {
myPosts.$add({
Title: $scope.post.Title,
Body: $scope.post.Body
}).then(function(ref) {
console.log(ref);
}, function(error) {
console.log("Error:", error);
});
}
}]);