【问题标题】:Angular + socketio don't work?Angular + socketio 不起作用?
【发布时间】:2015-04-10 06:24:45
【问题描述】:

目前我正在尝试使用 socket.io 和 angular.js 实现实时内容,就我而言,我所做的一切都是正确的,但实时不起作用。也许我错过了任何重要的事情。

我将写一个它应该如何工作的场景。基本上,用户编写内容,然后将值发布到服务器。在 home.html 中,内容应该是实时的(我把所有内容都放在下面,包括 home.html)。

这是代码

server.js

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

// REAL TIME WORK
var http        = require('http').Server(app);
var io          = require('socket.io')(http);

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

app.use(function(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
    next();
});

// log our request to our terminal
app.use(morgan('dev'));

// Connect to our database using mongoose
mongoose.connect(config.database, function(err) {
    if(err) {
        console.log("Connection to a mongodb database has failed");
    } else {
        console.log("Connected to a database");
    }
});


// set our static files to a designated location
app.use(express.static(__dirname + '/public'));

var apiRouter = require('./app/routes/api') (app, express, io);
app.use('/api', apiRouter);

// registered before your api routes.
app.get('*', function(req, res) {
    res.sendFile(path.join(__dirname + '/public/app/views/index.html'));
});

http.listen(config.port, function(err) {
    if(err) {
        console.log("There's an error connecting the app to port" + config.port);
    } else {
        console.log("App is listening on port " + config.port);
    }
});

api.js

module.exports = function(app, express, io) {

    // creating our first router
    var apiRouter = express.Router();

    // signup a user
    var createStory = function(req, res) {

        var story = new Story({
            user: req.decoded.id,
            content: req.body.content
        });

        story.save(function(err) {

            if(err) {
                res.send(err);
                return;
            }

            io.emit('story', req.body.content);
            res.json({ message: 'Story has been created!'});

        });
    };

    apiRouter.route('/')

        .post(createStory)


        .get(function(req, res) {

            Story.find({ user: req.decoded.id }, function(err, story) {
                if(err) {
                    res.send(err);
                    return;
                }

                res.json(story);
            });


        });

service.js

angular.module('storyService', [])


.factory('Story', function($http, $window) {

    // get all approach
    var storyFactory = {};

    var generateReq = function(method, url, data) {
            var req = {
              method: method,
              url: url,
              headers: {
                'x-access-token': $window.localStorage.getItem('token')
              },
              cache: false
            }

            if(method === 'POST') {
                req.data = data;
            }
            return req;
        };

    storyFactory.all = function() {
        return $http(generateReq('GET', '/api/'));
    };


    storyFactory.create = function(storyData) {
        return $http(generateReq('POST', '/api/', storyData));
    };

    storyFactory.getSingleStory = function(user_name, story_id) {
        return $http(generateReq('GET', '/api/' + user_name + '/' + story_id));
    };

    storyFactory.allStories = function() {
        return $http(generateReq('GET', '/api/all_stories'));
    };

    return storyFactory;

})


.factory('socketio', ['$rootScope', function ($rootScope) {

        var socket = io.connect();
        return {
            on: function (eventName, callback) {
                socket.on(eventName, function () {
                    var args = arguments;
                    $rootScope.$apply(function () {
                        callback.apply(socket, args);
                    });
                });
            },
            emit: function (eventName, data, callback) {
                socket.emit(eventName, data, function () {
                    var args = arguments;
                    $rootScope.$apply(function () {
                        if (callback) {
                            callback.apply(socket, args);
                        }
                    });
                });
            }
        };
    }]);

controller.js

angular.module('storyCtrl', ['storyService'])


.controller('StoryController', function(Story, $routeParams, $scope, socketio) {

    var vm = this;

    Story.all()
    .success(function(data) {
        $scope.stories = data;
    });


    Story.getSingleStory($routeParams.user_name, $routeParams.story_id)
    .success(function(data) {
        $scope.storyData = data;
    });

    vm.createStory = function() {


        vm.message = '';

        Story.create(vm.storyData) 
        .success(function(data) {


                // clear the form
                vm.storyData = {}
                vm.message = data.message;

                socketio.on('story', function () {
                    $scope.stories.push(data);
                });

            });
    };

});

index.html

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>User Diary</title>


    <base href="/">

    <!-- CSS  -->
    <!-- load bootstrap from CDN and custom CSS -->
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.1/paper/bootstrap.min.css">

    <!-- load angular and angular-route via CDN -->
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular-route.js"></script>

    <script src="/socket.io/socket.io.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.js"></script>

    <!-- directives -->



    <!--controllers -->

    <script src="app/controllers/storyCtrl.js"></script>
    <script src="app/services/storyService.js"></script>


    <!-- main Angular app files -->
    <script src="app/app.routes.js"></script>
    <script src="app/app.js"></script>


</head>


<body ng-app="userApp">


<main class="container">

    <!-- ANGULAR VIEWS -->
    <div ng-view></div>
</main>



</body>
</html>

home.html

<div class="panel-body" ng-repeat="story in stories | reverse" >
    <ul class="list-group">
        <li class="list-group-item">
            <div class="row">
                <div class="col-xs-10 col-md-11">
                    <div>
                        <div class="mic-info">
                            {{ story.createdAt | date:'MMM d, yyyy' }}
                        </div>
                    </div>
                    <div class="comment-text">
                        <h4>{{ story.content }}</h4>
                    </div>
                </div>
            </div>
        </li>
    </ul>
</div>

我知道它很大,我发布它的原因是因为我不想错过任何东西。

我对整个 socket.io + angular.js 真的很陌生,如果你有任何意见可以教我一些关于 socket.io + angular.js 的东西,这对我来说意义重大:)

