├── .editorconfig ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── projects ├── demo │ ├── .browserslistrc │ ├── e2e │ │ ├── protractor.conf.js │ │ ├── src │ │ │ ├── app.e2e-spec.ts │ │ │ └── app.po.ts │ │ └── tsconfig.json │ ├── karma.conf.js │ ├── src │ │ ├── app │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── date.component.html │ │ │ └── date.component.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json └── ngx-bootstrap-datetime-popup │ ├── README.md │ ├── karma.conf.js │ ├── ng-package.json │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── lib │ │ ├── ngx-bootstrap-datetime-popup-botton-options.interface.ts │ │ ├── ngx-bootstrap-datetime-popup.component.html │ │ ├── ngx-bootstrap-datetime-popup.component.spec.ts │ │ ├── ngx-bootstrap-datetime-popup.component.ts │ │ ├── ngx-bootstrap-datetime-popup.module.ts │ │ └── offclick.directive.ts │ ├── public-api.ts │ └── test.ts │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tsconfig.base.json ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://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 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.angular/cache 2 | # Node 3 | node_modules 4 | npm-debug.log 5 | 6 | # Yarn 7 | yarn-error.log 8 | 9 | # JetBrains 10 | .idea/ 11 | 12 | # VS Code 13 | .vscode/ 14 | 15 | # Windows 16 | Thumbs.db 17 | Desktop.ini 18 | 19 | # Mac 20 | .DS_Store 21 | 22 | # Temporary files 23 | coverage/ 24 | dist 25 | docs 26 | tmp 27 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Node 2 | node_modules 3 | npm-debug.log 4 | 5 | # Yarn 6 | yarn-error.log 7 | 8 | # JetBrains 9 | .idea/ 10 | 11 | # VS Code 12 | .vscode/ 13 | 14 | # Windows 15 | Thumbs.db 16 | Desktop.ini 17 | 18 | # Mac 19 | .DS_Store 20 | 21 | # Temporary files 22 | coverage/ 23 | demo/ 24 | docs 25 | tmp 26 | 27 | # Library files 28 | src/ 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Gillardo 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NOTE: DO NOT USE 5.0.0 THIS IS BROKEN!! PLEASE USE 5.0.1+ WITH NGX-BOOTSTRAP 5.0.0+. If you require ngx-bootstrap v4+ then continue to use 4.3.0+. For angular 10, please use 6.0.0+ 2 | 3 | # ngx-bootstrap-datetime-popup 4 | Date and time popup picker using ngx-bootstrap library 5 | 6 | This is currently a very simple date time picker, with only the features i needed for a project that i use this in. Happy to add more features 7 | 8 | ![image](https://user-images.githubusercontent.com/7406381/32741384-fc825748-c89d-11e7-94d9-063cd36bcac9.png) 9 | ![image](https://user-images.githubusercontent.com/7406381/32741493-5668de62-c89e-11e7-98ce-1f718a98c3f8.png) 10 | ![image](https://user-images.githubusercontent.com/7406381/32741456-327c57f4-c89e-11e7-9f16-9023e4df5500.png) 11 | 12 | Simple example in demo folder, which can also be found on github pages at https://gillardo.github.io/ngx-bootstrap-datetime-popup/ 13 | 14 | To use the component, import the `DatetimePopupModule` via your .ts code, and add it to your modules using the .forRoot() function. You must also import the modules `datepicker`, `timepicker` and `dropdown` from `ngx-bootstrap` as there are services that are used 15 | 16 | ``` 17 | import { NgModule } from '@angular/core'; 18 | import { FormsModule } from '@angular/forms'; 19 | import { BrowserModule } from '@angular/platform-browser'; 20 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 21 | import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; 22 | import { DatepickerModule } from 'ngx-bootstrap/datepicker'; 23 | import { TimepickerModule } from 'ngx-bootstrap/timepicker'; 24 | import { DatetimePopupModule } from 'ngx-bootstrap-datetime-popup'; 25 | 26 | import { AppComponent } from './app.component'; 27 | 28 | @NgModule({ 29 | imports: [ 30 | FormsModule, 31 | BrowserModule, 32 | BrowserAnimationsModule, 33 | BsDropdownModule.forRoot(), 34 | DatepickerModule.forRoot(), 35 | TimepickerModule.forRoot(), 36 | DatetimePopupModule.forRoot() 37 | ], 38 | declarations: [ AppComponent ], 39 | bootstrap: [ AppComponent ] 40 | }) 41 | export class AppModule { 42 | 43 | } 44 | 45 | ``` 46 | 47 | Now add the component to your HTML. 48 | 49 | ``` 50 | 51 | ``` 52 | 53 | I have now added code which allows you to change attributes on the "Clear", "Now" and "Close" buttons. in order to do this, you must use an object that implements the same properties as the IDatetimePopupButtonOptions interface 54 | 55 | ``` 56 | export interface IDatetimePopupButtonOptions { 57 | // should the button be shown 58 | show: boolean; 59 | 60 | // What text label should it be given 61 | label: string; 62 | 63 | // css classes to be used, default is 'btn btn-sm btn-secondary' 64 | cssClass: string; 65 | } 66 | ``` 67 | 68 | The component accepts 3 inputs `closeButton`, `clearButton` and `nowButton`, so you can bind your options like so: 69 | 70 | ``` 71 | 72 | ``` 73 | 74 | Since i dont really like the style of the ngx-bootstrap datePicker, you can override the css like any other style, here is an example 75 | 76 | This css also overrides the glyphicon icons that are no longer used in bootstrap 4. 77 | 78 | ``` 79 | datetime-popup.dropdown .glyphicon { 80 | display: inline-block; 81 | font: normal normal normal 14px/1 FontAwesome; 82 | font-size: inherit; 83 | text-rendering: auto; 84 | -webkit-font-smoothing: antialiased; 85 | -moz-osx-font-smoothing: grayscale; 86 | } 87 | 88 | datetime-popup.dropdown timepicker { 89 | display: flex; 90 | justify-content: center; 91 | } 92 | 93 | datetime-popup.dropdown .bg-faded { 94 | border:0; 95 | background-color: #fff; 96 | } 97 | 98 | datetime-popup.dropdown datepicker button { 99 | border:0; 100 | background-color: #fff; 101 | } 102 | 103 | datetime-popup.dropdown datepicker button.active { 104 | background-color: #ddd; 105 | } 106 | 107 | datetime-popup.dropdown .glyphicon.glyphicon-remove-circle:before { 108 | content: "\f05c"; 109 | } 110 | 111 | datetime-popup.dropdown .glyphicon.glyphicon-chevron-down:before { 112 | content: "\f078"; 113 | } 114 | 115 | datetime-popup.dropdown .glyphicon.glyphicon-chevron-up:before { 116 | content: "\f077"; 117 | } 118 | 119 | datetime-popup.dropdown .glyphicon.glyphicon-chevron-left:before { 120 | content: "\f053"; 121 | } 122 | 123 | datetime-popup.dropdown .glyphicon.glyphicon-chevron-right:before { 124 | content: "\f054"; 125 | } 126 | 127 | datetime-popup.dropdown .glyphicon.hidden { 128 | display: none !important; 129 | } 130 | ``` 131 | 132 | ###Common Error 133 | If you get an error similar to this, then it because you have got a different version of ngx-bootstrap installed than this component is using. If you open the ngx-bootstrap-datetime-popup and see a node_modules folder you will probably see a folder called ngx-bootstrap inside it. 134 | ``` 135 | ERROR Error: Uncaught (in promise): Error: StaticInjectorError(AppModule)[BsDropdownDirective -> ComponentLoaderFactory]: 136 | StaticInjectorError(Platform: core)[BsDropdownDirective -> ComponentLoaderFactory]: 137 | NullInjectorError: No provider for ComponentLoaderFactory! 138 | Error: NullInjectorError: No provider for ComponentLoaderFactory! 139 | ``` 140 | 141 | If you want more features please create a PR as I am a little struck for time at the moment. Happy coding! 142 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "ngx-bootstrap-datetime-popup": { 7 | "projectType": "library", 8 | "root": "projects/ngx-bootstrap-datetime-popup", 9 | "sourceRoot": "projects/ngx-bootstrap-datetime-popup/src", 10 | "prefix": "lib", 11 | "architect": { 12 | "build": { 13 | "builder": "@angular-devkit/build-angular:ng-packagr", 14 | "options": { 15 | "tsConfig": "projects/ngx-bootstrap-datetime-popup/tsconfig.lib.json", 16 | "project": "projects/ngx-bootstrap-datetime-popup/ng-package.json" 17 | }, 18 | "configurations": { 19 | "production": { 20 | "tsConfig": "projects/ngx-bootstrap-datetime-popup/tsconfig.lib.prod.json" 21 | } 22 | }, 23 | "defaultConfiguration": "production" 24 | }, 25 | "test": { 26 | "builder": "@angular-devkit/build-angular:karma", 27 | "options": { 28 | "main": "projects/ngx-bootstrap-datetime-popup/src/test.ts", 29 | "tsConfig": "projects/ngx-bootstrap-datetime-popup/tsconfig.spec.json", 30 | "karmaConfig": "projects/ngx-bootstrap-datetime-popup/karma.conf.js" 31 | } 32 | } 33 | } 34 | }, 35 | "demo": { 36 | "projectType": "application", 37 | "schematics": { 38 | "@schematics/angular:component": { 39 | "style": "scss" 40 | } 41 | }, 42 | "root": "projects/demo", 43 | "sourceRoot": "projects/demo/src", 44 | "prefix": "app", 45 | "architect": { 46 | "build": { 47 | "builder": "@angular-devkit/build-angular:browser", 48 | "options": { 49 | "outputPath": "dist/demo", 50 | "index": "projects/demo/src/index.html", 51 | "main": "projects/demo/src/main.ts", 52 | "polyfills": "projects/demo/src/polyfills.ts", 53 | "tsConfig": "projects/demo/tsconfig.app.json", 54 | "assets": [ 55 | "projects/demo/src/favicon.ico", 56 | "projects/demo/src/assets" 57 | ], 58 | "styles": [ 59 | "projects/demo/src/styles.scss" 60 | ], 61 | "scripts": [], 62 | "vendorChunk": true, 63 | "extractLicenses": false, 64 | "buildOptimizer": false, 65 | "sourceMap": true, 66 | "optimization": false, 67 | "namedChunks": true 68 | }, 69 | "configurations": { 70 | "production": { 71 | "fileReplacements": [ 72 | { 73 | "replace": "projects/demo/src/environments/environment.ts", 74 | "with": "projects/demo/src/environments/environment.prod.ts" 75 | } 76 | ], 77 | "optimization": true, 78 | "outputHashing": "all", 79 | "sourceMap": false, 80 | "namedChunks": false, 81 | "extractLicenses": true, 82 | "vendorChunk": false, 83 | "buildOptimizer": true, 84 | "budgets": [ 85 | { 86 | "type": "initial", 87 | "maximumWarning": "2mb", 88 | "maximumError": "5mb" 89 | }, 90 | { 91 | "type": "anyComponentStyle", 92 | "maximumWarning": "6kb", 93 | "maximumError": "10kb" 94 | } 95 | ] 96 | } 97 | }, 98 | "defaultConfiguration": "" 99 | }, 100 | "serve": { 101 | "builder": "@angular-devkit/build-angular:dev-server", 102 | "options": { 103 | "browserTarget": "demo:build" 104 | }, 105 | "configurations": { 106 | "production": { 107 | "browserTarget": "demo:build:production" 108 | } 109 | } 110 | }, 111 | "extract-i18n": { 112 | "builder": "@angular-devkit/build-angular:extract-i18n", 113 | "options": { 114 | "browserTarget": "demo:build" 115 | } 116 | }, 117 | "test": { 118 | "builder": "@angular-devkit/build-angular:karma", 119 | "options": { 120 | "main": "projects/demo/src/test.ts", 121 | "polyfills": "projects/demo/src/polyfills.ts", 122 | "tsConfig": "projects/demo/tsconfig.spec.json", 123 | "karmaConfig": "projects/demo/karma.conf.js", 124 | "assets": [ 125 | "projects/demo/src/favicon.ico", 126 | "projects/demo/src/assets" 127 | ], 128 | "styles": [ 129 | "projects/demo/src/styles.scss" 130 | ], 131 | "scripts": [] 132 | } 133 | }, 134 | "e2e": { 135 | "builder": "@angular-devkit/build-angular:protractor", 136 | "options": { 137 | "protractorConfig": "projects/demo/e2e/protractor.conf.js", 138 | "devServerTarget": "demo:serve" 139 | }, 140 | "configurations": { 141 | "production": { 142 | "devServerTarget": "demo:serve:production" 143 | } 144 | } 145 | }, 146 | "deploy": { 147 | "builder": "angular-cli-ghpages:deploy", 148 | "options": { 149 | "baseHref": "https://gillardo.github.io/ngx-bootstrap-datetime-popup/", 150 | "repo": "https://github.com/Gillardo/ngx-bootstrap-datetime-popup.git" 151 | } 152 | } 153 | } 154 | }}, 155 | "defaultProject": "ngx-bootstrap-datetime-popup" 156 | } 157 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-bootstrap-datetime-popup", 3 | "version": "7.0.4", 4 | "author": { 5 | "name": "Darren Gillard", 6 | "email": "darren.gillard81@gmail.com" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/gillardo/ngx-bootstrap-datetime-popup" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/gillardo/ngx-bootstrap-datetime-popup/issues" 14 | }, 15 | "license": "MIT", 16 | "url": "https://github.com/gillardo/ngx-bootstrap-datetime-popup#readme", 17 | "main": "./dist/bundles/ngx-bootstrap-datetime-popup.umd.js", 18 | "module": "./dist/esm5/ngx-bootstrap-datetime-popup.js", 19 | "typings": "./dist/ngx-bootstrap-datetime-popup.d.ts", 20 | "scripts": { 21 | "ng": "ng", 22 | "update": "ng update @angular/cli", 23 | "start": "ng serve", 24 | "build": "ng build ngx-bootstrap-datetime-popup", 25 | "test": "ng test", 26 | "lint": "ng lint", 27 | "e2e": "ng e2e", 28 | "watch": "ng serve demo --port 4300", 29 | "gh-pages": "ng deploy demo --no-silent", 30 | "publish": "npm run build && cd dist && npm publish" 31 | }, 32 | "dependencies": { 33 | "@angular/animations": "^13.1.0", 34 | "@angular/common": "^13.1.0", 35 | "@angular/compiler": "^13.1.0", 36 | "@angular/core": "^13.1.0", 37 | "@angular/forms": "^13.1.0", 38 | "@angular/platform-browser": "^13.1.0", 39 | "@angular/platform-browser-dynamic": "^13.1.0", 40 | "@angular/router": "^13.1.0", 41 | "ngx-bootstrap": "^7.1.0", 42 | "rxjs": "^6.5.4", 43 | "tslib": "^2.3.1", 44 | "zone.js": "~0.11.4" 45 | }, 46 | "devDependencies": { 47 | "@angular-devkit/build-angular": "^13.1.1", 48 | "@angular/cli": "^13.1.1", 49 | "@angular/compiler-cli": "^13.1.0", 50 | "@angular/language-service": "^13.1.0", 51 | "@types/jasmine": "~3.6.0", 52 | "@types/jasminewd2": "^2.0.3", 53 | "@types/node": "^12.11.1", 54 | "angular-cli-ghpages": "^0.6.2", 55 | "codelyzer": "^6.0.0", 56 | "jasmine-core": "~3.6.0", 57 | "jasmine-spec-reporter": "~5.0.0", 58 | "karma": "~6.3.9", 59 | "karma-chrome-launcher": "~3.1.0", 60 | "karma-coverage-istanbul-reporter": "~3.0.2", 61 | "karma-jasmine": "~4.0.0", 62 | "karma-jasmine-html-reporter": "^1.5.0", 63 | "ng-packagr": "^13.1.1", 64 | "protractor": "~7.0.0", 65 | "ts-node": "^8.3.0", 66 | "tslint": "~6.1.0", 67 | "typescript": "^4.5.4" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /projects/demo/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /projects/demo/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /projects/demo/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('demo app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /projects/demo/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo(): Promise { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText(): Promise { 9 | return element(by.css('app-root .content span')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../../../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es2018", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /projects/demo/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/demo'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Select a date

