├── .npmignore
├── .gitignore
├── examples
└── chat-app
│ ├── public
│ ├── src
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── styles.css
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── app
│ │ │ ├── chat.component.html
│ │ │ ├── app.module.ts
│ │ │ ├── chat.service.ts
│ │ │ └── chat.component.ts
│ │ ├── index.html
│ │ ├── main.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.spec.json
│ │ ├── test.ts
│ │ └── polyfills.ts
│ ├── dist
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── e2e
│ │ ├── app.po.ts
│ │ ├── app.e2e-spec.ts
│ │ └── tsconfig.e2e.json
│ ├── .editorconfig
│ ├── tsconfig.json
│ ├── package.json
│ ├── README.md
│ ├── .angular-cli.json
│ └── tslint.json
│ ├── readme.md
│ ├── package.json
│ └── app.js
├── .gitattributes
├── .travis.yml
├── socketIoConfig.ts
├── index.ts
├── tsconfig.json
├── socket-io.module.ts
├── LICENSE
├── package.json
├── socket-io.service.ts
├── tslint.json
├── spec
└── socket.spec.js
└── README.md
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | *.d.ts
3 | *.map
--------------------------------------------------------------------------------
/examples/chat-app/public/src/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * linguist-vendored
2 | *.ts linguist-vendored=false
--------------------------------------------------------------------------------
/examples/chat-app/public/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | before_script:
2 | - npm install
3 | script:
4 | - tsc; npm test
5 | language: node_js
6 | node_js:
7 | - "6"
8 |
--------------------------------------------------------------------------------
/examples/chat-app/public/dist/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bougarfaoui/ng-socket-io/HEAD/examples/chat-app/public/dist/favicon.ico
--------------------------------------------------------------------------------
/examples/chat-app/public/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bougarfaoui/ng-socket-io/HEAD/examples/chat-app/public/src/favicon.ico
--------------------------------------------------------------------------------
/socketIoConfig.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | /** Config interface */
4 | export interface SocketIoConfig {
5 | url: string;
6 | options?: any;
7 | };
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | export { SocketIoModule } from './socket-io.module';
4 | export { SocketIoConfig } from './socketIoConfig';
5 | export { WrappedSocket as Socket } from './socket-io.service';
6 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/app/chat.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{msg}}
6 |
7 |
--------------------------------------------------------------------------------
/examples/chat-app/public/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, element, by } from 'protractor';
2 |
3 | export class SocketAppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/chat-app/readme.md:
--------------------------------------------------------------------------------
1 | download the example
2 |
3 | ```cd chat-app```
4 |
5 | ```npm install```
6 |
7 | ```node app```
8 |
9 | open another terminal
10 |
11 | ```cd chat-app/public```
12 |
13 | ```npm install```
14 |
15 | ```ng build```
16 |
17 | then enter ```http://localhost:8988/``` in your browser.
18 |
--------------------------------------------------------------------------------
/examples/chat-app/public/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/examples/chat-app/public/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "lib": [
11 | "es2016"
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SocketApp
6 |
7 |
8 |
9 |
10 |
11 |
12 | Loading...
13 |
14 |
15 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule);
12 |
--------------------------------------------------------------------------------
/examples/chat-app/public/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { SocketAppPage } from './app.po';
2 |
3 | describe('socket-app App', () => {
4 | let page: SocketAppPage;
5 |
6 | beforeEach(() => {
7 | page = new SocketAppPage();
8 | });
9 |
10 | it('should display message saying app works', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('app works!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false
8 | };
9 |
--------------------------------------------------------------------------------
/examples/chat-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng2-socket-io",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node ./bin/www"
7 | },
8 | "dependencies": {
9 | "body-parser": "~1.15.1",
10 | "cookie-parser": "~1.4.3",
11 | "debug": "~2.2.0",
12 | "express": "~4.13.4",
13 | "jade": "~1.11.0",
14 | "morgan": "~1.7.0",
15 | "serve-favicon": "~2.3.0",
16 | "socket.io": "^1.7.3"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/chat-app/public/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": true,
4 | "declaration": false,
5 | "moduleResolution": "node",
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "lib": [
9 | "es2016"
10 | ],
11 | "outDir": "../dist/out-tsc-e2e",
12 | "module": "commonjs",
13 | "target": "es6",
14 | "types":[
15 | "jasmine",
16 | "node"
17 | ]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": true,
4 | "declaration": false,
5 | "moduleResolution": "node",
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "lib": [
9 | "es2016",
10 | "dom"
11 | ],
12 | "outDir": "../out-tsc/app",
13 | "target": "es5",
14 | "module": "es2015",
15 | "baseUrl": "",
16 | "types": []
17 | },
18 | "exclude": [
19 | "test.ts",
20 | "**/*.spec.ts"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "lib": ["es6", "dom"],
6 | "moduleResolution": "node",
7 | "declaration": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "noImplicitAny": true,
12 | "outDir": "./",
13 | "typeRoots": [
14 | "./node_modules/@types"
15 | ]
16 | },
17 | "files": [
18 | "./index.ts"
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule } from '@angular/core';
3 | import { SocketIoModule, SocketIoConfig } from 'ng-socket-io';
4 | import { ChatComponent } from './chat.component';
5 |
6 | const config: SocketIoConfig = { url: 'http://localhost:8988', options: {} };
7 |
8 | @NgModule({
9 | declarations: [
10 | ChatComponent
11 | ],
12 | imports: [
13 | BrowserModule,
14 | SocketIoModule.forRoot(config)
15 | ],
16 | bootstrap: [ChatComponent]
17 | })
18 | export class AppModule { }
19 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/app/chat.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Observable } from 'rxjs/Observable'
3 | import 'rxjs/add/operator/map';
4 | import { Socket } from 'ng-socket-io';
5 |
6 | @Injectable()
7 | export class ChatService {
8 |
9 | constructor(private socket: Socket) {}
10 |
11 | getMessage() {
12 | return this.socket
13 | .fromEvent("msg")
14 | .map(data => data.msg);
15 | }
16 |
17 | sendMessage(msg: string) {
18 | this.socket
19 | .emit("msg", msg);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": true,
4 | "declaration": false,
5 | "moduleResolution": "node",
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "lib": [
9 | "es2016"
10 | ],
11 | "outDir": "../out-tsc/spec",
12 | "module": "commonjs",
13 | "target": "es6",
14 | "baseUrl": "",
15 | "types": [
16 | "jasmine",
17 | "node"
18 | ]
19 | },
20 | "files": [
21 | "test.ts"
22 | ],
23 | "include": [
24 | "**/*.spec.ts"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/app/chat.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | import { ChatService } from './chat.service';
4 |
5 | @Component({
6 | selector: 'app-root',
7 | templateUrl: './chat.component.html',
8 | providers : [ChatService]
9 | })
10 | export class ChatComponent {
11 | msg : string;
12 |
13 | constructor(private chatService : ChatService) {}
14 |
15 | ngOnInit() {
16 | this.chatService
17 | .getMessage()
18 | .subscribe(msg => {
19 | this.msg = "1st "+msg;
20 | });
21 | }
22 |
23 | sendMsg(msg){
24 | this.chatService.sendMessage(msg);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/examples/chat-app/app.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var path = require('path');
3 | var express = require('express');
4 | var app = express();
5 |
6 |
7 |
8 | app.use(express.static(path.join(__dirname, 'public/dist')));
9 |
10 | app.get('*', function(req, res, next) {
11 | res.sendFile(__dirname+"/public/dist/index.html");
12 | });
13 |
14 |
15 | var server = http.createServer(app);
16 | var io = require('socket.io')(server);
17 | io.on('connection', function (socket) {
18 | socket.emit('msg', { msg: 'Welcome bro!' });
19 | socket.on('msg',function(msg){
20 | socket.emit('msg', { msg: "you sent : "+msg });
21 | })
22 | });
23 |
24 | server.listen(8988);
--------------------------------------------------------------------------------
/examples/chat-app/public/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SocketApp
6 |
7 |
8 |
9 |
10 |
11 |
12 | Loading...
13 |
14 |
15 |
--------------------------------------------------------------------------------
/socket-io.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ModuleWithProviders, InjectionToken } from '@angular/core';
2 |
3 | import { WrappedSocket } from './socket-io.service';
4 | import { SocketIoConfig } from './socketIoConfig';
5 |
6 |
7 | /** Socket factory */
8 | export function SocketFactory(config: SocketIoConfig) {
9 | return new WrappedSocket(config);
10 | }
11 |
12 | export const SOCKET_CONFIG_TOKEN = new InjectionToken('__SOCKET_IO_CONFIG__');
13 |
14 | @NgModule({})
15 | export class SocketIoModule {
16 | static forRoot(config: SocketIoConfig): ModuleWithProviders {
17 | return {
18 | ngModule: SocketIoModule,
19 | providers: [
20 | { provide: SOCKET_CONFIG_TOKEN, useValue: config },
21 | {
22 | provide: WrappedSocket,
23 | useFactory: SocketFactory,
24 | deps : [SOCKET_CONFIG_TOKEN]
25 | }
26 | ]
27 | };
28 | }
29 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Bougarfaoui El houcine
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/chat-app/public/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "socket-app",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "scripts": {
6 | "ng": "ng",
7 | "start": "ng serve",
8 | "build": "ng build",
9 | "test": "ng test",
10 | "lint": "ng lint",
11 | "e2e": "ng e2e"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/common": "^2.4.0",
16 | "@angular/compiler": "^2.4.0",
17 | "@angular/core": "^2.4.0",
18 | "@angular/forms": "^2.4.0",
19 | "@angular/http": "^2.4.0",
20 | "@angular/platform-browser": "^2.4.0",
21 | "@angular/platform-browser-dynamic": "^2.4.0",
22 | "@angular/router": "^3.4.0",
23 | "core-js": "^2.4.1",
24 | "ng-socket-io": "^0.1.0",
25 | "rxjs": "^5.1.0",
26 | "zone.js": "^0.7.6"
27 | },
28 | "devDependencies": {
29 | "@angular/cli": "1.0.0-rc.0",
30 | "@angular/compiler-cli": "^2.4.0",
31 | "@types/jasmine": "2.5.38",
32 | "@types/node": "^6.0.63",
33 | "codelyzer": "~2.0.0",
34 | "jasmine-core": "~2.5.2",
35 | "jasmine-spec-reporter": "~3.2.0",
36 | "ts-node": "~2.0.0",
37 | "tslint": "~4.4.2",
38 | "typescript": "~2.0.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/examples/chat-app/public/README.md:
--------------------------------------------------------------------------------
1 | # SocketApp
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0-rc.0.
4 |
5 | ## Development server
6 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
7 |
8 | ## Code scaffolding
9 |
10 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
11 |
12 | ## Build
13 |
14 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
15 |
16 | ## Running unit tests
17 |
18 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
19 |
20 | ## Running end-to-end tests
21 |
22 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
23 | Before running the tests make sure you are serving the app via `ng serve`.
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
28 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/long-stack-trace-zone';
4 | import 'zone.js/dist/proxy.js';
5 | import 'zone.js/dist/sync-test';
6 | import 'zone.js/dist/jasmine-patch';
7 | import 'zone.js/dist/async-test';
8 | import 'zone.js/dist/fake-async-test';
9 | import { getTestBed } from '@angular/core/testing';
10 | import {
11 | BrowserDynamicTestingModule,
12 | platformBrowserDynamicTesting
13 | } from '@angular/platform-browser-dynamic/testing';
14 |
15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
16 | declare var __karma__: any;
17 | declare var require: any;
18 |
19 | // Prevent Karma from running prematurely.
20 | __karma__.loaded = function () {};
21 |
22 | // First, initialize the Angular testing environment.
23 | getTestBed().initTestEnvironment(
24 | BrowserDynamicTestingModule,
25 | platformBrowserDynamicTesting()
26 | );
27 | // Then we find all the tests.
28 | const context = require.context('./', true, /\.spec\.ts$/);
29 | // And load the modules.
30 | context.keys().map(context);
31 | // Finally, start Karma to run the tests.
32 | __karma__.start();
33 |
--------------------------------------------------------------------------------
/examples/chat-app/public/.angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "project": {
4 | "name": "socket-app"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
12 | "favicon.ico"
13 | ],
14 | "index": "index.html",
15 | "main": "main.ts",
16 | "polyfills": "polyfills.ts",
17 | "test": "test.ts",
18 | "tsconfig": "tsconfig.app.json",
19 | "testTsconfig": "tsconfig.spec.json",
20 | "prefix": "app",
21 | "styles": [
22 | "styles.css"
23 | ],
24 | "scripts": [],
25 | "environmentSource": "environments/environment.ts",
26 | "environments": {
27 | "dev": "environments/environment.ts",
28 | "prod": "environments/environment.prod.ts"
29 | }
30 | }
31 | ],
32 | "e2e": {
33 | "protractor": {
34 | "config": "./protractor.conf.js"
35 | }
36 | },
37 | "lint": [
38 | {
39 | "project": "src/tsconfig.app.json"
40 | },
41 | {
42 | "project": "src/tsconfig.spec.json"
43 | },
44 | {
45 | "project": "e2e/tsconfig.e2e.json"
46 | }
47 | ],
48 | "test": {
49 | "karma": {
50 | "config": "./karma.conf.js"
51 | }
52 | },
53 | "defaults": {
54 | "styleExt": "css",
55 | "component": {}
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng-socket-io",
3 | "version": "0.1.5",
4 | "license": "MIT",
5 | "author": {
6 | "name": "Bougarfaoui El Houcine",
7 | "email": "bougarfaoui.el.houcine@gmail.com"
8 | },
9 | "main": "index.js",
10 | "module": "index.js",
11 | "jsnext:main": "index.js",
12 | "tags": [
13 | "angular2",
14 | "socket.io",
15 | "typescript",
16 | "angular2-socket.io"
17 | ],
18 | "scripts": {
19 | "test": "jasmine ./spec/socket.spec.js"
20 | },
21 | "dependencies": {
22 | "@types/socket.io-client": "^1.4.29",
23 | "socket.io-client": "^2.0.2"
24 | },
25 | "devDependencies": {
26 | "@angular/common": "^4.1.3",
27 | "@angular/compiler": "^4.1.3",
28 | "@angular/compiler-cli": "^4.1.3",
29 | "@angular/core": "^4.1.3",
30 | "@angular/platform-browser": "^4.1.3",
31 | "@angular/platform-browser-dynamic": "^4.1.3",
32 | "@types/jasmine": "2.5.38",
33 | "@types/node": "^6.0.63",
34 | "@types/socket.io": "^1.4.28",
35 | "@types/socket.io-client": "^1.4.29",
36 | "codelyzer": "~2.0.0-beta.1",
37 | "core-js": "^2.4.1",
38 | "es6-shim": "^0.35.3",
39 | "jasmine": "^2.5.3",
40 | "jasmine-core": "2.5.2",
41 | "jasmine-spec-reporter": "2.5.0",
42 | "karma": "1.2.0",
43 | "karma-chrome-launcher": "^2.0.0",
44 | "karma-cli": "^1.0.1",
45 | "karma-jasmine": "^1.0.2",
46 | "karma-remap-istanbul": "^0.2.1",
47 | "protractor": "~4.0.13",
48 | "reflect-metadata": "^0.1.10",
49 | "rxjs": "^5.0.1",
50 | "server-destroy": "^1.0.1",
51 | "socket.io": "^1.7.3",
52 | "socket.io-client": "^2.0.2",
53 | "ts-helpers": "^1.1.1",
54 | "ts-node": "1.2.1",
55 | "tslint": "^4.3.0",
56 | "typescript": "^2.3.4",
57 | "zone.js": "^0.8.16"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/socket-io.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, EventEmitter, Inject } from '@angular/core';
2 | import { Observable } from 'rxjs/Observable';
3 | import 'rxjs/add/operator/share';
4 |
5 | import * as io from 'socket.io-client';
6 |
7 | import { SocketIoConfig } from './socketIoConfig';
8 | import { SOCKET_CONFIG_TOKEN } from './socket-io.module';
9 |
10 | export class WrappedSocket {
11 | subscribersCounter = 0;
12 | ioSocket: any;
13 |
14 | constructor(@Inject(SOCKET_CONFIG_TOKEN) config: SocketIoConfig) {
15 | const url: string = config.url || '';
16 | const options: any = config.options || {};
17 | this.ioSocket = io(url, options);
18 | }
19 |
20 | on(eventName: string, callback: Function) {
21 | this.ioSocket.on(eventName, callback);
22 | }
23 |
24 | once(eventName: string, callback: Function) {
25 | this.ioSocket.once(eventName, callback);
26 | }
27 |
28 | connect() {
29 | return this.ioSocket.connect();
30 | }
31 |
32 | disconnect(close?: any) {
33 | return this.ioSocket.disconnect.apply(this.ioSocket, arguments);
34 | }
35 |
36 | emit(eventName: string, data?: any, callback?: Function) {
37 | return this.ioSocket.emit.apply(this.ioSocket, arguments);
38 | }
39 |
40 | removeListener(eventName: string, callback?: Function) {
41 | return this.ioSocket.removeListener.apply(this.ioSocket, arguments);
42 | }
43 |
44 | removeAllListeners(eventName?: string) {
45 | return this.ioSocket.removeAllListeners.apply(this.ioSocket, arguments);
46 | }
47 |
48 | /** create an Observable from an event */
49 | fromEvent(eventName: string): Observable {
50 | this.subscribersCounter++;
51 | return Observable.create( (observer: any) => {
52 | this.ioSocket.on(eventName, (data: T) => {
53 | observer.next(data);
54 | });
55 | return () => {
56 | if (this.subscribersCounter === 1)
57 | this.ioSocket.removeListener(eventName);
58 | };
59 | }).share();
60 | }
61 |
62 | /* Creates a Promise for a one-time event */
63 | fromEventOnce(eventName: string): Promise {
64 | return new Promise(resolve => this.once(eventName, resolve));
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/examples/chat-app/public/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/set';
35 |
36 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
37 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
38 |
39 | /** IE10 and IE11 requires the following to support `@angular/animation`. */
40 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
41 |
42 |
43 | /** Evergreen browsers require these. **/
44 | import 'core-js/es6/reflect';
45 | import 'core-js/es7/reflect';
46 |
47 |
48 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone'; // Included with Angular CLI.
57 |
58 |
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
64 | /**
65 | * Date, currency, decimal and percent pipes.
66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
67 | */
68 | // import 'intl'; // Run `npm install --save intl`.
69 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "callable-types": true,
7 | "class-name": true,
8 | "comment-format": [
9 | true,
10 | "check-space"
11 | ],
12 | "curly": true,
13 | "eofline": true,
14 | "forin": true,
15 | "import-blacklist": [true, "rxjs"],
16 | "import-spacing": true,
17 | "indent": [
18 | true,
19 | "spaces"
20 | ],
21 | "interface-over-type-literal": true,
22 | "label-position": true,
23 | "max-line-length": [
24 | true,
25 | 140
26 | ],
27 | "member-access": false,
28 | "member-ordering": [
29 | true,
30 | "static-before-instance",
31 | "variables-before-functions"
32 | ],
33 | "no-arg": true,
34 | "no-bitwise": true,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-construct": true,
44 | "no-debugger": true,
45 | "no-duplicate-variable": true,
46 | "no-empty": false,
47 | "no-empty-interface": true,
48 | "no-eval": true,
49 | "no-inferrable-types": true,
50 | "no-shadowed-variable": true,
51 | "no-string-literal": false,
52 | "no-string-throw": true,
53 | "no-switch-case-fall-through": true,
54 | "no-trailing-whitespace": true,
55 | "no-unused-expression": true,
56 | "no-use-before-declare": true,
57 | "no-var-keyword": true,
58 | "object-literal-sort-keys": false,
59 | "one-line": [
60 | true,
61 | "check-open-brace",
62 | "check-catch",
63 | "check-else",
64 | "check-whitespace"
65 | ],
66 | "prefer-const": true,
67 | "quotemark": [
68 | true,
69 | "single"
70 | ],
71 | "radix": true,
72 | "semicolon": [
73 | "always"
74 | ],
75 | "triple-equals": [
76 | true,
77 | "allow-null-check"
78 | ],
79 | "typedef-whitespace": [
80 | true,
81 | {
82 | "call-signature": "nospace",
83 | "index-signature": "nospace",
84 | "parameter": "nospace",
85 | "property-declaration": "nospace",
86 | "variable-declaration": "nospace"
87 | }
88 | ],
89 | "typeof-compare": true,
90 | "unified-signatures": true,
91 | "variable-name": false,
92 | "whitespace": [
93 | true,
94 | "check-branch",
95 | "check-decl",
96 | "check-operator",
97 | "check-separator",
98 | "check-type"
99 | ],
100 |
101 | "directive-selector": [true, "attribute", "app", "camelCase"],
102 | "component-selector": [true, "element", "app", "kebab-case"],
103 | "use-input-property-decorator": true,
104 | "use-output-property-decorator": true,
105 | "use-host-property-decorator": true,
106 | "no-input-rename": true,
107 | "no-output-rename": true,
108 | "use-life-cycle-interface": true,
109 | "use-pipe-transform-interface": true,
110 | "component-class-suffix": true,
111 | "directive-class-suffix": true,
112 | "no-access-missing-member": true,
113 | "templates-use-public": true,
114 | "invoke-injectable": true
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/examples/chat-app/public/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "callable-types": true,
7 | "class-name": true,
8 | "comment-format": [
9 | true,
10 | "check-space"
11 | ],
12 | "curly": true,
13 | "eofline": true,
14 | "forin": true,
15 | "import-blacklist": [true, "rxjs"],
16 | "import-spacing": true,
17 | "indent": [
18 | true,
19 | "spaces"
20 | ],
21 | "interface-over-type-literal": true,
22 | "label-position": true,
23 | "max-line-length": [
24 | true,
25 | 140
26 | ],
27 | "member-access": false,
28 | "member-ordering": [
29 | true,
30 | "static-before-instance",
31 | "variables-before-functions"
32 | ],
33 | "no-arg": true,
34 | "no-bitwise": true,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-construct": true,
44 | "no-debugger": true,
45 | "no-duplicate-variable": true,
46 | "no-empty": false,
47 | "no-empty-interface": true,
48 | "no-eval": true,
49 | "no-inferrable-types": [true, "ignore-params"],
50 | "no-shadowed-variable": true,
51 | "no-string-literal": false,
52 | "no-string-throw": true,
53 | "no-switch-case-fall-through": true,
54 | "no-trailing-whitespace": true,
55 | "no-unused-expression": true,
56 | "no-use-before-declare": true,
57 | "no-var-keyword": true,
58 | "object-literal-sort-keys": false,
59 | "one-line": [
60 | true,
61 | "check-open-brace",
62 | "check-catch",
63 | "check-else",
64 | "check-whitespace"
65 | ],
66 | "prefer-const": true,
67 | "quotemark": [
68 | true,
69 | "single"
70 | ],
71 | "radix": true,
72 | "semicolon": [
73 | "always"
74 | ],
75 | "triple-equals": [
76 | true,
77 | "allow-null-check"
78 | ],
79 | "typedef-whitespace": [
80 | true,
81 | {
82 | "call-signature": "nospace",
83 | "index-signature": "nospace",
84 | "parameter": "nospace",
85 | "property-declaration": "nospace",
86 | "variable-declaration": "nospace"
87 | }
88 | ],
89 | "typeof-compare": true,
90 | "unified-signatures": true,
91 | "variable-name": false,
92 | "whitespace": [
93 | true,
94 | "check-branch",
95 | "check-decl",
96 | "check-operator",
97 | "check-separator",
98 | "check-type"
99 | ],
100 |
101 | "directive-selector": [true, "attribute", "app", "camelCase"],
102 | "component-selector": [true, "element", "app", "kebab-case"],
103 | "use-input-property-decorator": true,
104 | "use-output-property-decorator": true,
105 | "use-host-property-decorator": true,
106 | "no-input-rename": true,
107 | "no-output-rename": true,
108 | "use-life-cycle-interface": true,
109 | "use-pipe-transform-interface": true,
110 | "component-class-suffix": true,
111 | "directive-class-suffix": true,
112 | "no-access-missing-member": true,
113 | "templates-use-public": true,
114 | "invoke-injectable": true
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/spec/socket.spec.js:
--------------------------------------------------------------------------------
1 | require("reflect-metadata");
2 | require("es6-shim");
3 |
4 | var enableDestroy = require('server-destroy');
5 | var http = require('http');
6 | var IOSocket = require("../socket-io.service.js").WrappedSocket;
7 | var server, io;
8 |
9 | beforeEach(function(){
10 | server = http.createServer();
11 |
12 | io = require('socket.io')(server);
13 | io.on('connection', function(socket){
14 | socket.emit('event',"someData");
15 | socket.emit('event',"someData");
16 | socket.on("otherEvent",function(){
17 | socket.emit('otherEvent',"Msg Received");
18 | });
19 | socket.emit('secondEvent',"someData");
20 | socket.emit('thirdEvent',"someDatasss");
21 | });
22 | server.listen(3000);
23 | enableDestroy(server);
24 |
25 | });
26 |
27 | afterEach(function(){
28 | server.destroy();
29 | })
30 |
31 |
32 |
33 | var ioClient = require('socket.io-client');
34 |
35 | var socketURL = 'http://localhost:3000';
36 |
37 | describe("fromEvent",function(){
38 | it('should be equal', (done) => {
39 |
40 | let socket = new IOSocket({url: socketURL});
41 | socket.fromEvent("event").subscribe((data)=>{
42 | expect(data).toEqual("someData");
43 | done();
44 | });
45 |
46 | });
47 | })
48 |
49 | describe("unsubcribe from Event",function(){
50 | it('should be equal', (done) => {
51 | var unsubcribeCallBack = jasmine.createSpy('unsubcribeCallBack');
52 | let socket = new IOSocket({url: socketURL});
53 | socket.fromEvent("thirdEvent").subscribe((data)=>{
54 | expect(data).toEqual("someData");
55 | socket.on("thirdEvent",unsubcribeCallBack);
56 | }).unsubscribe();
57 |
58 | setTimeout(function(){
59 | expect(unsubcribeCallBack).not.toHaveBeenCalled();
60 | done();
61 | },200);
62 |
63 | });
64 | })
65 |
66 |
67 |
68 |
69 | describe("on",function(){
70 | it('should be equal', (done) => {
71 |
72 | let socket = new IOSocket({url: socketURL});
73 | socket.on("event",(data) => {
74 | expect(data).toEqual("someData");
75 | done();
76 | });
77 |
78 | });
79 | })
80 |
81 |
82 | describe("once",function(){
83 | it('should be equal', (done) => {
84 |
85 | let socket = new IOSocket({url: socketURL});
86 | let count = 0;
87 | socket.once("event",(data) => {
88 | expect(data).toEqual("someData");
89 | count++;
90 | });
91 |
92 | setTimeout(function(){
93 | expect(count).toEqual(1);
94 | done();
95 | },200)
96 | });
97 | })
98 |
99 | describe("emit",function(){
100 | it('should be equal', (done) => {
101 |
102 | let socket = new IOSocket({url: socketURL});
103 | let count = 0;
104 | socket.emit('otherEvent');
105 | socket.on("otherEvent",function(data){
106 | expect(data).toEqual("Msg Received");
107 | done();
108 | });
109 | });
110 | })
111 |
112 |
113 | describe("should remove the listener",function(){
114 | it('should be equal', (done) => {
115 | var removeListenerCallBack = jasmine.createSpy('removeListenerCallBack');
116 | let socket = new IOSocket({url: socketURL});
117 | let count = 0;
118 | socket.on("event",removeListenerCallBack);
119 | socket.removeListener('event');
120 | setTimeout(function(){
121 | expect(removeListenerCallBack).not.toHaveBeenCalled();
122 | done();
123 | },200);
124 | });
125 | })
126 |
127 | describe("removeAllListeners",function(){
128 | it('should remove all listeners ', (done) => {
129 | var removeAllListenersCallBack = jasmine.createSpy('removeAllListenersCallBack');
130 | let socket = new IOSocket({url: socketURL});
131 | let count = 0;
132 | socket.on("event",removeAllListenersCallBack);
133 | socket.on("secondEvent",removeAllListenersCallBack);
134 | socket.removeAllListeners();
135 |
136 | setTimeout(function(){
137 | expect(removeAllListenersCallBack).not.toHaveBeenCalled();
138 | done();
139 | },200);
140 | });
141 | })
142 |
143 |
144 | describe("disconnect",function(){
145 | it('should disconnect', (done) => {
146 | var disconnectCallBack = jasmine.createSpy('disconnectCallBack');
147 | let socket = new IOSocket({url: socketURL});
148 | let count = 0;
149 | socket.disconnect();
150 | socket.on("event",disconnectCallBack);
151 | setTimeout(function(){
152 | expect(disconnectCallBack).not.toHaveBeenCalled();
153 | done();
154 | },200);
155 | });
156 | })
157 |
158 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ng-socket-io
2 | [](https://travis-ci.org/bougarfaoui/ng-socket-io)
3 | [](https://www.npmjs.com/package/ng-socket-io)
4 | [](https://github.com/bougarfaoui/ng-socket-io)
5 |
6 | [Socket.IO](http://socket.io/) module for Angular 2 and 4
7 |
8 | ## Install
9 | ``` npm install ng-socket-io ```
10 |
11 | ## How to use
12 |
13 | ### Import and configure SocketIoModule
14 |
15 | ```ts
16 | //...
17 | import { SocketIoModule, SocketIoConfig } from 'ng-socket-io';
18 |
19 | const config: SocketIoConfig = { url: 'http://localhost:8988', options: {} };
20 |
21 | @NgModule({
22 | declarations: [
23 | AppComponent
24 | ],
25 | imports: [
26 | BrowserModule,
27 | SocketIoModule.forRoot(config)
28 | ],
29 | providers: [],
30 | bootstrap: [AppComponent]
31 | })
32 | export class AppModule { }
33 | ```
34 |
35 | We need to configure ```SocketIoModule``` module using the object ```config``` of type ```SocketIoConfig```, this object accepts two optional properties they are the same used here [io(url[, options])](https://github.com/socketio/socket.io-client/blob/master/docs/API.md#iourl-options).
36 |
37 | Now we pass the configuration to the static method ```forRoot``` of ```SocketIoModule```
38 |
39 | ### Using your socket Instance
40 |
41 | The ```SocketIoModule``` provides now a configured ```Socket``` service that can be injected anywhere inside the ```AppModule```.
42 |
43 | ```typescript
44 | import { Injectable } from '@angular/core';
45 | import { Socket } from 'ng-socket-io';
46 |
47 | @Injectable()
48 | export class ChatService {
49 |
50 | constructor(private socket: Socket) { }
51 |
52 | sendMessage(msg: string){
53 | this.socket.emit("message", msg);
54 | }
55 |
56 | getMessage() {
57 | return this.socket
58 | .fromEvent("message")
59 | .map( data => data.msg );
60 | }
61 | }
62 | ```
63 |
64 | ### Using multiple sockets with different end points
65 |
66 | In this case we do not configure the ```SocketIoModule``` directly using ```forRoot```. What we have to do is: extend the ```Socket``` service, and call ```super()``` with the ```SocketIoConfig``` object type (passing ```url``` & ```options``` if any).
67 |
68 | ```typescript
69 | import { Injectable, NgModule } from '@angular/core';
70 | import { Socket } from 'ng-socket-io';
71 |
72 | @Injectable()
73 | export class SocketOne extends Socket {
74 |
75 | constructor() {
76 | super({ url: 'http://url_one:portOne', options: {} });
77 | }
78 |
79 | }
80 |
81 | @Injectable()
82 | export class SocketTwo extends Socket {
83 |
84 | constructor() {
85 | super({ url: 'http://url_two:portTwo', options: {} });
86 | }
87 |
88 | }
89 |
90 | @NgModule({
91 | declarations: [
92 | //components
93 | ],
94 | imports: [
95 | SocketIoModule,
96 | //...
97 | ],
98 | providers: [SocketOne, SocketTwo],
99 | bootstrap: [/** AppComponent **/]
100 | })
101 | export class AppModule { }
102 |
103 | ```
104 |
105 | Now you can inject ```SocketOne```, ```SocketTwo``` in any other services and / or components.
106 |
107 |
108 | ## API
109 |
110 | Most of the functionalities here you are already familiar with.
111 |
112 | The only addition is the ```fromEvent``` method, which returns an ```Observable``` that you can subscribe to.
113 |
114 | ### `socket.on(eventName: string)`
115 | Takes an event name and callback.
116 | Works the same as in Socket.IO.
117 |
118 | ### `socket.removeListener(eventName: string, callback: Function)`
119 | Takes an event name and callback.
120 | Works the same as in Socket.IO.
121 |
122 | ### `socket.removeAllListeners(eventName: string)`
123 | Takes an event name.
124 | Works the same as in Socket.IO.
125 |
126 | ### `socket.emit(eventName:string, message: any, [callback: Function])`
127 | Sends a message to the server.
128 | Optionally takes a callback.
129 | Works the same as in Socket.IO.
130 |
131 | ### `socket.fromEvent(eventName: string): Observable`
132 | Takes an event name and returns an Observable that you can subscribe to.
133 |
134 | ### socket.fromEventOnce(eventName: string): Promise
135 | Takes an event name, and returns a Promise instead of an Observable.
136 | Works the same as `once` in Socket.IO.
137 |
138 | You should keep a reference to the Observable subscription and unsubscribe when you're done with it.
139 | This prevents memory leaks as the event listener attached will be removed (using ```socket.removeListener```) ONLY and when/if you unsubscribe.
140 |
141 | If you have multiple subscriptions to an Observable only the last unsubscription will remove the listener.
142 |
143 | ##### Example
144 |
145 | You can also see this [example](https://github.com/bougarfaoui/ng-socket-io/tree/master/examples/chat-app) with express.js.
146 |
147 | ```typescript
148 | import { BrowserModule } from '@angular/platform-browser';
149 | import { NgModule } from '@angular/core';
150 | import { AppComponent } from './app.component';
151 |
152 | import { SocketIoModule, SocketIoConfig, Socket} from 'ng-socket-io';
153 |
154 | const config: SocketIoConfig = { url: 'http://localhost:8988', options: {} };
155 |
156 | @Injectable()
157 | class ChatService {
158 |
159 | constructor(private socket: Socket) { }
160 |
161 | sendMessage(msg: string){
162 | this.socket.emit("message", msg);
163 | }
164 |
165 | getMessage() {
166 | return this.socket
167 | .fromEvent("message")
168 | .map(data => data.msg );
169 | }
170 |
171 | close() {
172 | this.socket.disconnect()
173 | }
174 | }
175 |
176 |
177 | @NgModule({
178 | declarations: [
179 | AppComponent
180 | ],
181 | imports: [
182 | BrowserModule,
183 | SocketIoModule.forRoot(config)
184 | ],
185 | providers: [ChatService],
186 | bootstrap: [AppComponent]
187 | })
188 | export class AppModule { }
189 | ```
190 |
191 |
192 | ## LICENSE
193 |
194 | MIT
195 |
--------------------------------------------------------------------------------