├── .gitignore ├── .npmignore ├── src ├── index.ts ├── angular2-pubsub.module.ts ├── angular2-pubsub.service.spec.ts └── angular2-pubsub.service.ts ├── publish.sh ├── tsconfig.json ├── karma.conf.js ├── tsconfig-ngc.json ├── webpack.config.test.js ├── karma-test-runner.js ├── webpack.config.umd.js ├── CHANGELOG.md ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | npm-debug.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bower.json 2 | tsconfig.json 3 | npm-debug.log -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './angular2-pubsub.service'; 2 | export * from './angular2-pubsub.module'; -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Build project 4 | npm run build 5 | 6 | echo "====== PUBLISHING: angular2-pubusb =====" 7 | npm publish ./dist --access public 8 | echo "====== PUBLISHED: angular2-pubusb =====" 9 | -------------------------------------------------------------------------------- /src/angular2-pubsub.module.ts: -------------------------------------------------------------------------------- 1 | import { PubSubService } from './angular2-pubsub.service'; 2 | import { ModuleWithProviders, NgModule } from '@angular/core'; 3 | 4 | @NgModule() 5 | export class PubSubModule { 6 | public static forRoot(): ModuleWithProviders { 7 | return { 8 | ngModule: PubSubModule, 9 | providers: [ 10 | PubSubService 11 | ] 12 | }; 13 | } 14 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": false, 11 | "allowSyntheticDefaultImports": true, 12 | "baseUrl": ".", 13 | "paths": { 14 | "tempo-common": [ 15 | "./src/index" 16 | ] 17 | } 18 | }, 19 | "compileOnSave": false 20 | } -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | config.set({ 3 | browsers: ['PhantomJS'], 4 | frameworks: ['jasmine'], 5 | reporters: ['mocha'], 6 | singleRun: true, 7 | preprocessors: { './karma-test-runner.js': ['webpack', 'sourcemap'] }, 8 | files: [ 9 | { pattern: 'node_modules/babel-polyfill/browser.js', instrument: false }, 10 | { pattern: './karma-test-runner.js', watched: false } 11 | ], 12 | webpack: require('./webpack.config.test.js'), 13 | 14 | webpackServer: { noInfo: true } 15 | }); 16 | }; -------------------------------------------------------------------------------- /tsconfig-ngc.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es2015", 5 | "moduleResolution": "node", 6 | "declaration": true, 7 | "experimentalDecorators": true, 8 | "baseUrl": ".", 9 | "stripInternal": true, 10 | "outDir": "./dist/esm", 11 | "rootDir": "./", 12 | "sourceMap": true, 13 | "inlineSources": true, 14 | "types": [], 15 | "lib": [ 16 | "es6", 17 | "dom" 18 | ] 19 | }, 20 | "files": [ 21 | "src/index.ts" 22 | ], 23 | "angularCompilerOptions": { 24 | "genDir": "./dist/esm", 25 | "skipTemplateCodegen": true, 26 | "strictMetadataEmit": true, 27 | "debug": true 28 | } 29 | } -------------------------------------------------------------------------------- /webpack.config.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const DefinePlugin = require('webpack/lib/DefinePlugin'); 3 | 4 | const ENV = process.env.NODE_ENV = 'development'; 5 | const HOST = process.env.HOST || 'localhost'; 6 | const PORT = process.env.PORT || 8080; 7 | 8 | const metadata = { 9 | env: ENV, 10 | host: HOST, 11 | port: PORT 12 | }; 13 | 14 | module.exports = { 15 | debug: true, 16 | devtool: 'inline-source-map', 17 | module: { 18 | loaders: [ 19 | { test: /\.ts$/, loader: 'ts', query: { compilerOptions: { noEmit: false } } } 20 | ] 21 | }, 22 | plugins: [ 23 | new DefinePlugin({ 'webpack': { 'ENV': JSON.stringify(metadata.env) } }) 24 | ], 25 | resolve: { 26 | extensions: ['', '.ts', '.js'] 27 | } 28 | }; -------------------------------------------------------------------------------- /karma-test-runner.js: -------------------------------------------------------------------------------- 1 | 2 | Error.stackTraceLimit = Infinity; 3 | 4 | require('reflect-metadata'); 5 | require('zone.js/dist/zone');; 6 | require('zone.js/dist/long-stack-trace-zone'); 7 | require('zone.js/dist/async-test'); 8 | require('zone.js/dist/fake-async-test'); 9 | require('zone.js/dist/sync-test'); 10 | require('zone.js/dist/proxy'); 11 | require('zone.js/dist/jasmine-patch'); 12 | 13 | var testing = require('@angular/core/testing'); 14 | var browser = require('@angular/platform-browser-dynamic/testing'); 15 | 16 | testing.TestBed.initTestEnvironment( 17 | browser.BrowserDynamicTestingModule, 18 | browser.platformBrowserDynamicTesting() 19 | ); 20 | 21 | Object.assign(global, testing); 22 | 23 | var testContext = require.context('./src', true, /\.spec\.ts/); 24 | 25 | function requireAll(requireContext) { 26 | return requireContext.keys().map(requireContext); 27 | } 28 | 29 | var modules = requireAll(testContext); -------------------------------------------------------------------------------- /src/angular2-pubsub.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { PubSubService } from './angular2-pubsub.service'; 4 | import { Observable, Subscriber } from 'rxjs'; 5 | 6 | describe('PubSubService', (): void => { 7 | let pubService: PubSubService; 8 | 9 | beforeEach(() => { 10 | pubService = new PubSubService(); 11 | }); 12 | 13 | describe('$sub', (): void => { 14 | it('should throw an error when event is falsy', (): void => { 15 | expect(() => pubService.$sub(undefined)).toThrow(); 16 | }); 17 | 18 | it('should return an observable when there is no callback', (): void => { 19 | let result: any = pubService.$sub('test'); 20 | expect(result instanceof Observable).toBeTruthy(); 21 | }); 22 | 23 | it('should return a subscriber when there is a callback specified', (): void => { 24 | let result: any = pubService.$sub('test', (v: any): void => { 25 | ''; 26 | }); 27 | expect(result instanceof Subscriber).toBeTruthy(); 28 | }); 29 | }); 30 | 31 | describe('$pub', (): void => { 32 | it('should throw an error when event is falsy', (): void => { 33 | expect(() => pubService.$pub(undefined)).toThrow(); 34 | }); 35 | 36 | it('should do nothing when an event is not registered', (): void => { 37 | expect(() => pubService.$pub('not-registered')).not.toThrow(); 38 | }); 39 | 40 | it('should publish with parameters if the event is registered', (): void => { 41 | let subscriberEventSpy: jasmine.Spy = jasmine.createSpy('subscriberEvent'); 42 | pubService.$sub('new-event', subscriberEventSpy); 43 | 44 | pubService.$pub('new-event', 'foo'); 45 | 46 | expect(subscriberEventSpy).toHaveBeenCalledWith('foo'); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /webpack.config.umd.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | // Webpack and its plugins 3 | const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'); 4 | const CompressionPlugin = require('compression-webpack-plugin'); 5 | const DedupePlugin = require('webpack/lib/optimize/DedupePlugin'); 6 | const DefinePlugin = require('webpack/lib/DefinePlugin'); 7 | const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin'); 8 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 9 | const StyleLintPlugin = require('stylelint-webpack-plugin'); 10 | 11 | const ENV = process.env.NODE_ENV = 'production'; 12 | 13 | const metadata = { 14 | env: ENV 15 | }; 16 | module.exports = { 17 | devtool: 'source-map', 18 | entry: { 19 | 'main': './src/index.ts' 20 | }, 21 | externals: { 22 | '@angular/core': { 23 | root: ['ng', 'core'], 24 | commonjs: '@angular/core', 25 | commonjs2: '@angular/core', 26 | amd: '@angular/core' 27 | }, 28 | '@angular/common': { 29 | root: ['ng', 'common'], 30 | commonjs: '@angular/common', 31 | commonjs2: '@angular/common', 32 | amd: '@angular/common' 33 | }, 34 | '@angular/platform-browser': { 35 | root: ['ng', 'platformBrowser'], 36 | commonjs: '@angular/platform-browser', 37 | commonjs2: '@angular/platform-browser', 38 | amd: '@angular/platform-browser' 39 | }, 40 | 'rxjs/Subscription': { 41 | root: ['rx', 'Subscription'], 42 | commonjs: 'rxjs/Subscription', 43 | commonjs2: 'rxjs/Subscription', 44 | amd: 'rxjs/Subscription' 45 | } 46 | }, 47 | module: { 48 | loaders: [ 49 | { test: /\.ts$/, loader: 'ts', query: { compilerOptions: { noEmit: false } } } 50 | ] 51 | }, 52 | output: { 53 | path: './dist/umd', 54 | filename: 'angular2-pubsub.js', 55 | libraryTarget: 'umd', 56 | library: 'angular2-pubsub' 57 | }, 58 | plugins: [ 59 | new CompressionPlugin({ regExp: /\.css$|\.html$|\.js$|\.map$/ }) 60 | ], 61 | resolve: { 62 | extensions: ['', '.ts', '.js'], 63 | modules: [path.resolve(__dirname, 'node_modules')] 64 | } 65 | }; -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v4.0.4 2 | - Updated NPM Readme 3 | 4 | ## v4.0.3 5 | - Default version is now 4.x.x 6 | - Fixed type error 7 | 8 | ## Next v4.0.2 9 | - Fixed the issue that created multiple pubsub services (#7). 10 | 11 | ## Next v4.0.0 12 | - Only version changed for anyone using Angular 4.0.0 13 | 14 | ## v2.0.6 15 | - Fixed type error. 16 | 17 | ## v2.0.5 18 | - Fixed the issue that created multiple pubsub services (#7). 19 | 20 | ## v2.0.1 21 | - $pub command return undefined when no event subscribe. 22 | - $sub method bug solved. RxJS Subscriber no longer call subscribe method on start. 23 | 24 | ## v2.0.0 25 | - PubSubService moved into PubSubModule. 26 | - Added unit tests for the service and project restructure updated to use the benefits of webpack and bundling. 27 | 28 | ## v1.1.1 29 | Recovery fix and added interfaces. 30 | 31 | ### Class Overview 32 | ```typescript 33 | declare class PubSubService{ 34 | private events: Object; 35 | $pub(event: string, eventObject?: any): void; 36 | $sub: { 37 | (): undefined; 38 | (event: string): Observable; 39 | (event: string, callback: (value: any) => void): Subscription; 40 | (event: string, callback: (value: any) => void, error: (error: any) => void): Subscription; 41 | (event: string, callback: (value: any) => void, error: (error: any) => void, complete: () => void): Subscription; 42 | } 43 | } 44 | ``` 45 | 46 | ------- 47 | ## v1.1.0 48 | 49 | Added overload to $sub method for to be useful. 50 | 51 | ### Class Overview 52 | ```typescript 53 | declare class PubSubService{ 54 | private events: Object; 55 | $pub(event: string, eventObject?: any): void; 56 | $sub(event: string): >; 57 | $sub(event: string, callback: (value: any) => void, error?: (error: any) => void, complete?: () => void): Subscription; 58 | } 59 | ``` 60 | ------- 61 | ## v1.0.0 62 | A simple publisher/subscriber service. 63 | 64 | ### Class Overview 65 | ```typescript 66 | declare class PubSubService{ 67 | private events: Object; 68 | $pub(event: string, eventObject?: any): void; 69 | $sub(event: string): >; 70 | $sub(event: string, callback: (value: any) => void, error?: (error: any) => void, complete?: () => void): Subscription; 71 | } 72 | ``` -------------------------------------------------------------------------------- /src/angular2-pubsub.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ReplaySubject } from 'rxjs/ReplaySubject'; 3 | import { Observable } from 'rxjs/Observable'; 4 | import { Subscription } from 'rxjs/Subscription'; 5 | 6 | const ServiceName: string = "PubSub Service"; 7 | 8 | @Injectable() 9 | export class PubSubService implements IPubSubService { 10 | private events = { }; 11 | 12 | constructor() { } 13 | 14 | public $sub(event: string): Observable; 15 | public $sub(event: string, callback: (value: any) => void): Subscription; 16 | public $sub(event: string, callback: (value: any) => void, error: (error: any) => void): Subscription; 17 | public $sub(event: string, callback: (value: any) => void, error: (error: any) => void, complete: () => void): Subscription; 18 | public $sub(event: string, callback?: (value: any) => void, error?: (error: any) => void, complete?: () => void) { 19 | if (!event) { 20 | throw new Error(`[${ServiceName}] => Subscription method must get event name.`); 21 | } 22 | 23 | if (this.events[event] === undefined) { 24 | this.events[event] = new ReplaySubject(); 25 | } 26 | 27 | if (typeof callback !== 'function') { 28 | return this.events[event].asObservable(); 29 | } else { 30 | return this.events[event].asObservable().subscribe(callback, error, complete); 31 | } 32 | } 33 | 34 | public $pub(event: string, eventObject?: any) { 35 | if (!event) { 36 | throw new Error(`[${ServiceName}] => Publish method must get event name.`); 37 | } else if (!this.events[event]) { 38 | return; 39 | } 40 | 41 | this.events[event].next(eventObject); 42 | } 43 | } 44 | 45 | export interface IPubSubService { 46 | $pub(event: string, eventObject?: any): void; 47 | $sub(event: string): Observable; 48 | $sub(event: string, callback: (value: any) => void): Subscription; 49 | $sub(event: string, callback: (value: any) => void, error: (error: any) => void): Subscription; 50 | $sub(event: string, callback: (value: any) => void, error: (error: any) => void, complete: () => void): Subscription; 51 | } 52 | 53 | interface I$sub{ 54 | (event: string): Observable; 55 | (event: string, callback: (value: any) => void): Subscription; 56 | (event: string, callback: (value: any) => void, error: (error: any) => void): Subscription; 57 | (event: string, callback: (value: any) => void, error: (error: any) => void, complete: () => void): Subscription; 58 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pub/Sub Service for Angular 2 2 | 3 | A simple publisher/subscriber service. 4 | 5 | [![NPM](https://nodei.co/npm/angular2-pubsub.png?downloads=true&stars=true)](https://nodei.co/npm/angular2-pubsub/) 6 | 7 | ## Usage 8 | - Import service in your codes or download via npm or bower. 9 | 10 | `npm i --save angular2-pubsub` 11 | 12 | if you use Angular version 2.x.x plase install from npm with '2.0.6' tag. 13 | 14 | `npm i --save angular2-pubsub@2.0.6` 15 | 16 | - Add module bundle to imports in your application. 17 | ```typescript 18 | ... 19 | 20 | import { PubSubModule } from 'angular2-pubsub'; // <= HERE 21 | 22 | @NgModule({ 23 | declarations: [ 24 | RootComponent, 25 | NavigationComponent, 26 | OverlayComponent 27 | ], 28 | imports: [ 29 | BrowserModule, 30 | FormsModule, 31 | HttpModule, 32 | PubSubModule.forRoot() // <= AND HERE 33 | ], 34 | providers: [], 35 | bootstrap: [RootComponent] 36 | }) 37 | 38 | ... 39 | ``` 40 | - And import service wherever you want 41 | 42 | ## Documentation 43 | 44 | #### Class Overview 45 | 46 | ```typescript 47 | declare class PubSubService { 48 | private events: Object; 49 | $pub(event: string, eventObject?: any): void; 50 | $sub(): undefined; 51 | $sub(event: string): Observable; 52 | $sub(event: string, callback: (value: any) => void): Subscription; 53 | $sub(event: string, callback: (value: any) => void, error: (error: any) => void): Subscription; 54 | $sub(event: string, callback: (value: any) => void, error: (error: any) => void, complete: () => void): Subscription; 55 | } 56 | ``` 57 | 58 | #### PubSubService.$pub(event: string, eventObject?: any): void 59 | 60 | Publish event to all subscriber. 61 | 62 | etc. 63 | ```typescript 64 | export class OverlayComponent implements OnInit, OnDestroy { 65 | constructor(private pubsub: PubSubService) { } 66 | 67 | anyFunc(){ 68 | this.pubsub.$pub('pleaseCloseSidenav', 'helloIAmOverlay'); 69 | } 70 | } 71 | ``` 72 | 73 | #### PubSubService.$sub(event: string): Observable 74 | 75 | Subscribe to channel. 76 | 77 | etc. 78 | ```typescript 79 | export class NavigationComponent implements OnInit, OnDestroy { 80 | sideanvSub: any; 81 | 82 | constructor(private pubsub: EventDispatcherService) { } 83 | 84 | ngOnInit() { 85 | // usage of $sub(event: string): >; 86 | this.closeSidenavSub = this.pubsub.$sub('pleaseCloseSidenav').subscribe((from) => { 87 | this.sidenavOpened = false; 88 | }); 89 | 90 | // usage of $sub(event: string, callback: (value: any) => void, error?: (error: any) => void, complete?: () => void): Subscription; 91 | this.openSidenavSub = this.pubsub.$sub('pleaseOpenSidenav', (from) => { 92 | this.sidenavOpened = true; 93 | }); 94 | } 95 | ngOnDestroy() { 96 | this.closeSidenavSub.unsubscribe(); 97 | this.openSidenavSub.unsubscribe(); 98 | } 99 | ``` 100 | 101 | **See Changelog** ~~$sub method have one bug. RxJS Subscriber call subscribe method on start like Angular 1.x $scope.$watch.~~ 102 | 103 | ## Build the source 104 | 105 | Follow the steps to run the tests and build the source code. 106 | ```sh 107 | npm install 108 | npm test 109 | npm run build 110 | ``` 111 | Commands above will generate the ready to use bundles under the `./dist` folder. 112 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-pubsub", 3 | "version": "4.0.4", 4 | "description": "Pub/Sub service for Angular 2", 5 | "main": "./umd/angular2-pubsub.js", 6 | "module": "./esm/src/index.js", 7 | "typings": "./esm/src/index.d.ts", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/sqlProvider/angular2-pubsub.git" 11 | }, 12 | "scripts": { 13 | "test": "karma start", 14 | "clean": "rm -rf dist", 15 | "build-umd": "webpack --config webpack.config.umd.js", 16 | "build-angular": "ngc -p tsconfig-ngc.json", 17 | "copy-package-info": "cp ./package.json ./dist/package.json && cp ./.npmignore ./dist/.npmignore && cp ./README.md ./dist/README.md", 18 | "build": "npm run clean && npm run build-umd && npm run build-angular && npm run copy-package-info", 19 | "publish": "./publish.sh" 20 | }, 21 | "keywords": [ 22 | "Angular2", 23 | "pubsub", 24 | "angular2-service" 25 | ], 26 | "author": { 27 | "name": "Semih KEŞKEK", 28 | "email": "keskeksmh@gmail.com", 29 | "url": "http://github.com/sqlProvider" 30 | }, 31 | "contributors": [ 32 | { 33 | "name": "Mert Susur", 34 | "email": "mail@mertsusur.com", 35 | "url": "http://github.com/msusur" 36 | }, 37 | { 38 | "name": "Dustin Cleveland", 39 | "url": "https://github.com/dustincleveland" 40 | } 41 | ], 42 | "license": "ISC", 43 | "bugs": { 44 | "url": "https://github.com/sqlProvider/angular2-pubsub/issues" 45 | }, 46 | "homepage": "https://github.com/sqlProvider/angular2-pubsub#readme", 47 | "dependencies": { 48 | "@angular/common": "^4.0.0", 49 | "@angular/compiler": "^4.0.0", 50 | "@angular/core": "^4.0.0", 51 | "@angular/forms": "^4.0.0", 52 | "@angular/platform-browser": "^4.0.0", 53 | "jasmine-core": "^2.5.2", 54 | "rxjs": "^5.1.0", 55 | "ts-helpers": "^1.1.2", 56 | "zone.js": "^0.7.6" 57 | }, 58 | "devDependencies": { 59 | "@angular/compiler-cli": "^4.0.0", 60 | "@angular/platform-browser-dynamic": "^4.0.0", 61 | "@types/es6-shim": "^0.31.32", 62 | "@types/jasmine": "^2.5.41", 63 | "@types/node": "^7.0.5", 64 | "awesome-typescript-loader": "^3.0.4-rc.0", 65 | "babel-polyfill": "^6.22.0", 66 | "chai": "^3.5.0", 67 | "codelyzer": "^2.0.0", 68 | "commitizen": "^2.9.5", 69 | "compression-webpack-plugin": "^0.3.2", 70 | "extract-text-webpack-plugin": "^1.0.1", 71 | "imports-loader": "^0.7.0", 72 | "karma": "^1.4.1", 73 | "karma-chrome-launcher": "^2.0.0", 74 | "karma-coverage": "^1.1.1", 75 | "karma-jasmine": "^1.1.0", 76 | "karma-mocha-reporter": "^2.2.2", 77 | "karma-phantomjs-launcher": "^1.0.2", 78 | "karma-remap-istanbul": "^0.4.0", 79 | "karma-sourcemap-loader": "^0.3.7", 80 | "karma-typescript": "^2.1.6", 81 | "karma-webpack": "^1.8.1", 82 | "phantomjs-prebuilt": "^2.1.7", 83 | "rxjs": "^5.0.1", 84 | "sinon": "^1.17.4", 85 | "sinon-chai": "^2.8.0", 86 | "sourcemap-istanbul-instrumenter-loader": "^0.2.0", 87 | "standard-version": "^4.0.0", 88 | "stylelint-webpack-plugin": "^0.5.1", 89 | "ts-loader": "^1.3.3", 90 | "tslint": "^4.0.2", 91 | "tslint-loader": "^3.3.0", 92 | "typedoc": "^0.5.0", 93 | "typescript": "^2.1.6", 94 | "validate-commit-msg": "^2.8.0", 95 | "webpack": "^1.13.0", 96 | "webpack-dev-server": "^1.16.1", 97 | "webpack-fix-default-import-plugin": "^1.0.1", 98 | "zone.js": "^0.7.4" 99 | } 100 | } --------------------------------------------------------------------------------