3 |
4 |
5 | 6 | 7 |
8 |
9 |
10 | Selected date: {{ localValue1 }} 11 |
12 | 13 |
14 |

Select a time

15 |
16 |
17 | 18 | 19 |
20 |
21 |
22 | Selected date: {{ localValue2 }} 23 |
24 | 25 |
26 |

Select a date and time

27 |
28 |
29 | 30 | 31 |
32 |
33 |
34 | Selected date: {{ localValue3 }} 35 |
36 | 37 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gillardo/ngx-bootstrap-datetime-popup/1fa36507fbd7819295129be40327a6b96244a1ec/projects/demo/src/app/app.component.scss -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationModule } from '@angular/core'; 2 | import { TestBed, waitForAsync } from '@angular/core/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach( 7 | waitForAsync(() => { 8 | TestBed.configureTestingModule({ 9 | imports: [ApplicationModule], 10 | }).compileComponents(); 11 | }) 12 | ); 13 | 14 | it('should create the app', () => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.componentInstance; 17 | expect(app).toBeTruthy(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | public localValue1: Date = null; 10 | public showPicker1 = false; 11 | public localValue2: Date = null; 12 | public showPicker2 = false; 13 | public localValue3: Date = null; 14 | public showPicker3 = false; 15 | } 16 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 5 | import { BsDatepickerModule, DatepickerModule } from 'ngx-bootstrap/datepicker'; 6 | import { TimepickerModule } from 'ngx-bootstrap/timepicker'; 7 | import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; 8 | import { DatetimePopupModule } from 'projects/ngx-bootstrap-datetime-popup/src/public-api'; 9 | 10 | import { AppComponent } from './app.component'; 11 | 12 | @NgModule({ 13 | declarations: [AppComponent], 14 | imports: [ 15 | BrowserModule, 16 | BrowserAnimationsModule, 17 | FormsModule, 18 | BsDatepickerModule.forRoot(), 19 | DatepickerModule.forRoot(), 20 | TimepickerModule.forRoot(), 21 | BsDropdownModule.forRoot(), 22 | DatetimePopupModule, 23 | ], 24 | bootstrap: [AppComponent], 25 | }) 26 | export class AppModule {} 27 | -------------------------------------------------------------------------------- /projects/demo/src/app/date.component.html: -------------------------------------------------------------------------------- 1 |
2 | 10 | 11 | 19 | 20 |
21 | 24 |
25 |
26 | -------------------------------------------------------------------------------- /projects/demo/src/app/date.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'input-date', 5 | templateUrl: './date.component.html' 6 | }) 7 | 8 | export class DateComponent { 9 | 10 | @Input() 11 | public name: string; 12 | 13 | @Input() 14 | public showDate = true; 15 | 16 | @Input() 17 | public showTime = false; 18 | 19 | @Input() 20 | public defaultTimeEndOfDay = false; 21 | 22 | @Input() 23 | public appendTo: string = undefined; 24 | 25 | @Input() 26 | public value: Date; 27 | 28 | @Input() 29 | public minDate: Date = null; 30 | 31 | @Input() 32 | public maxDate: Date = null; 33 | 34 | @Input() 35 | public placeholder = ''; 36 | 37 | @Output() 38 | public valueChange = new EventEmitter(); 39 | 40 | @Input() 41 | public showPicker = false; 42 | 43 | @Output() 44 | public showPickerChange = new EventEmitter(); 45 | 46 | public onBlur(value: string) { 47 | console.log('blur event'); 48 | } 49 | 50 | public onFocus($event: any) { 51 | $event.stopPropagation(); 52 | $event.preventDefault(); 53 | 54 | this.showPicker = true; 55 | this.showPickerChange.emit(true); 56 | } 57 | 58 | public onChange(value: string) { 59 | this.valueChange.emit(value); 60 | } 61 | 62 | public onTogglePicker($event, showPicker) { 63 | $event.stopPropagation(); 64 | $event.preventDefault(); 65 | 66 | this.showPicker = showPicker; 67 | this.showPickerChange.emit(showPicker); 68 | } 69 | 70 | public onPopupChange(val: Date) { 71 | // if we're going from NULL to a DATE default the time to the end of the day 72 | if (this.value == null && val != null && this.defaultTimeEndOfDay) { 73 | val.setHours(23, 59, 59, 0); 74 | } 75 | 76 | this.valueChange.emit(val); 77 | 78 | if (this.showDate === true && this.showTime === false) { 79 | this.showPicker = false; 80 | this.showPickerChange.emit(false); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /projects/demo/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gillardo/ngx-bootstrap-datetime-popup/1fa36507fbd7819295129be40327a6b96244a1ec/projects/demo/src/assets/.gitkeep -------------------------------------------------------------------------------- /projects/demo/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /projects/demo/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /projects/demo/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gillardo/ngx-bootstrap-datetime-popup/1fa36507fbd7819295129be40327a6b96244a1ec/projects/demo/src/favicon.ico -------------------------------------------------------------------------------- /projects/demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

ngx-bootstrap-datetime-picker demo

17 |

Demo pages to show features of datetime picker

18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /projects/demo/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 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /projects/demo/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/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /projects/demo/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /projects/demo/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/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), { 21 | teardown: { destroyAfterEach: false } 22 | } 23 | ); 24 | // Then we find all the tests. 25 | const context = require.context('./', true, /\.spec\.ts$/); 26 | // And load the modules. 27 | context.keys().map(context); 28 | -------------------------------------------------------------------------------- /projects/demo/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /projects/demo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | ], 13 | "include": [ 14 | "src/**/*.spec.ts", 15 | "src/**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/demo/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "camelCase" 8 | ], 9 | "component-selector": [ 10 | true, 11 | "element", 12 | "kebab-case" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/README.md: -------------------------------------------------------------------------------- 1 | ## NOTES 2 | - DO NOT USE 5.0.0 THIS IS BROKEN!! PLEASE USE 5.0.1 WITH NGX-BOOTSTRAP 5.0.0. If you require ngx-bootstrap v4+ then continue to use 4.3.0+ 3 | - VERSION 6.0.0+ of this library uses a Library template built from Angular/Cli so it will be compatible with Ivy 4 | 5 | 6 | # ngx-bootstrap-datetime-popup 7 | Date and time popup picker using ngx-bootstrap library 8 | 9 | This is currently a very simple date time picker, with only the features i needed for a project that i use this in. Happy to add more features 10 | 11 | ![image](https://user-images.githubusercontent.com/7406381/32741384-fc825748-c89d-11e7-94d9-063cd36bcac9.png) 12 | ![image](https://user-images.githubusercontent.com/7406381/32741493-5668de62-c89e-11e7-98ce-1f718a98c3f8.png) 13 | ![image](https://user-images.githubusercontent.com/7406381/32741456-327c57f4-c89e-11e7-9f16-9023e4df5500.png) 14 | 15 | Simple example in demo folder, which can also be found on github pages at https://gillardo.github.io/ngx-bootstrap-datetime-popup/ 16 | 17 | To use the component, import the `DatetimePopupModule` via your .ts code, and add it to your modules using `forRoot()` method. You must also import the modules `datepicker`, `timepicker` and `dropdown` from `ngx-bootstrap` as there are services that are used 18 | 19 | ``` 20 | import { NgModule } from '@angular/core'; 21 | import { FormsModule } from '@angular/forms'; 22 | import { BrowserModule } from '@angular/platform-browser'; 23 | import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; 24 | import { DatepickerModule } from 'ngx-bootstrap/datepicker'; 25 | import { TimepickerModule } from 'ngx-bootstrap/timepicker'; 26 | import { NgxBootstrapDatetimePopupModule } from 'ngx-bootstrap-datetime-popup'; 27 | 28 | import { AppComponent } from './app.component'; 29 | 30 | @NgModule({ 31 | imports: [ 32 | FormsModule, 33 | BrowserModule, 34 | BsDropdownModule.forRoot(), 35 | DatepickerModule.forRoot(), 36 | TimepickerModule.forRoot(), 37 | NgxBootstrapDatetimePopupModule.forRoot() 38 | ], 39 | declarations: [ AppComponent ], 40 | bootstrap: [ AppComponent ] 41 | }) 42 | export class AppModule { 43 | 44 | } 45 | 46 | ``` 47 | 48 | Now add the component to your HTML. 49 | 50 | ``` 51 | 52 | ``` 53 | 54 | I have now added code so you can change attributes on the "Clear", "Now" and "Close" buttons. in order to do this, you must use an object that implements the same properties as the INgxBootstrapDatetimePopupButtonOptions interface 55 | 56 | ``` 57 | export interface INgxBootstrapDatetimePopupButtonOptions { 58 | // should the button be shown 59 | show: boolean; 60 | 61 | // What text label should it be given 62 | label: string; 63 | 64 | // css classes to be used, default is 'btn btn-sm btn-secondary' 65 | cssClass: string; 66 | } 67 | ``` 68 | 69 | The component accepts 3 inputs `closeButton`, `clearButton` and `nowButton`, so you can bind your options like so: 70 | 71 | ``` 72 | 73 | ``` 74 | 75 | Since i dont really like the style of the ngx-bootstrap datePicker, you can override the css like any other style, here is an example 76 | 77 | This css also overrides the glyphicon icons that are no longer used in bootstrap 4. 78 | 79 | ``` 80 | ngx-bootstrap-datetime-popup.dropdown .glyphicon { 81 | display: inline-block; 82 | font: normal normal normal 14px/1 FontAwesome; 83 | font-size: inherit; 84 | text-rendering: auto; 85 | -webkit-font-smoothing: antialiased; 86 | -moz-osx-font-smoothing: grayscale; 87 | } 88 | 89 | ngx-bootstrap-datetime-popup.dropdown timepicker { 90 | display: flex; 91 | justify-content: center; 92 | } 93 | 94 | ngx-bootstrap-datetime-popup.dropdown .bg-faded { 95 | border:0; 96 | background-color: #fff; 97 | } 98 | 99 | ngx-bootstrap-datetime-popup.dropdown datepicker button { 100 | border:0; 101 | background-color: #fff; 102 | } 103 | 104 | ngx-bootstrap-datetime-popup.dropdown datepicker button.active { 105 | background-color: #ddd; 106 | } 107 | 108 | ngx-bootstrap-datetime-popup.dropdown .glyphicon.glyphicon-remove-circle:before { 109 | content: "\f05c"; 110 | } 111 | 112 | ngx-bootstrap-datetime-popup.dropdown .glyphicon.glyphicon-chevron-down:before { 113 | content: "\f078"; 114 | } 115 | 116 | ngx-bootstrap-datetime-popup.dropdown .glyphicon.glyphicon-chevron-up:before { 117 | content: "\f077"; 118 | } 119 | 120 | ngx-bootstrap-datetime-popup.dropdown .glyphicon.glyphicon-chevron-left:before { 121 | content: "\f053"; 122 | } 123 | 124 | ngx-bootstrap-datetime-popup.dropdown .glyphicon.glyphicon-chevron-right:before { 125 | content: "\f054"; 126 | } 127 | 128 | ngx-bootstrap-datetime-popup.dropdown .glyphicon.hidden { 129 | display: none !important; 130 | } 131 | ``` 132 | 133 | If you want more features please create a PR as i am a little struck for time at the moment. Happy coding! 134 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/ngx-bootstrap-datetime-popup'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist", 4 | "lib": { 5 | "entryFile": "src/public-api.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-bootstrap-datetime-popup", 3 | "version": "5.1.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-bootstrap-datetime-popup", 3 | "version": "7.0.4", 4 | "description": "Datetime popup component using ngx-bootstrap datePicker, timePicker and bsDropdown", 5 | "keywords": [ 6 | "angular", 7 | "angular10", 8 | "aot", 9 | "aot-compatible", 10 | "aot-compilation", 11 | "library", 12 | "ng", 13 | "timepicker", 14 | "datepicker", 15 | "ngx-bootstrap", 16 | "ngx-bootstrap-datetime-popup", 17 | "typescript" 18 | ], 19 | "peerDependencies": { 20 | "@angular/common": "^12.0.0 || ^13.0.0", 21 | "@angular/core": "^12.0.0 || ^13.0.0", 22 | "@angular/forms": "^12.0.0 || ^13.0.0", 23 | "ngx-bootstrap": "^7.0.0" 24 | }, 25 | "dependencies": { 26 | "tslib": "^2.0.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/src/lib/ngx-bootstrap-datetime-popup-botton-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IDatetimePopupButtonOptions { 2 | show: boolean; 3 | label: string; 4 | cssClass: string; 5 | } 6 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/src/lib/ngx-bootstrap-datetime-popup.component.html: -------------------------------------------------------------------------------- 1 |
2 | 42 |
43 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/src/lib/ngx-bootstrap-datetime-popup.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import { DatetimePopupComponent } from './ngx-bootstrap-datetime-popup.component'; 4 | 5 | describe('NgxBootstrapDatetimePopupComponent', () => { 6 | let component: DatetimePopupComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach( 10 | waitForAsync(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [DatetimePopupComponent], 13 | }).compileComponents(); 14 | }) 15 | ); 16 | 17 | beforeEach(() => { 18 | fixture = TestBed.createComponent(DatetimePopupComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/src/lib/ngx-bootstrap-datetime-popup.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | ElementRef, 4 | EventEmitter, HostListener, 5 | Input, 6 | OnChanges, 7 | Output, 8 | ViewChild 9 | } from '@angular/core'; 10 | import { IDatetimePopupButtonOptions } from './ngx-bootstrap-datetime-popup-botton-options.interface'; 11 | import { BsDropdownDirective } from 'ngx-bootstrap/dropdown'; 12 | 13 | @Component({ 14 | selector: 'datetime-popup', 15 | templateUrl: './ngx-bootstrap-datetime-popup.component.html' , 16 | styles: [ 17 | ], 18 | }) 19 | 20 | export class DatetimePopupComponent implements OnChanges { 21 | 22 | @ViewChild('dropdown', { static: true }) 23 | public dropdown: BsDropdownDirective; 24 | 25 | @Input() 26 | public appendTo: string = undefined; 27 | 28 | @Input() 29 | public value: Date; 30 | 31 | @Output() 32 | public valueChange = new EventEmitter(); 33 | 34 | @Input() 35 | public showPopup = false; 36 | 37 | @Output() 38 | public showPopupChange = new EventEmitter(); 39 | 40 | @Input() 41 | public showDate = true; 42 | 43 | @Input() 44 | public showTime = true; 45 | 46 | @Input() 47 | public showWeeks = false; 48 | 49 | @Input() 50 | public showMeridian = false; 51 | 52 | @Input() 53 | public showSeconds = false; 54 | 55 | @Input() 56 | public datepickerMode = 'day'; 57 | 58 | @Input() 59 | public initDate: Date = null; 60 | 61 | @Input() 62 | public minDate: Date = null; 63 | 64 | @Input() 65 | public maxDate: Date = null; 66 | 67 | @Input() 68 | public dateDisabled: any[] = []; 69 | 70 | @Input() 71 | public nowButton: IDatetimePopupButtonOptions; 72 | 73 | @Input() 74 | public clearButton: IDatetimePopupButtonOptions; 75 | 76 | @Input() 77 | public closeButton: IDatetimePopupButtonOptions; 78 | 79 | @Input() 80 | public minuteStep = 5; 81 | 82 | @Input() 83 | public hourStep = 1; 84 | 85 | @Input() 86 | public secondsStep = 1; 87 | 88 | public localValue: Date = null; 89 | public isOpening = false; 90 | public isDropUp = false; 91 | 92 | constructor(private elementRef: ElementRef) { 93 | 94 | } 95 | 96 | public ngOnChanges(changes: any) { 97 | if (!this.nowButton) { 98 | this.nowButton = { show: true, label: 'Now', cssClass: 'btn btn-secondary btn-sm'}; 99 | } 100 | 101 | if (!this.clearButton) { 102 | this.clearButton = { show: true, label: 'Clear', cssClass: 'btn btn-secondary btn-sm'}; 103 | } 104 | 105 | if (!this.closeButton) { 106 | this.closeButton = { show: true, label: 'Close', cssClass: 'btn btn-secondary btn-sm'}; 107 | } 108 | 109 | // user maybe typing a value into an input box, so would come in as string 110 | if (typeof this.value === 'string') { 111 | // check if the string is a valid date 112 | if (!isNaN(new Date(this.value).getTime())) { 113 | this.localValue = new Date(this.value); 114 | } 115 | } else if (this.value) { 116 | this.localValue = this.value; 117 | } 118 | 119 | if (changes.showPopup && this.dropdown) { 120 | if (changes.showPopup.currentValue === true) { 121 | this.dropdown.show(); 122 | } else if (changes.showPopup.currentValue === false) { 123 | this.dropdown.hide(); 124 | } 125 | } 126 | } 127 | 128 | @HostListener('window:scroll', []) 129 | @HostListener('window:resize', []) 130 | public onWindowScroll() { 131 | const nativeEl: HTMLElement = this.elementRef.nativeElement; 132 | const clientRect: ClientRect = nativeEl.getBoundingClientRect(); 133 | const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; 134 | const offsetTop = clientRect.top + window.pageYOffset; 135 | const height = clientRect.height; 136 | const dropdownEl: HTMLElement = nativeEl.children.item(0) as HTMLElement; 137 | const menuEl: HTMLElement = dropdownEl.children.length > 0 ? dropdownEl.children.item(0) as HTMLElement : null; 138 | let menuHeight = this.showDate && this.showTime ? 402 : this.showDate ? 300 : 102; 139 | 140 | if (menuEl != null) { 141 | // get the style 142 | const display = menuEl.style.display; 143 | menuEl.style.display = 'block'; 144 | 145 | menuHeight = menuEl.getBoundingClientRect().height; 146 | menuEl.style.display = display; 147 | } 148 | 149 | if ((offsetTop - menuHeight) <= 0) { 150 | this.isDropUp = false; 151 | } else { 152 | this.isDropUp = ((offsetTop + height + menuHeight) > (scrollTop + document.documentElement.clientHeight)); 153 | } 154 | } 155 | 156 | public onOpenChange(opened: boolean) { 157 | if (opened === true) { 158 | this.isOpening = true; 159 | this.onWindowScroll(); 160 | this.dropdown.show(); 161 | 162 | setTimeout(() => this.isOpening = false, 250); 163 | } else { 164 | this.showPopupChange.emit(false); 165 | } 166 | } 167 | 168 | public onNow() { 169 | this.localValue = new Date(); 170 | this.onPickerChange('timepicker'); 171 | } 172 | 173 | public onClear() { 174 | this.valueChange.emit(null); 175 | } 176 | 177 | public onClose() { 178 | this.showPopupChange.emit(false); 179 | } 180 | 181 | public onOffClick($event: any) { 182 | this.showPopupChange.emit(false); 183 | } 184 | 185 | public onPickerChange(picker: string) { 186 | if (this.isOpening === true) { 187 | return; 188 | } 189 | 190 | if (picker === 'datepicker' && this.value != null) { 191 | const hours = this.value.getHours(); 192 | const minutes = this.value.getMinutes(); 193 | const seconds = this.value.getSeconds(); 194 | const milliseconds = this.value.getMilliseconds(); 195 | 196 | this.localValue.setHours(hours, minutes, seconds, milliseconds); 197 | } 198 | 199 | this.valueChange.emit(this.localValue); 200 | 201 | if (this.showDate === true && this.showTime === false) { 202 | this.dropdown.hide(); 203 | } 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/src/lib/ngx-bootstrap-datetime-popup.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BsDatepickerConfig, BsDatepickerModule, DatepickerModule } from 'ngx-bootstrap/datepicker'; 5 | import { BsDropdownConfig, BsDropdownModule } from 'ngx-bootstrap/dropdown'; 6 | import { TimepickerModule } from 'ngx-bootstrap/timepicker'; 7 | import { DatetimePopupComponent } from './ngx-bootstrap-datetime-popup.component'; 8 | import { OffClickDirective } from './offclick.directive'; 9 | 10 | @NgModule({ 11 | declarations: [DatetimePopupComponent, OffClickDirective], 12 | imports: [ 13 | CommonModule, 14 | FormsModule, 15 | DatepickerModule, 16 | TimepickerModule, 17 | BsDatepickerModule, 18 | BsDropdownModule, 19 | ], 20 | exports: [DatetimePopupComponent], 21 | providers: [BsDatepickerConfig, BsDropdownConfig] 22 | }) 23 | export class DatetimePopupModule {} 24 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/src/lib/offclick.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[offClick]' 5 | }) 6 | 7 | export class OffClickDirective implements OnInit, OnDestroy { 8 | @Output() 9 | public offClick = new EventEmitter(); 10 | 11 | public eventHandler: any; 12 | constructor(private elementRef: ElementRef) { 13 | 14 | } 15 | 16 | ngOnInit() { 17 | this.eventHandler = ($event: any) => { 18 | $event.stopPropagation(); 19 | 20 | if (!this.elementRef.nativeElement.contains($event.target) && $event.target.localName !== 'button') { 21 | this.offClick.emit(null); 22 | } 23 | }; 24 | 25 | document.addEventListener('mouseup', this.eventHandler); 26 | } 27 | 28 | ngOnDestroy() { 29 | document.removeEventListener('mouseup', this.eventHandler); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ngx-bootstrap-datetime-popup 3 | */ 4 | 5 | export * from './lib/ngx-bootstrap-datetime-popup.component'; 6 | export * from './lib/ngx-bootstrap-datetime-popup.module'; 7 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/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'; 4 | import 'zone.js/testing'; 5 | import { getTestBed } from '@angular/core/testing'; 6 | import { 7 | BrowserDynamicTestingModule, 8 | platformBrowserDynamicTesting 9 | } from '@angular/platform-browser-dynamic/testing'; 10 | 11 | declare const require: { 12 | context(path: string, deep?: boolean, filter?: RegExp): { 13 | keys(): string[]; 14 | (id: string): T; 15 | }; 16 | }; 17 | 18 | // First, initialize the Angular testing environment. 19 | getTestBed().initTestEnvironment( 20 | BrowserDynamicTestingModule, 21 | platformBrowserDynamicTesting(), { 22 | teardown: { destroyAfterEach: false } 23 | } 24 | ); 25 | // Then we find all the tests. 26 | const context = require.context('./', true, /\.spec\.ts$/); 27 | // And load the modules. 28 | context.keys().map(context); 29 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": [ 11 | "dom", 12 | "es2018" 13 | ] 14 | }, 15 | "angularCompilerOptions": { 16 | "skipTemplateCodegen": true, 17 | "strictMetadataEmit": true, 18 | "enableResourceInlining": true 19 | }, 20 | "exclude": [ 21 | "src/test.ts", 22 | "**/*.spec.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "compilationMode": "partial" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/ngx-bootstrap-datetime-popup/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "camelCase" 8 | ], 9 | "component-selector": [ 10 | true, 11 | "element", 12 | "kebab-case" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "es2020", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "lib": [ 15 | "es2018", 16 | "dom" 17 | ], 18 | }, 19 | "angularCompilerOptions": { 20 | "fullTemplateTypeCheck": true, 21 | "strictInjectionParameters": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* 2 | This is a "Solution Style" tsconfig.json file, and is used by editors and TypeScript’s language server to improve development experience. 3 | It is not intended to be used to perform a compilation. 4 | 5 | To learn more about this file see: https://angular.io/config/solution-tsconfig. 6 | */ 7 | { 8 | "files": [], 9 | "references": [ 10 | { 11 | "path": "./projects/ngx-bootstrap-datetime-popup/tsconfig.lib.json" 12 | }, 13 | { 14 | "path": "./projects/ngx-bootstrap-datetime-popup/tsconfig.spec.json" 15 | }, 16 | { 17 | "path": "./projects/demo/tsconfig.app.json" 18 | }, 19 | { 20 | "path": "./projects/demo/tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "codelyzer" 5 | ], 6 | "rules": { 7 | "align": { 8 | "options": [ 9 | "parameters", 10 | "statements" 11 | ] 12 | }, 13 | "array-type": false, 14 | "arrow-return-shorthand": true, 15 | "curly": true, 16 | "deprecation": { 17 | "severity": "warning" 18 | }, 19 | "eofline": true, 20 | "import-blacklist": [ 21 | true, 22 | "rxjs/Rx" 23 | ], 24 | "import-spacing": true, 25 | "indent": { 26 | "options": [ 27 | "spaces" 28 | ] 29 | }, 30 | "max-classes-per-file": false, 31 | "max-line-length": [ 32 | true, 33 | 140 34 | ], 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-empty": false, 55 | "no-inferrable-types": [ 56 | true, 57 | "ignore-params" 58 | ], 59 | "no-non-null-assertion": true, 60 | "no-redundant-jsdoc": true, 61 | "no-switch-case-fall-through": true, 62 | "no-var-requires": false, 63 | "object-literal-key-quotes": [ 64 | true, 65 | "as-needed" 66 | ], 67 | "quotemark": [ 68 | true, 69 | "single" 70 | ], 71 | "semicolon": { 72 | "options": [ 73 | "always" 74 | ] 75 | }, 76 | "space-before-function-paren": { 77 | "options": { 78 | "anonymous": "never", 79 | "asyncArrow": "always", 80 | "constructor": "never", 81 | "method": "never", 82 | "named": "never" 83 | } 84 | }, 85 | "typedef-whitespace": { 86 | "options": [ 87 | { 88 | "call-signature": "nospace", 89 | "index-signature": "nospace", 90 | "parameter": "nospace", 91 | "property-declaration": "nospace", 92 | "variable-declaration": "nospace" 93 | }, 94 | { 95 | "call-signature": "onespace", 96 | "index-signature": "onespace", 97 | "parameter": "onespace", 98 | "property-declaration": "onespace", 99 | "variable-declaration": "onespace" 100 | } 101 | ] 102 | }, 103 | "variable-name": { 104 | "options": [ 105 | "ban-keywords", 106 | "check-format", 107 | "allow-pascal-case" 108 | ] 109 | }, 110 | "whitespace": { 111 | "options": [ 112 | "check-branch", 113 | "check-decl", 114 | "check-operator", 115 | "check-separator", 116 | "check-type", 117 | "check-typecast" 118 | ] 119 | }, 120 | "component-class-suffix": true, 121 | "contextual-lifecycle": true, 122 | "directive-class-suffix": true, 123 | "no-conflicting-lifecycle": true, 124 | "no-host-metadata-property": true, 125 | "no-input-rename": true, 126 | "no-inputs-metadata-property": true, 127 | "no-output-native": true, 128 | "no-output-on-prefix": true, 129 | "no-output-rename": true, 130 | "no-outputs-metadata-property": true, 131 | "template-banana-in-box": true, 132 | "template-no-negated-async": true, 133 | "use-lifecycle-interface": true, 134 | "use-pipe-transform-interface": true 135 | } 136 | } 137 | --------------------------------------------------------------------------------