【问题讨论】:

  • 在您的 StoryController 中,您每次创建新帖子时都会注册事件侦听器,您应该这样做一次(另外它会在服务器上第一次发出后注册)。此外,控制器似乎混合使用了 controllerAs 语法和 $scope
  • 感谢您的回复,但您能否详细说明一下,以便我接受它,而我仍然不知道现在该做什么。
  • 我已发表评论,因为我不确定它是否能解决问题。我的意思的第一点是你只需要注册一次事件监听器socketio.on('story', function(content){ // }),而不是每次你创建一个新的故事。其次,如果您使用controllerAs 语法,那么您应该分配给thisvm,而不是$scope
  • 我应该在 promise 对象内部还是外部调用它?关于这个不用担心,现在的问题是在哪里推送数据以及如何去做。请帮帮我:(
  • 我给你看开源代码和网站可以吗?所以也许你可以指出我哪里做错了

标签: angularjs node.js socket.io mean-stack


【解决方案1】:

从 cmets 开始。

  1. 事件监听器socketio.on(..) 只需要创建一次。它将接收所有未来的事件,直到它被删除。也不要混用vm$scope

    angular.module('storyCtrl', ['storyService'])
    
    
    .controller('StoryController', function(Story, $routeParams, socketio) {
    
        var vm = this;
        vm.stories = [];
    
        Story.all()
        .success(function(data) {
            vm.stories = data;
        });
    
    
        Story.getSingleStory($routeParams.user_name, $routeParams.story_id)
        .success(function(data) {
            vm.storyData = data;
        });
    
        vm.createStory = function() {
            vm.message = '';
    
            Story.create(vm.storyData) 
            .success(function(data) {
                // clear the form
                vm.storyData = {}
                vm.message = data.message;
            });
        };
    
        socketio.on('story', function (data) {
            vm.stories.push(data);
        });
    });
    

    ng-controller="StoryController as StoryCtrl" 一样创建控制器,然后使用ng-repeat="story in StoryCtrl.stories" 重复

  2. 您的服务器端发出仅在它似乎应该返回具有至少contentcreatedAt 属性的对象时才响应帖子内容

    // signup a user
    var createStory = function(req, res) {
    
        var story = new Story({
            user: req.decoded.id,
            content: req.body.content
        });
    
        story.save(function(err) {
    
            if(err) {
                res.send(err);
                return;
            }
    
            io.emit('story', {
                user: req.decoded.id,
                createdAt: new Date(),
                content: req.body.content
            });
    
            // you might be able to do instead
            // io.emit('story', story.toObject())
    
            res.json({ message: 'Story has been created!'});
    
        });
    };
    

【讨论】:

  • 它可以工作,但是在第三次尝试之后,实时数据有点停止,这真的很奇怪。如果您转到您的帐户并尝试发布数据并转到路由“/allStories”,则不会显示实时时间。再次感谢您
  • 我的意思是尝试打开 2 个浏览器,1 个隐身浏览器和普通浏览器
  • 我无法测试,你heroku上的代码没有改变
  • 现在可以查看了,基本上还是不是实时的,而且每次点击第三个帖子,数据都不显示。
  • socket.on('story', ..) 仍然在错误的位置,因此每次创建故事时都会添加新的听众。添加 2 个故事会创建 2 个听众,故事会被推送到 stories 两次。 ng-repeat 然后停止工作,因为您有重复的项目。您的 allStories 路由不会是实时的,因为那里没有事件监听器
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
  • 2017-12-13
  • 2018-03-02
  • 2015-11-05
  • 1970-01-01
相关资源
最近更新 更多