├── .all-contributorsrc ├── .editorconfig ├── .github ├── dependabot-github-actions.yaml └── workflows │ ├── ci.yml │ └── test-angular-versions.yaml ├── .gitignore ├── .jsbeautifyrc ├── LICENSE ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── projects └── ngx-intl-tel-input │ ├── karma.conf.js │ ├── ng-package.json │ ├── package.json │ ├── src │ ├── lib │ │ ├── bootstrap-dropdown.css │ │ ├── data │ │ │ └── country-code.ts │ │ ├── directives │ │ │ └── native-element-injector.directive.ts │ │ ├── enums │ │ │ ├── country-iso.enum.ts │ │ │ ├── phone-number-format.enum.ts │ │ │ └── search-country-field.enum.ts │ │ ├── interfaces │ │ │ └── change-data.ts │ │ ├── model │ │ │ └── country.model.ts │ │ ├── ngx-intl-tel-input.component.css │ │ ├── ngx-intl-tel-input.component.html │ │ ├── ngx-intl-tel-input.component.spec.ts │ │ ├── ngx-intl-tel-input.component.ts │ │ ├── ngx-intl-tel-input.module.ts │ │ └── ngx-intl-tel-input.validator.ts │ ├── public_api.ts │ └── test.ts │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── readme-assets └── ngx-intl-tel-input.jpg ├── src ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ └── app.module.ts ├── assets │ └── .gitkeep ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── karma.conf.js ├── main.ts ├── polyfills.ts ├── styles.css ├── test.ts ├── tsconfig.app.json └── tsconfig.spec.json └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "ngx-intl-tel-input", 3 | "projectOwner": "webcat12345", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": false, 11 | "contributors": [ 12 | { 13 | "login": "webcat12345", 14 | "name": "webcat_black", 15 | "avatar_url": "https://avatars3.githubusercontent.com/u/19761422?v=4", 16 | "profile": "https://github.com/webcat12345", 17 | "contributions": [ 18 | "design", 19 | "code", 20 | "doc", 21 | "ideas", 22 | "question", 23 | "infra", 24 | "example", 25 | "maintenance", 26 | "review", 27 | "test" 28 | ] 29 | }, 30 | { 31 | "login": "cmckni3", 32 | "name": "Chris McKnight", 33 | "avatar_url": "https://avatars0.githubusercontent.com/u/735717?v=4", 34 | "profile": "https://github.com/cmckni3", 35 | "contributions": [ 36 | "question", 37 | "code", 38 | "doc", 39 | "ideas", 40 | "infra", 41 | "plugin", 42 | "review", 43 | "tool" 44 | ] 45 | }, 46 | { 47 | "login": "pasevin", 48 | "name": "Aleksandr Pasevin", 49 | "avatar_url": "https://avatars2.githubusercontent.com/u/1058469?v=4", 50 | "profile": "http://pasevin.com", 51 | "contributions": [ 52 | "code", 53 | "doc", 54 | "bug", 55 | "platform", 56 | "plugin", 57 | "question", 58 | "infra", 59 | "example", 60 | "maintenance", 61 | "review", 62 | "test" 63 | ] 64 | }, 65 | { 66 | "login": "Dviejopomata", 67 | "name": "Dviejo", 68 | "avatar_url": "https://avatars0.githubusercontent.com/u/6862893?v=4", 69 | "profile": "https://github.com/Dviejopomata", 70 | "contributions": [ 71 | "code", 72 | "bug", 73 | "example", 74 | "test", 75 | "question", 76 | "maintenance", 77 | "review" 78 | ] 79 | }, 80 | { 81 | "login": "kinoroy", 82 | "name": "Kino Roy", 83 | "avatar_url": "https://avatars3.githubusercontent.com/u/22554212?v=4", 84 | "profile": "http://kino.codes", 85 | "contributions": [ 86 | "code" 87 | ] 88 | }, 89 | { 90 | "login": "NathanWalker", 91 | "name": "Nathan Walker", 92 | "avatar_url": "https://avatars2.githubusercontent.com/u/457187?v=4", 93 | "profile": "https://twitter.com/wwwalkerrun", 94 | "contributions": [ 95 | "maintenance", 96 | "code" 97 | ] 98 | }, 99 | { 100 | "login": "jiarongxu", 101 | "name": "Jiarong Xu", 102 | "avatar_url": "https://avatars0.githubusercontent.com/u/502605?v=4", 103 | "profile": "https://github.com/jiarongxu", 104 | "contributions": [ 105 | "code" 106 | ] 107 | }, 108 | { 109 | "login": "crutchcorn", 110 | "name": "Corbin Crutchley", 111 | "avatar_url": "https://avatars.githubusercontent.com/u/9100169?v=4", 112 | "profile": "https://crutchcorn.dev", 113 | "contributions": [ 114 | "code" 115 | ] 116 | }, 117 | { 118 | "login": "NayeBeckham", 119 | "name": "Nayeli Beckham", 120 | "avatar_url": "https://avatars.githubusercontent.com/u/78670199?v=4", 121 | "profile": "https://www.linkedin.com/in/nayeli-beckham-martínez/", 122 | "contributions": [ 123 | "code", 124 | "platform", 125 | "question", 126 | "maintenance" 127 | ] 128 | }, 129 | { 130 | "login": "rushvora", 131 | "name": "Rushabh Vora", 132 | "avatar_url": "https://avatars.githubusercontent.com/u/602333?v=4", 133 | "profile": "http://rushvora.com", 134 | "contributions": [ 135 | "code" 136 | ] 137 | }, 138 | { 139 | "login": "KarimTayie", 140 | "name": "Karim Tayie", 141 | "avatar_url": "https://avatars.githubusercontent.com/u/29521303?v=4", 142 | "profile": "https://github.com/KarimTayie", 143 | "contributions": [ 144 | "code" 145 | ] 146 | }, 147 | { 148 | "login": "imadilkhalil", 149 | "name": "Adil Khalil", 150 | "avatar_url": "https://avatars.githubusercontent.com/u/19613930?v=4", 151 | "profile": "https://github.com/imadilkhalil", 152 | "contributions": [ 153 | "code" 154 | ] 155 | }, 156 | { 157 | "login": "ambersz", 158 | "name": "Alice Zhao", 159 | "avatar_url": "https://avatars.githubusercontent.com/u/647791?v=4", 160 | "profile": "https://github.com/ambersz", 161 | "contributions": [ 162 | "code" 163 | ] 164 | }, 165 | { 166 | "login": "felipecespedes", 167 | "name": "Felipe Céspedes", 168 | "avatar_url": "https://avatars.githubusercontent.com/u/11846311?v=4", 169 | "profile": "https://www.felipecespedes.co", 170 | "contributions": [ 171 | "code" 172 | ] 173 | }, 174 | { 175 | "login": "bb-sonam", 176 | "name": "bb-sonam", 177 | "avatar_url": "https://avatars.githubusercontent.com/u/60337996?v=4", 178 | "profile": "https://github.com/bb-sonam", 179 | "contributions": [ 180 | "code" 181 | ] 182 | }, 183 | { 184 | "login": "alQlagin", 185 | "name": "Alex Kulagin", 186 | "avatar_url": "https://avatars.githubusercontent.com/u/3256488?v=4", 187 | "profile": "https://github.com/alQlagin", 188 | "contributions": [ 189 | "code" 190 | ] 191 | }, 192 | { 193 | "login": "subodhyadav712", 194 | "name": "Subodh Kumar Yadav", 195 | "avatar_url": "https://avatars.githubusercontent.com/u/36027830?v=4", 196 | "profile": "https://github.com/subodhyadav712", 197 | "contributions": [ 198 | "code" 199 | ] 200 | }, 201 | { 202 | "login": "harshalganbote", 203 | "name": "harshalganbote", 204 | "avatar_url": "https://avatars.githubusercontent.com/u/60728890?v=4", 205 | "profile": "https://github.com/harshalganbote", 206 | "contributions": [ 207 | "code" 208 | ] 209 | }, 210 | { 211 | "login": "christianopaets", 212 | "name": "christianopaets", 213 | "avatar_url": "https://avatars.githubusercontent.com/u/43338174?v=4", 214 | "profile": "https://github.com/christianopaets", 215 | "contributions": [ 216 | "code" 217 | ] 218 | }, 219 | { 220 | "login": "velechva", 221 | "name": "Victor Velechovsky", 222 | "avatar_url": "https://avatars.githubusercontent.com/u/13340931?v=4", 223 | "profile": "https://github.com/velechva", 224 | "contributions": [ 225 | "code" 226 | ] 227 | }, 228 | { 229 | "login": "leo6104", 230 | "name": "Heo", 231 | "avatar_url": "https://avatars.githubusercontent.com/u/7777929?v=4", 232 | "profile": "https://www.mapianist.com", 233 | "contributions": [ 234 | "code" 235 | ] 236 | }, 237 | { 238 | "login": "riderx", 239 | "name": "Martin DONADIEU", 240 | "avatar_url": "https://avatars.githubusercontent.com/u/4084527?v=4", 241 | "profile": "https://martin.solos.ventures/", 242 | "contributions": [ 243 | "code", 244 | "userTesting" 245 | ] 246 | }, 247 | { 248 | "login": "nicolasl-alight", 249 | "name": "Nico", 250 | "avatar_url": "https://avatars.githubusercontent.com/u/133889962?v=4", 251 | "profile": "https://github.com/nicolasl-alight", 252 | "contributions": [ 253 | "code", 254 | "doc", 255 | "platform", 256 | "userTesting" 257 | ] 258 | }, 259 | { 260 | "login": "zaizac", 261 | "name": "zaizac", 262 | "avatar_url": "https://avatars.githubusercontent.com/u/9007583?v=4", 263 | "profile": "https://github.com/zaizac", 264 | "contributions": [ 265 | "code", 266 | "review" 267 | ] 268 | }, 269 | { 270 | "login": "nicolasleb", 271 | "name": "nicolasleb", 272 | "avatar_url": "https://avatars.githubusercontent.com/u/4135062?v=4", 273 | "profile": "https://github.com/nicolasleb", 274 | "contributions": [ 275 | "code", 276 | "maintenance", 277 | "platform", 278 | "review", 279 | "userTesting" 280 | ] 281 | }, 282 | { 283 | "login": "jljabben", 284 | "name": "jlj", 285 | "avatar_url": "https://avatars.githubusercontent.com/u/5000255?v=4", 286 | "profile": "https://github.com/jljabben", 287 | "contributions": [ 288 | "code", 289 | "userTesting", 290 | "bug" 291 | ] 292 | }, 293 | { 294 | "login": "ahmedasif1", 295 | "name": "Ahmed Asif", 296 | "avatar_url": "https://avatars.githubusercontent.com/u/5271212?v=4", 297 | "profile": "https://github.com/ahmedasif1", 298 | "contributions": [ 299 | "bug", 300 | "code" 301 | ] 302 | }, 303 | { 304 | "login": "snmhinge", 305 | "name": "snmhinge", 306 | "avatar_url": "https://avatars.githubusercontent.com/u/10630821?v=4", 307 | "profile": "https://github.com/snmhinge", 308 | "contributions": [ 309 | "code" 310 | ] 311 | }, 312 | { 313 | "login": "juju-sunrise", 314 | "name": "juju-sunrise", 315 | "avatar_url": "https://avatars.githubusercontent.com/u/139119987?v=4", 316 | "profile": "https://github.com/juju-sunrise", 317 | "contributions": [ 318 | "code", 319 | "maintenance" 320 | ] 321 | }, 322 | { 323 | "login": "danielstvn", 324 | "name": "danielstvn", 325 | "avatar_url": "https://avatars.githubusercontent.com/u/83106033?v=4", 326 | "profile": "https://github.com/danielstvn", 327 | "contributions": [ 328 | "code", 329 | "maintenance" 330 | ] 331 | }, 332 | { 333 | "login": "kapcake", 334 | "name": "kapcake", 335 | "avatar_url": "https://avatars.githubusercontent.com/u/9072781?v=4", 336 | "profile": "https://github.com/kapcake", 337 | "contributions": [ 338 | "code", 339 | "maintenance" 340 | ] 341 | } 342 | ], 343 | "contributorsPerLine": 7, 344 | "skipCi": true, 345 | "commitConvention": "angular", 346 | "commitType": "docs" 347 | } 348 | -------------------------------------------------------------------------------- /.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 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.ts] 13 | quote_type = single 14 | 15 | [*.{md,rst}] 16 | max_line_length = off 17 | insert_final_newline = false 18 | trim_trailing_whitespace = false 19 | -------------------------------------------------------------------------------- /.github/dependabot-github-actions.yaml: -------------------------------------------------------------------------------- 1 | # Set update schedule for GitHub Actions 2 | 3 | version: 2 4 | updates: 5 | 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | schedule: 9 | # Check for updates to GitHub Actions every week 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | tags-ignore: 6 | - '**' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 🛎️ 13 | uses: actions/checkout@v4 14 | 15 | - name: Install and Build 🔧 16 | run: | 17 | npm ci 18 | npm run build_lib 19 | npm run build 20 | 21 | -------------------------------------------------------------------------------- /.github/workflows/test-angular-versions.yaml: -------------------------------------------------------------------------------- 1 | name: Test Angular Versions 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | test-angular-versions: 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | angular_version: ["16", "17", "18", "19"] 14 | 15 | steps: 16 | - name: Checkout 🔔 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: 18 23 | 24 | - name: Install dependencies 25 | run: npm ci 26 | 27 | - name: Determine TypeScript version for Angular ${{ matrix.angular_version }} 🔄 28 | run: | 29 | case ${{ matrix.angular_version }} in 30 | "15") TS_VERSION="~4.8.0" ;; 31 | "16") TS_VERSION="~4.9.0" ;; 32 | "17") TS_VERSION="~5.2.0" ;; 33 | "18") TS_VERSION="~5.5.0" ;; 34 | "19") TS_VERSION="~5.5.0" ;; 35 | *) echo "Unsupported Angular version"; exit 1 ;; 36 | esac 37 | echo "Using TypeScript version $TS_VERSION" 38 | npm install typescript@$TS_VERSION --save-dev --force 39 | 40 | - name: Install Angular version ${{ matrix.angular_version }} 41 | run: | 42 | npm run ng version 43 | 44 | # Angular runtime dependencies 45 | npm install @angular/animations@${{ matrix.angular_version }} --save --force 46 | npm install @angular/common@${{ matrix.angular_version }} --save --force 47 | npm install @angular/compiler@${{ matrix.angular_version }} --save --force 48 | npm install @angular/core@${{ matrix.angular_version }} --save --force 49 | npm install @angular/forms@${{ matrix.angular_version }} --save --force 50 | npm install @angular/platform-browser@${{ matrix.angular_version }} --save --force 51 | npm install @angular/platform-browser-dynamic@${{ matrix.angular_version }} --save --force 52 | npm install @angular/router@${{ matrix.angular_version }} --save --force 53 | 54 | # Angular dev dependencies 55 | npm install @angular-devkit/build-angular@${{ matrix.angular_version }} --save-dev --force 56 | npm install @angular/cli@${{ matrix.angular_version }} --save-dev --force 57 | npm install @angular/compiler-cli@${{ matrix.angular_version }} --save-dev --force 58 | npm install @angular/language-service@${{ matrix.angular_version }} --save-dev --force 59 | 60 | npm install --force 61 | 62 | npm run ng update @angular/cli@${{ matrix.angular_version }} -- --force --allow-dirty 63 | npm run ng update @angular/core@${{ matrix.angular_version }} -- --force --allow-dirty 64 | npm run ng update -- --force --allow-dirty 65 | 66 | - name: Run Angular build 🔧 67 | run: npm run build 68 | 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /.jsbeautifyrc: -------------------------------------------------------------------------------- 1 | { 2 | "indent_inner_html": true, 3 | "indent_with_tabs": true, 4 | "tab_size": 2, 5 | "wrap_attributes": "force" 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 webcat12345 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 | # International Telephone Input for Angular (NgxIntlTelInput) 2 | 3 | [![Build Status](https://github.com/webcat12345/ngx-intl-tel-input/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/webcat12345/ngx-intl-tel-input/actions/workflows/ci.yml) 4 | [![GitHub Pages](https://img.shields.io/badge/Demo-blue?logo=angular&label=Pages&color=7952B3)](https://webcat12345.github.io/ngx-intl-tel-input/demo/) 5 | [![license](https://img.shields.io/github/license/webcat12345/ngx-intl-tel-input)](https://github.com/webcat12345/ngx-intl-tel-input/blob/master/LICENSE) 6 | [![npm version](https://img.shields.io/npm/v/ngx-intl-tel-input)](https://badge.fury.io/js/ngx-intl-tel-input) 7 | [![npm](https://img.shields.io/npm/dm/ngx-intl-tel-input)](https://www.npmjs.com/package/ngx-intl-tel-input) 8 | 9 | [![All Contributors](https://img.shields.io/github/all-contributors/webcat12345/ngx-intl-tel-input?color=ee8449&style=flat-square)](#contributors) 10 | 11 | An Angular package for entering and validating international telephone numbers. It adds a flag dropdown to any input, detects the user's country, displays a relevant placeholder and provides formatting/validation methods. 12 | 13 | ![alt](readme-assets/ngx-intl-tel-input.jpg) 14 | 15 | **Compatibility:** 16 | 17 | Validation with [google-libphonenumber](https://github.com/ruimarinho/google-libphonenumber) 18 | 19 | | ngx-intl-tel-input | Angular | ngx-bootstrap | 20 | | ------------------ |-----------------| ------------- | 21 | | 17.x.x | >= 17.x.x | >= 12.0.0 | 22 | | 16.x.x | >= 16.x.x | >= 11.0.0 | 23 | | 15.x.x | >= 15.x.x | >= 10.0.0 | 24 | | 14.x.x | 12.x.x - 14.x.x | >= 6.0.0 | 25 | | 13.x.x | 12.x.x - 13.x.x | >= 6.0.0 | 26 | | 3.2.1 | 12.x.x - 13.x.x | >= 6.0.0 | 27 | | 3.1.3 | 8.x.x - 11.x.x | 6.0.x | 28 | | 2.x.x | 8.x.x - 9.1.x | 5.6.x | 29 | 30 | ## Installation 31 | 32 | ### Install Dependencies 33 | 34 | `$ npm install intl-tel-input@19 --save` 35 | 36 | `$ npm install google-libphonenumber --save` 37 | 38 | `$ ng add ngx-bootstrap` 39 | 40 | If you do not wish to use Bootstrap's global CSS, we now package the project with only the relevant 41 | bootstrap styling needed for the dropdown. As such, you can remove the bootstrap styling from `angular.json`. 42 | 43 | Further, Angular CLI should tree-shake the rest of Ngx-Boostrap away if you don't utilize other dependencies from 44 | the bootstrap package. This should keep this dependency a lean feature-add 45 | 46 | ### Add Dependency Style 47 | 48 | Add _'intl-tel-input'_ style file: 49 | 50 | `./node_modules/intl-tel-input/build/css/intlTelInput.css` 51 | 52 | to **angular.json** styles array: 53 | 54 | ```json 55 | 56 | "styles": [ 57 | "./node_modules/intl-tel-input/build/css/intlTelInput.css", 58 | "src/styles.css" 59 | ], 60 | 61 | ``` 62 | 63 | ### Install This Library 64 | 65 | `$ npm install ngx-intl-tel-input --save` 66 | 67 | ## Usage 68 | 69 | ### Import 70 | 71 | Add `NgxIntlTelInputModule` to your module file: 72 | 73 | ```javascript 74 | imports: [NgxIntlTelInputModule]; 75 | ``` 76 | 77 | ## Example 78 | 79 | Refer to main app in this repository for working example. 80 | 81 | Or this: 82 | 83 | [Stackblitz Demo (Angular 8)](https://stackblitz.com/edit/ngx-intl-tel-input-demo-ng-8) 84 | 85 | [Stackblitz Demo (Angular 9)](https://stackblitz.com/edit/ngx-intl-tel-input-demo-ng-9) 86 | 87 | [Stackblitz Demo (Angular 10)](https://stackblitz.com/edit/ngx-intl-tel-input-demo-ng-10) 88 | 89 | [Stackblitz Demo (Angular 11)](https://stackblitz.com/edit/ngx-intl-tel-input-demo-ng-11) 90 | 91 | [Stackblitz Demo (Angular 12)](https://stackblitz.com/edit/ngx-intl-tel-input-demo-ng-12) 92 | 93 | ```html 94 |
95 | 110 |
111 | ``` 112 | 113 | ## Options 114 | 115 | | Options | Type | Default | Description | 116 | | ------------------------ | ------------------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------- | 117 | | cssClass | `string` | `control-form` | Bootstrap input css class or your own custom one. | 118 | | preferredCountries | `[]` | `[]` | List of countries, which will appear at the top. | 119 | | onlyCountries | `[]` | `[]` | List of manually selected countries, which will appear in the dropdown. | 120 | | enableAutoCountrySelect | `boolean` | `true` | Toggle automatic country (flag) selection based on user input. | 121 | | enablePlaceholder | `boolean` | `true` | Input placeholder text, which adapts to the country selected. | 122 | | customPlaceholder | `string` | `None` | Custom string to be inserted as a placeholder. | 123 | | numberFormat | `` | `PhoneNumberFormat.International` | Custom string to be inserted as a placeholder. | 124 | | searchCountryFlag | `boolean` | `false` | Enables input search box for countries in the flag dropdown. | 125 | | searchCountryField | `[]` | `[SearchCountryField.All]` | Customize which fields to search in, if `searchCountryFlag` is enabled. Use `SearchCountryField` helper enum. | 126 | | searchCountryPlaceholder | `string` | `'Search Country'` | Placeholder value for `searchCountryField` | 127 | | maxLength | `number` | `None` | Add character limit. | 128 | | selectFirstCountry | `boolean` | `true` | Selects first country from `preferredCountries` if is set. If not then uses main list. | 129 | | phoneValidation | `boolean` | `true` | Disable phone validation. | 130 | | inputId | `string` | `phone` | Unique ID for `` element. | 131 | | selectedCountryISO | `` | `None` | Set specific country on load. | 132 | | separateDialCode | `boolean` | `false` | Visually separate dialcode into the drop down element. | 133 | | countryChange | `` | `None` | Emits country value when the user selects a country from the dropdown. | 134 | 135 | ## Supported Formats 136 | 137 | Following formats are supported 138 | 139 | - NATIONAL // Produces "044 668 18 00" 140 | - INTERNATIONAL // Produces "+41 44 668 18 00" 141 | - E164 // Produces "+41446681800" 142 | 143 | ## Library Contributions 144 | 145 | - Fork repo. 146 | - Update `./projects/ngx-intl-tel-input` 147 | - Build / test library. 148 | - Update `./src/app` with new functionality. 149 | - Update README.md 150 | - Pull request. 151 | 152 | ### Helpful commands 153 | 154 | - Build lib: `$ npm run build_lib` 155 | - Copy license and readme files: `$ npm run copy-files` 156 | - Create package: `$ npm run npm_pack` 157 | - Build lib and create package: `$ npm run package` 158 | 159 | ### Use locally 160 | 161 | After building and creating package, you can use it locally too. 162 | 163 | In your project run: 164 | 165 | `$ npm install --save {{path to your local '*.tgz' package file}}` 166 | 167 | ## Contributors 168 | 169 | Thanks goes to these wonderful people ([emoji key](https://github.com/all-contributors/all-contributors#emoji-key)): 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 |
webcat_black
webcat_black

🎨 💻 📖 🤔 💬 🚇 💡 🚧 👀 ⚠️
Chris McKnight
Chris McKnight

💬 💻 📖 🤔 🚇 🔌 👀 🔧
Aleksandr Pasevin
Aleksandr Pasevin

💻 📖 🐛 📦 🔌 💬 🚇 💡 🚧 👀 ⚠️
Dviejo
Dviejo

💻 🐛 💡 ⚠️ 💬 🚧 👀
Kino Roy
Kino Roy

💻
Nathan Walker
Nathan Walker

🚧 💻
Jiarong Xu
Jiarong Xu

💻
Corbin Crutchley
Corbin Crutchley

💻
Nayeli Beckham
Nayeli Beckham

💻 📦 💬 🚧
Rushabh Vora
Rushabh Vora

💻
Karim Tayie
Karim Tayie

💻
Adil Khalil
Adil Khalil

💻
Alice Zhao
Alice Zhao

💻
Felipe Céspedes
Felipe Céspedes

💻
bb-sonam
bb-sonam

💻
Alex Kulagin
Alex Kulagin

💻
Subodh Kumar Yadav
Subodh Kumar Yadav

💻
harshalganbote
harshalganbote

💻
christianopaets
christianopaets

💻
Victor Velechovsky
Victor Velechovsky

💻
Heo
Heo

💻
Martin DONADIEU
Martin DONADIEU

💻 📓
Nico
Nico

💻 📖 📦 📓
zaizac
zaizac

💻 👀
nicolasleb
nicolasleb

💻 🚧 📦 👀 📓
jlj
jlj

💻 📓 🐛
Ahmed Asif
Ahmed Asif

🐛 💻
snmhinge
snmhinge

💻
juju-sunrise
juju-sunrise

💻 🚧
danielstvn
danielstvn

💻 🚧
kapcake
kapcake

💻 🚧
219 | 220 | 221 | 222 | 223 | 224 | 225 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 226 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "ngx-intl-tel-input-app": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/ngx-intl-tel-input-app", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "src/tsconfig.app.json", 21 | "assets": ["src/favicon.ico", "src/assets"], 22 | "styles": [ 23 | "./node_modules/intl-tel-input/build/css/intlTelInput.css", 24 | "src/styles.css" 25 | ], 26 | "scripts": [], 27 | "allowedCommonJsDependencies": ["google-libphonenumber"], 28 | "vendorChunk": true, 29 | "extractLicenses": false, 30 | "buildOptimizer": false, 31 | "sourceMap": true, 32 | "optimization": false, 33 | "namedChunks": true 34 | }, 35 | "configurations": { 36 | "production": { 37 | "fileReplacements": [ 38 | { 39 | "replace": "src/environments/environment.ts", 40 | "with": "src/environments/environment.prod.ts" 41 | } 42 | ], 43 | "optimization": true, 44 | "outputHashing": "all", 45 | "sourceMap": false, 46 | "namedChunks": false, 47 | "extractLicenses": true, 48 | "vendorChunk": false, 49 | "buildOptimizer": true, 50 | "budgets": [ 51 | { 52 | "type": "initial", 53 | "maximumWarning": "2mb", 54 | "maximumError": "5mb" 55 | }, 56 | { 57 | "type": "anyComponentStyle", 58 | "maximumWarning": "6kb" 59 | } 60 | ] 61 | } 62 | }, 63 | "defaultConfiguration": "" 64 | }, 65 | "serve": { 66 | "builder": "@angular-devkit/build-angular:dev-server", 67 | "options": { 68 | "buildTarget": "ngx-intl-tel-input-app:build" 69 | }, 70 | "configurations": { 71 | "production": { 72 | "buildTarget": "ngx-intl-tel-input-app:build:production" 73 | } 74 | } 75 | }, 76 | "extract-i18n": { 77 | "builder": "@angular-devkit/build-angular:extract-i18n", 78 | "options": { 79 | "buildTarget": "ngx-intl-tel-input-app:build" 80 | } 81 | }, 82 | "test": { 83 | "builder": "@angular-devkit/build-angular:karma", 84 | "options": { 85 | "main": "src/test.ts", 86 | "polyfills": "src/polyfills.ts", 87 | "tsConfig": "src/tsconfig.spec.json", 88 | "karmaConfig": "src/karma.conf.js", 89 | "styles": [ 90 | "./node_modules/intl-tel-input/build/css/intlTelInput.css", 91 | "src/styles.css" 92 | ], 93 | "scripts": [], 94 | "assets": ["src/favicon.ico", "src/assets"] 95 | } 96 | } 97 | } 98 | }, 99 | "ngx-intl-tel-input": { 100 | "root": "projects/ngx-intl-tel-input", 101 | "sourceRoot": "projects/ngx-intl-tel-input/src", 102 | "projectType": "library", 103 | "prefix": "ngx", 104 | "architect": { 105 | "build": { 106 | "builder": "@angular-devkit/build-angular:ng-packagr", 107 | "options": { 108 | "tsConfig": "projects/ngx-intl-tel-input/tsconfig.lib.json", 109 | "project": "projects/ngx-intl-tel-input/ng-package.json" 110 | } 111 | }, 112 | "test": { 113 | "builder": "@angular-devkit/build-angular:karma", 114 | "options": { 115 | "main": "projects/ngx-intl-tel-input/src/test.ts", 116 | "tsConfig": "projects/ngx-intl-tel-input/tsconfig.spec.json", 117 | "karmaConfig": "projects/ngx-intl-tel-input/karma.conf.js" 118 | } 119 | } 120 | } 121 | } 122 | }, 123 | "cli": { 124 | "analytics": false 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-intl-tel-input-app", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "build_stats": "ng build --stats-json", 12 | "analyze": "webpack-bundle-analyzer dist/ngx-intl-tel-input-app/stats.json", 13 | "build_lib": "ng build ngx-intl-tel-input", 14 | "copy-license": "cp ./LICENSE ./dist/ngx-intl-tel-input", 15 | "copy-readme": "cp ./README.md ./dist/ngx-intl-tel-input", 16 | "copy-files": "npm run copy-license && npm run copy-readme", 17 | "npm_pack": "npm run copy-files && cd dist/ngx-intl-tel-input && npm pack", 18 | "package": "rimraf ./dist && npm run build_lib && npm run npm_pack" 19 | }, 20 | "private": true, 21 | "dependencies": { 22 | "@angular/animations": "^17.0.0", 23 | "@angular/common": "^17.0.0", 24 | "@angular/compiler": "^17.0.0", 25 | "@angular/core": "^17.0.0", 26 | "@angular/forms": "^17.0.0", 27 | "@angular/platform-browser": "^17.0.0", 28 | "@angular/platform-browser-dynamic": "^17.0.0", 29 | "@angular/router": "^17.0.0", 30 | "bootstrap": "^5.3.0", 31 | "core-js": "^3.35.0", 32 | "google-libphonenumber": "^3.2.34", 33 | "intl-tel-input": "^19.2.3", 34 | "jquery": "^3.7.1", 35 | "ngx-bootstrap": "^12.0.0", 36 | "popper.js": "^1.16.1", 37 | "rxjs": "^7.8.1", 38 | "tslib": "^2.6.2", 39 | "zone.js": "~0.14.3" 40 | }, 41 | "devDependencies": { 42 | "@angular-devkit/build-angular": "^17.0.0", 43 | "@angular/cli": "^17.0.0", 44 | "@angular/compiler-cli": "^17.0.0", 45 | "@angular/language-service": "^17.0.0", 46 | "@types/google-libphonenumber": "^7.4.30", 47 | "@types/jasmine": "^5.1.4", 48 | "@types/jasminewd2": "^2.0.13", 49 | "@types/node": "^20.11.5", 50 | "ajv": "^8.12.0", 51 | "eslint": "^8.56.0", 52 | "jasmine-core": "^5.1.1", 53 | "jasmine-spec-reporter": "^7.0.0", 54 | "karma": "^6.4.2", 55 | "karma-chrome-launcher": "^3.2.0", 56 | "karma-coverage-istanbul-reporter": "^3.0.3", 57 | "karma-jasmine": "^5.1.0", 58 | "karma-jasmine-html-reporter": "^2.1.0", 59 | "ng-packagr": "^17.0.0", 60 | "prettier": "^3.2.4", 61 | "rollup": "^4.9.5", 62 | "ts-node": "^10.9.2", 63 | "typescript": "~5.4.0", 64 | "webpack-bundle-analyzer": "^4.10.1" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/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'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true, 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | customLaunchers: { 29 | ChromeHeadless: { 30 | base: 'Chrome', 31 | flags: [ 32 | '--headless', 33 | '--disable-gpu', 34 | '--no-sandbox', 35 | '--remote-debugging-port=9222', 36 | '--disable-web-security', 37 | ], 38 | }, 39 | }, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | }); 43 | }; 44 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/ngx-intl-tel-input", 4 | "lib": { 5 | "entryFile": "src/public_api.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-intl-tel-input", 3 | "version": "17.0.0", 4 | "peerDependencies": { 5 | "@angular/common": ">= 17.0.0", 6 | "@angular/core": ">= 17.0.0", 7 | "@angular/forms": ">= 17.0.0", 8 | "google-libphonenumber": "^3.0.0", 9 | "intl-tel-input": "^19.0.0", 10 | "ngx-bootstrap": ">= 12.0.0" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/webcat12345/ngx-intl-tel-input.git" 15 | }, 16 | "author": { 17 | "name": "webcat12345", 18 | "email": "webcat91@gmail.com" 19 | }, 20 | "keywords": [ 21 | "angular", 22 | "angular 2", 23 | "ng8", 24 | "ng9", 25 | "ng10", 26 | "ng11", 27 | "ng12", 28 | "ng13", 29 | "ng14", 30 | "ng15", 31 | "ng16", 32 | "ng17", 33 | "angular 8", 34 | "angular 9", 35 | "angular 10", 36 | "angular 11", 37 | "angular 12", 38 | "angular 13", 39 | "angular 14", 40 | "angular 15", 41 | "angular 16", 42 | "angular 17", 43 | "intl-tel-input", 44 | "phone number", 45 | "validation" 46 | ], 47 | "license": "MIT", 48 | "bugs": { 49 | "url": "https://github.com/webcat12345/ngx-intl-tel-input/issues" 50 | }, 51 | "devDependencies": { 52 | "@types/google-libphonenumber": "^7.4.24" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/bootstrap-dropdown.css: -------------------------------------------------------------------------------- 1 | .dropup, 2 | .dropright, 3 | .dropdown, 4 | .dropleft { 5 | position: relative; 6 | } 7 | 8 | .dropdown-toggle { 9 | white-space: nowrap; 10 | } 11 | .dropdown-toggle::after { 12 | display: inline-block; 13 | margin-left: 0.255em; 14 | vertical-align: 0.255em; 15 | content: ""; 16 | border-top: 0.3em solid; 17 | border-right: 0.3em solid transparent; 18 | border-bottom: 0; 19 | border-left: 0.3em solid transparent; 20 | } 21 | .dropdown-toggle:empty::after { 22 | margin-left: 0; 23 | } 24 | 25 | .dropdown-menu { 26 | position: absolute; 27 | top: 100%; 28 | left: 0; 29 | z-index: 1000; 30 | display: none; 31 | float: left; 32 | min-width: 10rem; 33 | padding: 0.5rem 0; 34 | margin: 0.125rem 0 0; 35 | font-size: 1rem; 36 | color: #212529; 37 | text-align: left; 38 | list-style: none; 39 | background-color: #fff; 40 | background-clip: padding-box; 41 | border: 1px solid rgba(0, 0, 0, 0.15); 42 | border-radius: 0.25rem; 43 | } 44 | 45 | .dropdown-menu-left { 46 | right: auto; 47 | left: 0; 48 | } 49 | 50 | .dropdown-menu-right { 51 | right: 0; 52 | left: auto; 53 | } 54 | 55 | @media (min-width: 576px) { 56 | .dropdown-menu-sm-left { 57 | right: auto; 58 | left: 0; 59 | } 60 | 61 | .dropdown-menu-sm-right { 62 | right: 0; 63 | left: auto; 64 | } 65 | } 66 | @media (min-width: 768px) { 67 | .dropdown-menu-md-left { 68 | right: auto; 69 | left: 0; 70 | } 71 | 72 | .dropdown-menu-md-right { 73 | right: 0; 74 | left: auto; 75 | } 76 | } 77 | @media (min-width: 992px) { 78 | .dropdown-menu-lg-left { 79 | right: auto; 80 | left: 0; 81 | } 82 | 83 | .dropdown-menu-lg-right { 84 | right: 0; 85 | left: auto; 86 | } 87 | } 88 | @media (min-width: 1200px) { 89 | .dropdown-menu-xl-left { 90 | right: auto; 91 | left: 0; 92 | } 93 | 94 | .dropdown-menu-xl-right { 95 | right: 0; 96 | left: auto; 97 | } 98 | } 99 | .dropup .dropdown-menu { 100 | top: auto; 101 | bottom: 100%; 102 | margin-top: 0; 103 | margin-bottom: 0.125rem; 104 | } 105 | .dropup .dropdown-toggle::after { 106 | display: inline-block; 107 | margin-left: 0.255em; 108 | vertical-align: 0.255em; 109 | content: ""; 110 | border-top: 0; 111 | border-right: 0.3em solid transparent; 112 | border-bottom: 0.3em solid; 113 | border-left: 0.3em solid transparent; 114 | } 115 | .dropup .dropdown-toggle:empty::after { 116 | margin-left: 0; 117 | } 118 | 119 | .dropright .dropdown-menu { 120 | top: 0; 121 | right: auto; 122 | left: 100%; 123 | margin-top: 0; 124 | margin-left: 0.125rem; 125 | } 126 | .dropright .dropdown-toggle::after { 127 | display: inline-block; 128 | margin-left: 0.255em; 129 | vertical-align: 0.255em; 130 | content: ""; 131 | border-top: 0.3em solid transparent; 132 | border-right: 0; 133 | border-bottom: 0.3em solid transparent; 134 | border-left: 0.3em solid; 135 | } 136 | .dropright .dropdown-toggle:empty::after { 137 | margin-left: 0; 138 | } 139 | .dropright .dropdown-toggle::after { 140 | vertical-align: 0; 141 | } 142 | 143 | .dropleft .dropdown-menu { 144 | top: 0; 145 | right: 100%; 146 | left: auto; 147 | margin-top: 0; 148 | margin-right: 0.125rem; 149 | } 150 | .dropleft .dropdown-toggle::after { 151 | display: inline-block; 152 | margin-left: 0.255em; 153 | vertical-align: 0.255em; 154 | content: ""; 155 | } 156 | .dropleft .dropdown-toggle::after { 157 | display: none; 158 | } 159 | .dropleft .dropdown-toggle::before { 160 | display: inline-block; 161 | margin-right: 0.255em; 162 | vertical-align: 0.255em; 163 | content: ""; 164 | border-top: 0.3em solid transparent; 165 | border-right: 0.3em solid; 166 | border-bottom: 0.3em solid transparent; 167 | } 168 | .dropleft .dropdown-toggle:empty::after { 169 | margin-left: 0; 170 | } 171 | .dropleft .dropdown-toggle::before { 172 | vertical-align: 0; 173 | } 174 | 175 | .dropdown-menu[x-placement^=top], .dropdown-menu[x-placement^=right], .dropdown-menu[x-placement^=bottom], .dropdown-menu[x-placement^=left] { 176 | right: auto; 177 | bottom: auto; 178 | } 179 | 180 | .dropdown-divider { 181 | height: 0; 182 | margin: 0.5rem 0; 183 | overflow: hidden; 184 | border-top: 1px solid #e9ecef; 185 | } 186 | 187 | .dropdown-item { 188 | display: block; 189 | width: 100%; 190 | padding: 0.25rem 1.5rem; 191 | clear: both; 192 | font-weight: 400; 193 | color: #212529; 194 | text-align: inherit; 195 | white-space: nowrap; 196 | background-color: transparent; 197 | border: 0; 198 | } 199 | .dropdown-item:hover, .dropdown-item:focus { 200 | color: #16181b; 201 | text-decoration: none; 202 | background-color: #f8f9fa; 203 | } 204 | .dropdown-item.active, .dropdown-item:active { 205 | color: #fff; 206 | text-decoration: none; 207 | background-color: #007bff; 208 | } 209 | .dropdown-item.disabled, .dropdown-item:disabled { 210 | color: #6c757d; 211 | pointer-events: none; 212 | background-color: transparent; 213 | } 214 | 215 | .dropdown-menu.show { 216 | display: block; 217 | } 218 | 219 | .dropdown-header { 220 | display: block; 221 | padding: 0.5rem 1.5rem; 222 | margin-bottom: 0; 223 | font-size: 0.875rem; 224 | color: #6c757d; 225 | white-space: nowrap; 226 | } 227 | 228 | .dropdown-item-text { 229 | display: block; 230 | padding: 0.25rem 1.5rem; 231 | color: #212529; 232 | } 233 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/data/country-code.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { CountryISO } from '../enums/country-iso.enum'; 3 | 4 | @Injectable() 5 | export class CountryCode { 6 | public allCountries = [ 7 | ['Afghanistan (‫افغانستان‬‎)', CountryISO.Afghanistan, '93'], 8 | ['Albania (Shqipëri)', CountryISO.Albania, '355'], 9 | ['Algeria (‫الجزائر‬‎)', CountryISO.Algeria, '213'], 10 | ['American Samoa', 'as', '1', 1, ['684']], 11 | ['Andorra', CountryISO.Andorra, '376'], 12 | ['Angola', CountryISO.Angola, '244'], 13 | ['Anguilla', 'ai', '1', 1, ['264']], 14 | ['Antigua and Barbuda', 'ag', '1', 1, ['268']], 15 | ['Argentina', CountryISO.Argentina, '54'], 16 | ['Armenia (Հայաստան)', CountryISO.Armenia, '374'], 17 | ['Aruba', CountryISO.Aruba, '297'], 18 | ['Australia', CountryISO.Australia, '61', 0], 19 | ['Austria (Österreich)', CountryISO.Austria, '43'], 20 | ['Azerbaijan (Azərbaycan)', CountryISO.Azerbaijan, '994'], 21 | ['Bahamas', 'bs', '1', 1, ['242']], 22 | ['Bahrain (‫البحرين‬‎)', CountryISO.Bahrain, '973'], 23 | ['Bangladesh (বাংলাদেশ)', CountryISO.Bangladesh, '880'], 24 | ['Barbados', 'bb', '1', 1, ['246']], 25 | ['Belarus (Беларусь)', CountryISO.Belarus, '375'], 26 | ['Belgium (België)', CountryISO.Belgium, '32'], 27 | ['Belize', CountryISO.Belize, '501'], 28 | ['Benin (Bénin)', CountryISO.Benin, '229'], 29 | ['Bermuda', 'bm', '1', 1, ['441']], 30 | ['Bhutan (འབྲུག)', CountryISO.Bhutan, '975'], 31 | ['Bolivia', CountryISO.Bolivia, '591'], 32 | ['Bosnia and Herzegovina (Босна и Херцеговина)', CountryISO.BosniaAndHerzegovina, '387'], 33 | ['Botswana', CountryISO.Botswana, '267'], 34 | ['Brazil (Brasil)', CountryISO.Brazil, '55'], 35 | ['British Indian Ocean Territory', CountryISO.BritishIndianOceanTerritory, '246'], 36 | ['British Virgin Islands', 'vg', '1', 1, ['284']], 37 | ['Brunei', CountryISO.Brunei, '673'], 38 | ['Bulgaria (България)', CountryISO.Bulgaria, '359'], 39 | ['Burkina Faso', CountryISO.BurkinaFaso, '226'], 40 | ['Burundi (Uburundi)', CountryISO.Burundi, '257'], 41 | ['Cambodia (កម្ពុជា)', CountryISO.Cambodia, '855'], 42 | ['Cameroon (Cameroun)', CountryISO.Cameroon, '237'], 43 | [ 44 | 'Canada', 45 | CountryISO.Canada, 46 | '1', 47 | 1, 48 | [ 49 | '204', 50 | '226', 51 | '236', 52 | '249', 53 | '250', 54 | '289', 55 | '306', 56 | '343', 57 | '365', 58 | '387', 59 | '403', 60 | '416', 61 | '418', 62 | '431', 63 | '437', 64 | '438', 65 | '450', 66 | '506', 67 | '514', 68 | '519', 69 | '548', 70 | '579', 71 | '581', 72 | '587', 73 | '604', 74 | '613', 75 | '639', 76 | '647', 77 | '672', 78 | '705', 79 | '709', 80 | '742', 81 | '778', 82 | '780', 83 | '782', 84 | '807', 85 | '819', 86 | '825', 87 | '867', 88 | '873', 89 | '902', 90 | '905', 91 | ], 92 | ], 93 | ['Cape Verde (Kabu Verdi)', CountryISO.CapeVerde, '238'], 94 | ['Caribbean Netherlands', CountryISO.CaribbeanNetherlands, '599', 1], 95 | ['Cayman Islands', 'ky', '1', 1, ['345']], 96 | [ 97 | 'Central African Republic (République centrafricaine)', 98 | CountryISO.CentralAfricanRepublic, 99 | '236', 100 | ], 101 | ['Chad (Tchad)', CountryISO.Chad, '235'], 102 | ['Chile', CountryISO.Chile, '56'], 103 | ['China (中国)', CountryISO.China, '86'], 104 | ['Christmas Island', CountryISO.ChristmasIsland, '61', 2], 105 | ['Cocos (Keeling) Islands', CountryISO.Cocos, '61', 1], 106 | ['Colombia', CountryISO.Colombia, '57'], 107 | ['Comoros (‫جزر القمر‬‎)', CountryISO.Comoros, '269'], 108 | [ 109 | 'Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)', 110 | CountryISO.CongoDRCJamhuriYaKidemokrasiaYaKongo, 111 | '243', 112 | ], 113 | ['Congo (Republic) (Congo-Brazzaville)', CountryISO.CongoRepublicCongoBrazzaville, '242'], 114 | ['Cook Islands', CountryISO.CookIslands, '682'], 115 | ['Costa Rica', CountryISO.CostaRica, '506'], 116 | ['Côte d’Ivoire', CountryISO.CôteDIvoire, '225'], 117 | ['Croatia (Hrvatska)', CountryISO.Croatia, '385'], 118 | ['Cuba', CountryISO.Cuba, '53'], 119 | ['Curaçao', CountryISO.Curaçao, '599', 0], 120 | ['Cyprus (Κύπρος)', CountryISO.Cyprus, '357'], 121 | ['Czech Republic (Česká republika)', CountryISO.CzechRepublic, '420'], 122 | ['Denmark (Danmark)', CountryISO.Denmark, '45'], 123 | ['Djibouti', CountryISO.Djibouti, '253'], 124 | ['Dominica', CountryISO.Dominica, '1767'], 125 | [ 126 | 'Dominican Republic (República Dominicana)', 127 | CountryISO.DominicanRepublic, 128 | '1', 129 | 2, 130 | ['809', '829', '849'], 131 | ], 132 | ['Ecuador', CountryISO.Ecuador, '593'], 133 | ['Egypt (‫مصر‬‎)', CountryISO.Egypt, '20'], 134 | ['El Salvador', CountryISO.ElSalvador, '503'], 135 | ['Equatorial Guinea (Guinea Ecuatorial)', CountryISO.EquatorialGuinea, '240'], 136 | ['Eritrea', CountryISO.Eritrea, '291'], 137 | ['Estonia (Eesti)', CountryISO.Estonia, '372'], 138 | ['Ethiopia', CountryISO.Ethiopia, '251'], 139 | ['Falkland Islands (Islas Malvinas)', CountryISO.FalklandIslands, '500'], 140 | ['Faroe Islands (Føroyar)', CountryISO.FaroeIslands, '298'], 141 | ['Fiji', CountryISO.Fiji, '679'], 142 | ['Finland (Suomi)', CountryISO.Finland, '358', 0], 143 | ['France', CountryISO.France, '33'], 144 | ['French Guiana (Guyane française)', CountryISO.FrenchGuiana, '594'], 145 | ['French Polynesia (Polynésie française)', CountryISO.FrenchPolynesia, '689'], 146 | ['Gabon', CountryISO.Gabon, '241'], 147 | ['Gambia', CountryISO.Gambia, '220'], 148 | ['Georgia (საქართველო)', CountryISO.Georgia, '995'], 149 | ['Germany (Deutschland)', CountryISO.Germany, '49'], 150 | ['Ghana (Gaana)', CountryISO.Ghana, '233'], 151 | ['Gibraltar', CountryISO.Gibraltar, '350'], 152 | ['Greece (Ελλάδα)', CountryISO.Greece, '30'], 153 | ['Greenland (Kalaallit Nunaat)', CountryISO.Greenland, '299'], 154 | ['Grenada', CountryISO.Grenada, '1473'], 155 | ['Guadeloupe', CountryISO.Guadeloupe, '590', 0], 156 | ['Guam', 'gu', '1', 1, ['671']], 157 | ['Guatemala', CountryISO.Guatemala, '502'], 158 | ['Guernsey', CountryISO.Guernsey, '44', 1, [1481]], 159 | ['Guinea (Guinée)', CountryISO.Guinea, '224'], 160 | ['Guinea-Bissau (Guiné Bissau)', CountryISO.GuineaBissau, '245'], 161 | ['Guyana', CountryISO.Guyana, '592'], 162 | ['Haiti', CountryISO.Haiti, '509'], 163 | ['Honduras', CountryISO.Honduras, '504'], 164 | ['Hong Kong (香港)', CountryISO.HongKong, '852'], 165 | ['Hungary (Magyarország)', CountryISO.Hungary, '36'], 166 | ['Iceland (Ísland)', CountryISO.Iceland, '354'], 167 | ['India (भारत)', CountryISO.India, '91'], 168 | ['Indonesia', CountryISO.Indonesia, '62'], 169 | ['Iran (‫ایران‬‎)', CountryISO.Iran, '98'], 170 | ['Iraq (‫العراق‬‎)', CountryISO.Iraq, '964'], 171 | ['Ireland', CountryISO.Ireland, '353'], 172 | ['Isle of Man', CountryISO.IsleOfMan, '44', 2, [1624]], 173 | ['Israel (‫ישראל‬‎)', CountryISO.Israel, '972'], 174 | ['Italy (Italia)', CountryISO.Italy, '39', 0], 175 | ['Jamaica', 'jm', '1', 1, ['876']], 176 | ['Japan (日本)', CountryISO.Japan, '81'], 177 | ['Jersey', CountryISO.Jersey, '44', 3, [1534]], 178 | ['Jordan (‫الأردن‬‎)', CountryISO.Jordan, '962'], 179 | ['Kazakhstan (Казахстан)', CountryISO.Kazakhstan, '7', 1], 180 | ['Kenya', CountryISO.Kenya, '254'], 181 | ['Kiribati', CountryISO.Kiribati, '686'], 182 | ['Kosovo', CountryISO.Kosovo, '383'], 183 | ['Kuwait (‫الكويت‬‎)', CountryISO.Kuwait, '965'], 184 | ['Kyrgyzstan (Кыргызстан)', CountryISO.Kyrgyzstan, '996'], 185 | ['Laos (ລາວ)', CountryISO.Laos, '856'], 186 | ['Latvia (Latvija)', CountryISO.Latvia, '371'], 187 | ['Lebanon (‫لبنان‬‎)', CountryISO.Lebanon, '961'], 188 | ['Lesotho', CountryISO.Lesotho, '266'], 189 | ['Liberia', CountryISO.Liberia, '231'], 190 | ['Libya (‫ليبيا‬‎)', CountryISO.Libya, '218'], 191 | ['Liechtenstein', CountryISO.Liechtenstein, '423'], 192 | ['Lithuania (Lietuva)', CountryISO.Lithuania, '370'], 193 | ['Luxembourg', CountryISO.Luxembourg, '352'], 194 | ['Macau (澳門)', CountryISO.Macau, '853'], 195 | ['Macedonia (FYROM) (Македонија)', CountryISO.Macedonia, '389'], 196 | ['Madagascar (Madagasikara)', CountryISO.Madagascar, '261'], 197 | ['Malawi', CountryISO.Malawi, '265'], 198 | ['Malaysia', CountryISO.Malaysia, '60'], 199 | ['Maldives', CountryISO.Maldives, '960'], 200 | ['Mali', CountryISO.Mali, '223'], 201 | ['Malta', CountryISO.Malta, '356'], 202 | ['Marshall Islands', CountryISO.MarshallIslands, '692'], 203 | ['Martinique', CountryISO.Martinique, '596'], 204 | ['Mauritania (‫موريتانيا‬‎)', CountryISO.Mauritania, '222'], 205 | ['Mauritius (Moris)', CountryISO.Mauritius, '230'], 206 | ['Mayotte', CountryISO.Mayotte, '262', 1], 207 | ['Mexico (México)', CountryISO.Mexico, '52'], 208 | ['Micronesia', CountryISO.Micronesia, '691'], 209 | ['Moldova (Republica Moldova)', CountryISO.Moldova, '373'], 210 | ['Monaco', CountryISO.Monaco, '377'], 211 | ['Mongolia (Монгол)', CountryISO.Mongolia, '976'], 212 | ['Montenegro (Crna Gora)', CountryISO.Montenegro, '382'], 213 | ['Montserrat', 'ms', '1', 1, ['664']], 214 | ['Morocco (‫المغرب‬‎)', CountryISO.Morocco, '212', 0], 215 | ['Mozambique (Moçambique)', CountryISO.Mozambique, '258'], 216 | ['Myanmar (Burma) (မြန်မာ)', CountryISO.Myanmar, '95'], 217 | ['Namibia (Namibië)', CountryISO.Namibia, '264'], 218 | ['Nauru', CountryISO.Nauru, '674'], 219 | ['Nepal (नेपाल)', CountryISO.Nepal, '977'], 220 | ['Netherlands (Nederland)', CountryISO.Netherlands, '31'], 221 | ['New Caledonia (Nouvelle-Calédonie)', CountryISO.NewCaledonia, '687'], 222 | ['New Zealand', CountryISO.NewZealand, '64'], 223 | ['Nicaragua', CountryISO.Nicaragua, '505'], 224 | ['Niger (Nijar)', CountryISO.Niger, '227'], 225 | ['Nigeria', CountryISO.Nigeria, '234'], 226 | ['Niue', CountryISO.Niue, '683'], 227 | ['Norfolk Island', CountryISO.NorfolkIsland, '672'], 228 | ['North Korea (조선 민주주의 인민 공화국)', CountryISO.NorthKorea, '850'], 229 | ['Northern Mariana Islands', CountryISO.NorthernMarianaIslands, '1670'], 230 | ['Norway (Norge)', CountryISO.Norway, '47', 0], 231 | ['Oman (‫عُمان‬‎)', CountryISO.Oman, '968'], 232 | ['Pakistan (‫پاکستان‬‎)', CountryISO.Pakistan, '92'], 233 | ['Palau', CountryISO.Palau, '680'], 234 | ['Palestine (‫فلسطين‬‎)', CountryISO.Palestine, '970'], 235 | ['Panama (Panamá)', CountryISO.Panama, '507'], 236 | ['Papua New Guinea', CountryISO.PapuaNewGuinea, '675'], 237 | ['Paraguay', CountryISO.Paraguay, '595'], 238 | ['Peru (Perú)', CountryISO.Peru, '51'], 239 | ['Philippines', CountryISO.Philippines, '63'], 240 | ['Poland (Polska)', CountryISO.Poland, '48'], 241 | ['Portugal', CountryISO.Portugal, '351'], 242 | ['Puerto Rico', CountryISO.PuertoRico, '1', 3, ['787', '939']], 243 | ['Qatar (‫قطر‬‎)', CountryISO.Qatar, '974'], 244 | ['Réunion (La Réunion)', CountryISO.Réunion, '262', 0], 245 | ['Romania (România)', CountryISO.Romania, '40'], 246 | ['Russia (Россия)', CountryISO.Russia, '7', 0], 247 | ['Rwanda', CountryISO.Rwanda, '250'], 248 | ['Saint Barthélemy (Saint-Barthélemy)', CountryISO.SaintBarthélemy, '590', 1], 249 | ['Saint Helena', CountryISO.SaintHelena, '290'], 250 | ['Saint Kitts and Nevis', CountryISO.SaintKittsAndNevis, '1869'], 251 | ['Saint Lucia', 'lc', '1', 1, ['758']], 252 | ['Saint Martin (Saint-Martin (partie française))', CountryISO.SaintMartin, '590', 2], 253 | [ 254 | 'Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)', 255 | CountryISO.SaintPierreAndMiquelon, 256 | '508', 257 | ], 258 | ['Saint Vincent and the Grenadines', 'vc', '1', 1, ['784']], 259 | ['Samoa', CountryISO.Samoa, '685'], 260 | ['San Marino', CountryISO.SanMarino, '378'], 261 | ['São Tomé and Príncipe (São Tomé e Príncipe)', CountryISO.SãoToméAndPríncipe, '239'], 262 | ['Saudi Arabia (‫المملكة العربية السعودية‬‎)', CountryISO.SaudiArabia, '966'], 263 | ['Senegal (Sénégal)', CountryISO.Senegal, '221'], 264 | ['Serbia (Србија)', CountryISO.Serbia, '381'], 265 | ['Seychelles', CountryISO.Seychelles, '248'], 266 | ['Sierra Leone', CountryISO.SierraLeone, '232'], 267 | ['Singapore', CountryISO.Singapore, '65'], 268 | ['Sint Maarten', 'sx', '1', 1, ['721']], 269 | ['Slovakia (Slovensko)', CountryISO.Slovakia, '421'], 270 | ['Slovenia (Slovenija)', CountryISO.Slovenia, '386'], 271 | ['Solomon Islands', CountryISO.SolomonIslands, '677'], 272 | ['Somalia (Soomaaliya)', CountryISO.Somalia, '252'], 273 | ['South Africa', CountryISO.SouthAfrica, '27'], 274 | ['South Korea (대한민국)', CountryISO.SouthKorea, '82'], 275 | ['South Sudan (‫جنوب السودان‬‎)', CountryISO.SouthSudan, '211'], 276 | ['Spain (España)', CountryISO.Spain, '34'], 277 | ['Sri Lanka (ශ්‍රී ලංකාව)', CountryISO.SriLanka, '94'], 278 | ['Sudan (‫السودان‬‎)', CountryISO.Sudan, '249'], 279 | ['Suriname', CountryISO.Suriname, '597'], 280 | ['Svalbard and Jan Mayen', CountryISO.SvalbardAndJanMayen, '47', 1], 281 | ['Swaziland', CountryISO.Swaziland, '268'], 282 | ['Sweden (Sverige)', CountryISO.Sweden, '46'], 283 | ['Switzerland (Schweiz)', CountryISO.Switzerland, '41'], 284 | ['Syria (‫سوريا‬‎)', CountryISO.Syria, '963'], 285 | ['Taiwan (台灣)', CountryISO.Taiwan, '886'], 286 | ['Tajikistan', CountryISO.Tajikistan, '992'], 287 | ['Tanzania', CountryISO.Tanzania, '255'], 288 | ['Thailand (ไทย)', CountryISO.Thailand, '66'], 289 | ['Timor-Leste', CountryISO.TimorLeste, '670'], 290 | ['Togo', CountryISO.Togo, '228'], 291 | ['Tokelau', CountryISO.Tokelau, '690'], 292 | ['Tonga', CountryISO.Tonga, '676'], 293 | ['Trinidad and Tobago', 'tt', '1', 1, ['868']], 294 | ['Tunisia (‫تونس‬‎)', CountryISO.Tunisia, '216'], 295 | ['Turkey (Türkiye)', CountryISO.Turkey, '90'], 296 | ['Turkmenistan', CountryISO.Turkmenistan, '993'], 297 | ['Turks and Caicos Islands', CountryISO.TurksAndCaicosIslands, '1649'], 298 | ['Tuvalu', CountryISO.Tuvalu, '688'], 299 | ['U.S. Virgin Islands', 'vi', '1', 1, ['340']], 300 | ['Uganda', CountryISO.Uganda, '256'], 301 | ['Ukraine (Україна)', CountryISO.Ukraine, '380'], 302 | ['United Arab Emirates (‫الإمارات العربية المتحدة‬‎)', CountryISO.UnitedArabEmirates, '971'], 303 | ['United Kingdom', CountryISO.UnitedKingdom, '44', 0], 304 | ['United States', CountryISO.UnitedStates, '1', 0], 305 | ['Uruguay', CountryISO.Uruguay, '598'], 306 | ['Uzbekistan (Oʻzbekiston)', CountryISO.Uzbekistan, '998'], 307 | ['Vanuatu', CountryISO.Vanuatu, '678'], 308 | ['Vatican City (Città del Vaticano)', CountryISO.VaticanCity, '39', 1], 309 | ['Venezuela', CountryISO.Venezuela, '58'], 310 | ['Vietnam (Việt Nam)', CountryISO.Vietnam, '84'], 311 | ['Wallis and Futuna', CountryISO.WallisAndFutuna, '681'], 312 | ['Western Sahara (‫الصحراء الغربية‬‎)', CountryISO.WesternSahara, '212', 1], 313 | ['Yemen (‫اليمن‬‎)', CountryISO.Yemen, '967'], 314 | ['Zambia', CountryISO.Zambia, '260'], 315 | ['Zimbabwe', CountryISO.Zimbabwe, '263'], 316 | ['Åland Islands', CountryISO.ÅlandIslands, '358', 1], 317 | ]; 318 | } 319 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/directives/native-element-injector.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, OnInit } from '@angular/core'; 2 | import { NgControl } from '@angular/forms'; 3 | 4 | /* 5 | "Property 'nativeElement' does not exist on type 'FormControl'". 6 | 'NativeElementInjectorDirective' injects nativeElement to each control, 7 | so we can access it from inside validator for example. 8 | More about this approach and reasons for this: 9 | https://github.com/angular/angular/issues/18025 10 | https://stackoverflow.com/a/54075119/1617590 11 | */ 12 | @Directive({ 13 | // tslint:disable-next-line: directive-selector 14 | selector: '[ngModel], [formControl], [formControlName]', 15 | }) 16 | export class NativeElementInjectorDirective implements OnInit { 17 | constructor(private controlDir: NgControl, private host: ElementRef) {} 18 | ngOnInit() { 19 | if (this.controlDir.control) { 20 | // @ts-ignore 21 | this.controlDir.control['nativeElement'] = this.host.nativeElement; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/enums/country-iso.enum.ts: -------------------------------------------------------------------------------- 1 | export enum CountryISO { 2 | Afghanistan = 'af', 3 | Albania = 'al', 4 | Algeria = 'dz', 5 | AmericanSamoa = 'as', 6 | Andorra = 'ad', 7 | Angola = 'ao', 8 | Anguilla = 'ai', 9 | AntiguaAndBarbuda = 'ag', 10 | Argentina = 'ar', 11 | Armenia = 'am', 12 | Aruba = 'aw', 13 | Australia = 'au', 14 | Austria = 'at', 15 | Azerbaijan = 'az', 16 | Bahamas = 'bs', 17 | Bahrain = 'bh', 18 | Bangladesh = 'bd', 19 | Barbados = 'bb', 20 | Belarus = 'by', 21 | Belgium = 'be', 22 | Belize = 'bz', 23 | Benin = 'bj', 24 | Bermuda = 'bm', 25 | Bhutan = 'bt', 26 | Bolivia = 'bo', 27 | BosniaAndHerzegovina = 'ba', 28 | Botswana = 'bw', 29 | Brazil = 'br', 30 | BritishIndianOceanTerritory = 'io', 31 | BritishVirginIslands = 'vg', 32 | Brunei = 'bn', 33 | Bulgaria = 'bg', 34 | BurkinaFaso = 'bf', 35 | Burundi = 'bi', 36 | Cambodia = 'kh', 37 | Cameroon = 'cm', 38 | Canada = 'ca', 39 | CapeVerde = 'cv', 40 | CaribbeanNetherlands = 'bq', 41 | CaymanIslands = 'ky', 42 | CentralAfricanRepublic = 'cf', 43 | Chad = 'td', 44 | Chile = 'cl', 45 | China = 'cn', 46 | ChristmasIsland = 'cx', 47 | Cocos = 'cc', 48 | Colombia = 'co', 49 | Comoros = 'km', 50 | CongoDRCJamhuriYaKidemokrasiaYaKongo = 'cd', 51 | CongoRepublicCongoBrazzaville = 'cg', 52 | CookIslands = 'ck', 53 | CostaRica = 'cr', 54 | CôteDIvoire = 'ci', 55 | Croatia = 'hr', 56 | Cuba = 'cu', 57 | Curaçao = 'cw', 58 | Cyprus = 'cy', 59 | CzechRepublic = 'cz', 60 | Denmark = 'dk', 61 | Djibouti = 'dj', 62 | Dominica = 'dm', 63 | DominicanRepublic = 'do', 64 | Ecuador = 'ec', 65 | Egypt = 'eg', 66 | ElSalvador = 'sv', 67 | EquatorialGuinea = 'gq', 68 | Eritrea = 'er', 69 | Estonia = 'ee', 70 | Ethiopia = 'et', 71 | FalklandIslands = 'fk', 72 | FaroeIslands = 'fo', 73 | Fiji = 'fj', 74 | Finland = 'fi', 75 | France = 'fr', 76 | FrenchGuiana = 'gf', 77 | FrenchPolynesia = 'pf', 78 | Gabon = 'ga', 79 | Gambia = 'gm', 80 | Georgia = 'ge', 81 | Germany = 'de', 82 | Ghana = 'gh', 83 | Gibraltar = 'gi', 84 | Greece = 'gr', 85 | Greenland = 'gl', 86 | Grenada = 'gd', 87 | Guadeloupe = 'gp', 88 | Guam = 'gu', 89 | Guatemala = 'gt', 90 | Guernsey = 'gg', 91 | Guinea = 'gn', 92 | GuineaBissau = 'gw', 93 | Guyana = 'gy', 94 | Haiti = 'ht', 95 | Honduras = 'hn', 96 | HongKong = 'hk', 97 | Hungary = 'hu', 98 | Iceland = 'is', 99 | India = 'in', 100 | Indonesia = 'id', 101 | Iran = 'ir', 102 | Iraq = 'iq', 103 | Ireland = 'ie', 104 | IsleOfMan = 'im', 105 | Israel = 'il', 106 | Italy = 'it', 107 | Jamaica = 'jm', 108 | Japan = 'jp', 109 | Jersey = 'je', 110 | Jordan = 'jo', 111 | Kazakhstan = 'kz', 112 | Kenya = 'ke', 113 | Kiribati = 'ki', 114 | Kosovo = 'xk', 115 | Kuwait = 'kw', 116 | Kyrgyzstan = 'kg', 117 | Laos = 'la', 118 | Latvia = 'lv', 119 | Lebanon = 'lb', 120 | Lesotho = 'ls', 121 | Liberia = 'lr', 122 | Libya = 'ly', 123 | Liechtenstein = 'li', 124 | Lithuania = 'lt', 125 | Luxembourg = 'lu', 126 | Macau = 'mo', 127 | Macedonia = 'mk', 128 | Madagascar = 'mg', 129 | Malawi = 'mw', 130 | Malaysia = 'my', 131 | Maldives = 'mv', 132 | Mali = 'ml', 133 | Malta = 'mt', 134 | MarshallIslands = 'mh', 135 | Martinique = 'mq', 136 | Mauritania = 'mr', 137 | Mauritius = 'mu', 138 | Mayotte = 'yt', 139 | Mexico = 'mx', 140 | Micronesia = 'fm', 141 | Moldova = 'md', 142 | Monaco = 'mc', 143 | Mongolia = 'mn', 144 | Montenegro = 'me', 145 | Montserrat = 'ms', 146 | Morocco = 'ma', 147 | Mozambique = 'mz', 148 | Myanmar = 'mm', 149 | Namibia = 'na', 150 | Nauru = 'nr', 151 | Nepal = 'np', 152 | Netherlands = 'nl', 153 | NewCaledonia = 'nc', 154 | NewZealand = 'nz', 155 | Nicaragua = 'ni', 156 | Niger = 'ne', 157 | Nigeria = 'ng', 158 | Niue = 'nu', 159 | NorfolkIsland = 'nf', 160 | NorthKorea = 'kp', 161 | NorthernMarianaIslands = 'mp', 162 | Norway = 'no', 163 | Oman = 'om', 164 | Pakistan = 'pk', 165 | Palau = 'pw', 166 | Palestine = 'ps', 167 | Panama = 'pa', 168 | PapuaNewGuinea = 'pg', 169 | Paraguay = 'py', 170 | Peru = 'pe', 171 | Philippines = 'ph', 172 | Poland = 'pl', 173 | Portugal = 'pt', 174 | PuertoRico = 'pr', 175 | Qatar = 'qa', 176 | Réunion = 're', 177 | Romania = 'ro', 178 | Russia = 'ru', 179 | Rwanda = 'rw', 180 | SaintBarthélemy = 'bl', 181 | SaintHelena = 'sh', 182 | SaintKittsAndNevis = 'kn', 183 | SaintLucia = 'lc', 184 | SaintMartin = 'mf', 185 | SaintPierreAndMiquelon = 'pm', 186 | SaintVincentAndTheGrenadines = 'vc', 187 | Samoa = 'ws', 188 | SanMarino = 'sm', 189 | SãoToméAndPríncipe = 'st', 190 | SaudiArabia = 'sa', 191 | Senegal = 'sn', 192 | Serbia = 'rs', 193 | Seychelles = 'sc', 194 | SierraLeone = 'sl', 195 | Singapore = 'sg', 196 | SintMaarten = 'sx', 197 | Slovakia = 'sk', 198 | Slovenia = 'si', 199 | SolomonIslands = 'sb', 200 | Somalia = 'so', 201 | SouthAfrica = 'za', 202 | SouthKorea = 'kr', 203 | SouthSudan = 'ss', 204 | Spain = 'es', 205 | SriLanka = 'lk', 206 | Sudan = 'sd', 207 | Suriname = 'sr', 208 | SvalbardAndJanMayen = 'sj', 209 | Swaziland = 'sz', 210 | Sweden = 'se', 211 | Switzerland = 'ch', 212 | Syria = 'sy', 213 | Taiwan = 'tw', 214 | Tajikistan = 'tj', 215 | Tanzania = 'tz', 216 | Thailand = 'th', 217 | TimorLeste = 'tl', 218 | Togo = 'tg', 219 | Tokelau = 'tk', 220 | Tonga = 'to', 221 | TrinidadAndTobago = 'tt', 222 | Tunisia = 'tn', 223 | Turkey = 'tr', 224 | Turkmenistan = 'tm', 225 | TurksAndCaicosIslands = 'tc', 226 | Tuvalu = 'tv', 227 | USVirginIslands = 'vi', 228 | Uganda = 'ug', 229 | Ukraine = 'ua', 230 | UnitedArabEmirates = 'ae', 231 | UnitedKingdom = 'gb', 232 | UnitedStates = 'us', 233 | Uruguay = 'uy', 234 | Uzbekistan = 'uz', 235 | Vanuatu = 'vu', 236 | VaticanCity = 'va', 237 | Venezuela = 've', 238 | Vietnam = 'vn', 239 | WallisAndFutuna = 'wf', 240 | WesternSahara = 'eh', 241 | Yemen = 'ye', 242 | Zambia = 'zm', 243 | Zimbabwe = 'zw', 244 | ÅlandIslands = 'ax', 245 | } 246 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/enums/phone-number-format.enum.ts: -------------------------------------------------------------------------------- 1 | export enum PhoneNumberFormat { 2 | International = 'INTERNATIONAL', 3 | National = 'NATIONAL', 4 | } 5 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/enums/search-country-field.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SearchCountryField { 2 | DialCode = 'dialCode', 3 | Iso2 = 'iso2', 4 | Name = 'name', 5 | All = 'all', 6 | } 7 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/interfaces/change-data.ts: -------------------------------------------------------------------------------- 1 | export interface ChangeData { 2 | number?: string; 3 | internationalNumber?: string; 4 | nationalNumber?: string; 5 | e164Number?: string; 6 | countryCode?: string; 7 | dialCode?: string; 8 | } 9 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/model/country.model.ts: -------------------------------------------------------------------------------- 1 | export interface Country { 2 | name: string; 3 | iso2: string; 4 | dialCode: string; 5 | priority: number; 6 | areaCodes?: string[]; 7 | htmlId: string; 8 | flagClass: string; 9 | placeHolder: string; 10 | } 11 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/ngx-intl-tel-input.component.css: -------------------------------------------------------------------------------- 1 | li.iti__country:hover { 2 | background-color: rgba(0, 0, 0, 0.05); 3 | } 4 | .iti__selected-flag.dropdown-toggle:after { 5 | content: none; 6 | } 7 | .iti__flag-container.disabled { 8 | cursor: default !important; 9 | } 10 | .iti.iti--allow-dropdown .flag-container.disabled:hover .iti__selected-flag { 11 | background: none; 12 | } 13 | .iti__dropdown-content { 14 | border: 1px solid #ccc; 15 | width: fit-content; 16 | padding: 1px; 17 | border-collapse: collapse; 18 | } 19 | .search-container { 20 | position: relative; 21 | } 22 | .search-container input { 23 | width: 100%; 24 | border: none; 25 | border-bottom: 1px solid #ccc; 26 | padding-left: 10px; 27 | } 28 | .search-icon { 29 | position: absolute; 30 | z-index: 2; 31 | width: 25px; 32 | margin: 1px 10px; 33 | } 34 | .iti__country-list { 35 | position: relative; 36 | border: none; 37 | /* max-height: 170px; */ 38 | } 39 | 40 | .iti input#country-search-box { 41 | padding-left: 6px; 42 | } 43 | 44 | .iti .selected-dial-code { 45 | margin-left: 6px; 46 | } 47 | 48 | .iti.separate-dial-code .iti__selected-flag, 49 | .iti.separate-dial-code.iti--allow-dropdown.iti-sdc-2 .iti__selected-flag, 50 | .iti.separate-dial-code.iti--allow-dropdown.iti-sdc-3 .iti__selected-flag, 51 | .iti.separate-dial-code.iti--allow-dropdown.iti-sdc-4 .iti__selected-flag { 52 | width: 93px; 53 | } 54 | 55 | .iti.separate-dial-code input, 56 | .iti.separate-dial-code.iti--allow-dropdown.iti-sdc-2 input, 57 | .iti.separate-dial-code.iti--allow-dropdown.iti-sdc-3 input, 58 | .iti.separate-dial-code.iti--allow-dropdown.iti-sdc-4 input { 59 | padding-left: 98px; 60 | } 61 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/ngx-intl-tel-input.component.html: -------------------------------------------------------------------------------- 1 |
2 |
8 | 13 | 52 |
53 | 69 |
70 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/ngx-intl-tel-input.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NgxIntlTelInputComponent } from './ngx-intl-tel-input.component'; 4 | 5 | describe('NgxIntlTelInputComponent', () => { 6 | let component: NgxIntlTelInputComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [NgxIntlTelInputComponent], 12 | }).compileComponents(); 13 | })); 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(NgxIntlTelInputComponent); 17 | component = fixture.componentInstance; 18 | fixture.detectChanges(); 19 | }); 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/ngx-intl-tel-input.component.ts: -------------------------------------------------------------------------------- 1 | import * as lpn from 'google-libphonenumber'; 2 | 3 | import { 4 | Component, 5 | ElementRef, 6 | EventEmitter, 7 | forwardRef, 8 | Input, 9 | OnChanges, 10 | OnInit, 11 | Output, 12 | SimpleChanges, 13 | ViewChild, 14 | } from '@angular/core'; 15 | import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; 16 | 17 | import { setTheme } from 'ngx-bootstrap/utils'; 18 | 19 | import { CountryCode } from './data/country-code'; 20 | import { CountryISO } from './enums/country-iso.enum'; 21 | import { SearchCountryField } from './enums/search-country-field.enum'; 22 | import { ChangeData } from './interfaces/change-data'; 23 | import { Country } from './model/country.model'; 24 | import { phoneNumberValidator } from './ngx-intl-tel-input.validator'; 25 | import { PhoneNumberFormat } from './enums/phone-number-format.enum'; 26 | 27 | @Component({ 28 | // tslint:disable-next-line: component-selector 29 | selector: 'ngx-intl-tel-input', 30 | templateUrl: './ngx-intl-tel-input.component.html', 31 | styleUrls: ['./bootstrap-dropdown.css', './ngx-intl-tel-input.component.css'], 32 | providers: [ 33 | CountryCode, 34 | { 35 | provide: NG_VALUE_ACCESSOR, 36 | // tslint:disable-next-line:no-forward-ref 37 | useExisting: forwardRef(() => NgxIntlTelInputComponent), 38 | multi: true, 39 | }, 40 | { 41 | provide: NG_VALIDATORS, 42 | useValue: phoneNumberValidator, 43 | multi: true, 44 | }, 45 | ], 46 | }) 47 | export class NgxIntlTelInputComponent implements OnInit, OnChanges { 48 | @Input() value: string | undefined = ''; 49 | @Input() preferredCountries: Array = []; 50 | @Input() enablePlaceholder = true; 51 | @Input() customPlaceholder: string; 52 | @Input() numberFormat: PhoneNumberFormat = PhoneNumberFormat.International; 53 | @Input() cssClass = 'form-control'; 54 | @Input() onlyCountries: Array = []; 55 | @Input() enableAutoCountrySelect = true; 56 | @Input() searchCountryFlag = false; 57 | @Input() searchCountryField: SearchCountryField[] = [SearchCountryField.All]; 58 | @Input() searchCountryPlaceholder = 'Search Country'; 59 | @Input() maxLength: number; 60 | @Input() selectFirstCountry = true; 61 | @Input() selectedCountryISO: CountryISO; 62 | @Input() phoneValidation = true; 63 | @Input() inputId = 'phone'; 64 | @Input() separateDialCode = false; 65 | separateDialCodeClass: string; 66 | 67 | @Output() readonly countryChange = new EventEmitter(); 68 | 69 | selectedCountry: Country = { 70 | areaCodes: undefined, 71 | dialCode: '', 72 | htmlId: '', 73 | flagClass: '', 74 | iso2: '', 75 | name: '', 76 | placeHolder: '', 77 | priority: 0, 78 | }; 79 | 80 | phoneNumber: string | undefined = ''; 81 | allCountries: Array = []; 82 | preferredCountriesInDropDown: Array = []; 83 | // Has to be 'any' to prevent a need to install @types/google-libphonenumber by the package user... 84 | phoneUtil: any = lpn.PhoneNumberUtil.getInstance(); 85 | disabled = false; 86 | errors: Array = ['Phone number is required.']; 87 | countrySearchText = ''; 88 | 89 | @ViewChild('countryList') countryList: ElementRef; 90 | 91 | onTouched = () => {}; 92 | propagateChange = (_: ChangeData) => {}; 93 | 94 | constructor(private countryCodeData: CountryCode) { 95 | // If this is not set, ngx-bootstrap will try to use the bs3 CSS (which is not what we've embedded) and will 96 | // Add the wrong classes and such 97 | setTheme('bs4'); 98 | } 99 | 100 | ngOnInit() { 101 | this.init(); 102 | } 103 | 104 | ngOnChanges(changes: SimpleChanges) { 105 | const selectedISO = changes['selectedCountryISO']; 106 | if ( 107 | this.allCountries && 108 | selectedISO && 109 | selectedISO.currentValue !== selectedISO.previousValue 110 | ) { 111 | this.updateSelectedCountry(); 112 | } 113 | if (changes['preferredCountries']) { 114 | this.updatePreferredCountries(); 115 | } 116 | this.checkSeparateDialCodeStyle(); 117 | } 118 | 119 | /* 120 | This is a wrapper method to avoid calling this.ngOnInit() in writeValue(). 121 | Ref: http://codelyzer.com/rules/no-life-cycle-call/ 122 | */ 123 | init() { 124 | this.fetchCountryData(); 125 | if (this.preferredCountries.length) { 126 | this.updatePreferredCountries(); 127 | } 128 | if (this.onlyCountries.length) { 129 | this.allCountries = this.allCountries.filter(c => this.onlyCountries.includes(c.iso2)); 130 | } 131 | if (this.selectFirstCountry) { 132 | if (this.preferredCountriesInDropDown.length) { 133 | this.setSelectedCountry(this.preferredCountriesInDropDown[0]); 134 | } else { 135 | this.setSelectedCountry(this.allCountries[0]); 136 | } 137 | } 138 | this.updateSelectedCountry(); 139 | this.checkSeparateDialCodeStyle(); 140 | } 141 | 142 | setSelectedCountry(country: Country) { 143 | this.selectedCountry = country; 144 | this.countryChange.emit(country); 145 | } 146 | 147 | /** 148 | * Search country based on country name, iso2, dialCode or all of them. 149 | */ 150 | public searchCountry() { 151 | if (!this.countrySearchText) { 152 | this.countryList.nativeElement.querySelector('.iti__country-list li').scrollIntoView({ 153 | behavior: 'smooth', 154 | block: 'nearest', 155 | inline: 'nearest', 156 | }); 157 | return; 158 | } 159 | const countrySearchTextLower = this.countrySearchText.toLowerCase(); 160 | // @ts-ignore 161 | const country = this.allCountries.filter(c => { 162 | if (this.searchCountryField.indexOf(SearchCountryField.All) > -1) { 163 | // Search in all fields 164 | if (c.iso2.toLowerCase().startsWith(countrySearchTextLower)) { 165 | return c; 166 | } 167 | if (c.name.toLowerCase().startsWith(countrySearchTextLower)) { 168 | return c; 169 | } 170 | if (c.dialCode.startsWith(this.countrySearchText)) { 171 | return c; 172 | } 173 | } else { 174 | // Or search by specific SearchCountryField(s) 175 | if (this.searchCountryField.indexOf(SearchCountryField.Iso2) > -1) { 176 | if (c.iso2.toLowerCase().startsWith(countrySearchTextLower)) { 177 | return c; 178 | } 179 | } 180 | if (this.searchCountryField.indexOf(SearchCountryField.Name) > -1) { 181 | if (c.name.toLowerCase().startsWith(countrySearchTextLower)) { 182 | return c; 183 | } 184 | } 185 | if (this.searchCountryField.indexOf(SearchCountryField.DialCode) > -1) { 186 | if (c.dialCode.startsWith(this.countrySearchText)) { 187 | return c; 188 | } 189 | } 190 | } 191 | }); 192 | 193 | if (country.length > 0) { 194 | const el = this.countryList.nativeElement.querySelector('#' + country[0].htmlId); 195 | if (el) { 196 | el.scrollIntoView({ 197 | behavior: 'smooth', 198 | block: 'nearest', 199 | inline: 'nearest', 200 | }); 201 | } 202 | } 203 | 204 | this.checkSeparateDialCodeStyle(); 205 | } 206 | 207 | public onPhoneNumberChange(): void { 208 | let countryCode: string | undefined; 209 | // Handle the case where the user sets the value programatically based on a persisted ChangeData obj. 210 | if (this.phoneNumber && typeof this.phoneNumber === 'object') { 211 | const numberObj: ChangeData = this.phoneNumber; 212 | this.phoneNumber = numberObj.number; 213 | countryCode = numberObj.countryCode; 214 | } 215 | 216 | this.value = this.phoneNumber; 217 | countryCode = countryCode || this.selectedCountry.iso2; 218 | // @ts-ignore 219 | const number = this.getParsedNumber(this.phoneNumber, countryCode); 220 | 221 | // auto select country based on the extension (and areaCode if needed) (e.g select Canada if number starts with +1 416) 222 | if (this.enableAutoCountrySelect) { 223 | countryCode = 224 | number && number.getCountryCode() 225 | ? // @ts-ignore 226 | this.getCountryIsoCode(number.getCountryCode(), number) 227 | : this.selectedCountry.iso2; 228 | if (countryCode && countryCode !== this.selectedCountry.iso2) { 229 | const newCountry = this.allCountries 230 | .slice() 231 | .sort((a, b) => { 232 | return a.priority - b.priority; 233 | }) 234 | .find(c => c.iso2 === countryCode); 235 | if (newCountry) { 236 | this.selectedCountry = newCountry; 237 | } 238 | } 239 | } 240 | countryCode = countryCode ? countryCode : this.selectedCountry.iso2; 241 | 242 | this.checkSeparateDialCodeStyle(); 243 | 244 | if (!this.value) { 245 | // Reason: avoid https://stackoverflow.com/a/54358133/1617590 246 | // tslint:disable-next-line: no-null-keyword 247 | // @ts-ignore 248 | this.propagateChange(null); 249 | } else { 250 | const intlNo = number 251 | ? this.phoneUtil.format(number, lpn.PhoneNumberFormat.INTERNATIONAL) 252 | : ''; 253 | 254 | // parse phoneNumber if separate dial code is needed 255 | if (this.separateDialCode && intlNo) { 256 | this.value = this.removeDialCode(intlNo); 257 | } 258 | 259 | this.propagateChange({ 260 | number: this.value, 261 | internationalNumber: intlNo, 262 | nationalNumber: number ? this.phoneUtil.format(number, lpn.PhoneNumberFormat.NATIONAL) : '', 263 | e164Number: number ? this.phoneUtil.format(number, lpn.PhoneNumberFormat.E164) : '', 264 | countryCode: countryCode.toUpperCase(), 265 | dialCode: '+' + this.selectedCountry.dialCode, 266 | }); 267 | } 268 | } 269 | 270 | public onCountrySelect(country: Country, el: { focus: () => void }): void { 271 | this.setSelectedCountry(country); 272 | 273 | this.checkSeparateDialCodeStyle(); 274 | 275 | if (this.phoneNumber && this.phoneNumber.length > 0) { 276 | this.value = this.phoneNumber; 277 | const number = this.getParsedNumber(this.phoneNumber, this.selectedCountry.iso2); 278 | const intlNo = number 279 | ? this.phoneUtil.format(number, lpn.PhoneNumberFormat.INTERNATIONAL) 280 | : ''; 281 | // parse phoneNumber if separate dial code is needed 282 | if (this.separateDialCode && intlNo) { 283 | this.value = this.removeDialCode(intlNo); 284 | } 285 | 286 | this.propagateChange({ 287 | number: this.value, 288 | internationalNumber: intlNo, 289 | nationalNumber: number ? this.phoneUtil.format(number, lpn.PhoneNumberFormat.NATIONAL) : '', 290 | e164Number: number ? this.phoneUtil.format(number, lpn.PhoneNumberFormat.E164) : '', 291 | countryCode: this.selectedCountry.iso2.toUpperCase(), 292 | dialCode: '+' + this.selectedCountry.dialCode, 293 | }); 294 | } else { 295 | // Reason: avoid https://stackoverflow.com/a/54358133/1617590 296 | // tslint:disable-next-line: no-null-keyword 297 | // @ts-ignore 298 | this.propagateChange(null); 299 | } 300 | 301 | el.focus(); 302 | } 303 | 304 | public onInputKeyPress(event: KeyboardEvent): void { 305 | const allowedChars = /[0-9\+\-\(\)\ ]/; 306 | const allowedCtrlChars = /[axcv]/; // Allows copy-pasting 307 | const allowedOtherKeys = [ 308 | 'ArrowLeft', 309 | 'ArrowUp', 310 | 'ArrowRight', 311 | 'ArrowDown', 312 | 'Home', 313 | 'End', 314 | 'Insert', 315 | 'Delete', 316 | 'Backspace', 317 | ]; 318 | 319 | if ( 320 | !allowedChars.test(event.key) && 321 | !(event.ctrlKey && allowedCtrlChars.test(event.key)) && 322 | !allowedOtherKeys.includes(event.key) 323 | ) { 324 | event.preventDefault(); 325 | } 326 | } 327 | 328 | registerOnChange(fn: any): void { 329 | this.propagateChange = fn; 330 | } 331 | 332 | registerOnTouched(fn: any) { 333 | this.onTouched = fn; 334 | } 335 | 336 | setDisabledState(isDisabled: boolean): void { 337 | this.disabled = isDisabled; 338 | } 339 | 340 | writeValue(obj: any): void { 341 | if (obj === undefined) { 342 | this.init(); 343 | } 344 | this.phoneNumber = obj; 345 | setTimeout(() => { 346 | this.onPhoneNumberChange(); 347 | }, 1); 348 | } 349 | 350 | resolvePlaceholder(): string { 351 | let placeholder = ''; 352 | if (this.customPlaceholder) { 353 | placeholder = this.customPlaceholder; 354 | } else if (this.selectedCountry.placeHolder) { 355 | placeholder = this.selectedCountry.placeHolder; 356 | if (this.separateDialCode) { 357 | placeholder = this.removeDialCode(placeholder); 358 | } 359 | } 360 | return placeholder; 361 | } 362 | 363 | /* --------------------------------- Helpers -------------------------------- */ 364 | /** 365 | * Returns parse PhoneNumber object. 366 | * @param phoneNumber string 367 | * @param countryCode string 368 | */ 369 | private getParsedNumber(phoneNumber: string, countryCode: string): lpn.PhoneNumber { 370 | let number: lpn.PhoneNumber; 371 | try { 372 | number = this.phoneUtil.parse(phoneNumber, countryCode.toUpperCase()); 373 | } catch (e) {} 374 | // @ts-ignore 375 | return number; 376 | } 377 | 378 | /** 379 | * Adjusts input alignment based on the dial code presentation style. 380 | */ 381 | private checkSeparateDialCodeStyle() { 382 | if (this.separateDialCode && this.selectedCountry) { 383 | const cntryCd = this.selectedCountry.dialCode; 384 | this.separateDialCodeClass = 'separate-dial-code iti-sdc-' + (cntryCd.length + 1); 385 | } else { 386 | this.separateDialCodeClass = ''; 387 | } 388 | } 389 | 390 | /** 391 | * Cleans dialcode from phone number string. 392 | * @param phoneNumber string 393 | */ 394 | private removeDialCode(phoneNumber: string): string { 395 | const number = this.getParsedNumber(phoneNumber, this.selectedCountry.iso2); 396 | phoneNumber = this.phoneUtil.format(number, lpn.PhoneNumberFormat[this.numberFormat]); 397 | if (phoneNumber.startsWith('+') && this.separateDialCode) { 398 | phoneNumber = phoneNumber.substr(phoneNumber.indexOf(' ') + 1); 399 | } 400 | return phoneNumber; 401 | } 402 | 403 | /** 404 | * Sifts through all countries and returns iso code of the primary country 405 | * based on the number provided. 406 | * @param countryCode country code in number format 407 | * @param number PhoneNumber object 408 | */ 409 | private getCountryIsoCode(countryCode: number, number: lpn.PhoneNumber): string | undefined { 410 | // Will use this to match area code from the first numbers 411 | // @ts-ignore 412 | const rawNumber = number['values_']['2'].toString(); 413 | // List of all countries with countryCode (can be more than one. e.x. US, CA, DO, PR all have +1 countryCode) 414 | const countries = this.allCountries.filter(c => c.dialCode === countryCode.toString()); 415 | // Main country is the country, which has no areaCodes specified in country-code.ts file. 416 | const mainCountry = countries.find(c => c.areaCodes === undefined); 417 | // Secondary countries are all countries, which have areaCodes specified in country-code.ts file. 418 | const secondaryCountries = countries.filter(c => c.areaCodes !== undefined); 419 | let matchedCountry = mainCountry ? mainCountry.iso2 : undefined; 420 | 421 | /* 422 | Iterate over each secondary country and check if nationalNumber starts with any of areaCodes available. 423 | If no matches found, fallback to the main country. 424 | */ 425 | secondaryCountries.forEach(country => { 426 | // @ts-ignore 427 | country.areaCodes.forEach(areaCode => { 428 | if (rawNumber.startsWith(areaCode)) { 429 | matchedCountry = country.iso2; 430 | } 431 | }); 432 | }); 433 | 434 | return matchedCountry; 435 | } 436 | 437 | /** 438 | * Gets formatted example phone number from phoneUtil. 439 | * @param countryCode string 440 | */ 441 | protected getPhoneNumberPlaceHolder(countryCode: string): string { 442 | try { 443 | return this.phoneUtil.format( 444 | this.phoneUtil.getExampleNumber(countryCode), 445 | lpn.PhoneNumberFormat[this.numberFormat] 446 | ); 447 | } catch (e) { 448 | // @ts-ignore 449 | return e; 450 | } 451 | } 452 | 453 | /** 454 | * Clearing the list to avoid duplicates (https://github.com/webcat12345/ngx-intl-tel-input/issues/248) 455 | */ 456 | protected fetchCountryData(): void { 457 | this.allCountries = []; 458 | 459 | this.countryCodeData.allCountries.forEach(c => { 460 | const country: Country = { 461 | name: c[0].toString(), 462 | iso2: c[1].toString(), 463 | dialCode: c[2].toString(), 464 | priority: +c[3] || 0, 465 | areaCodes: (c[4] as string[]) || undefined, 466 | htmlId: `iti-0__item-${c[1].toString()}`, 467 | flagClass: `iti__${c[1].toString().toLocaleLowerCase()}`, 468 | placeHolder: '', 469 | }; 470 | 471 | if (this.enablePlaceholder) { 472 | country.placeHolder = this.getPhoneNumberPlaceHolder(country.iso2.toUpperCase()); 473 | } 474 | 475 | this.allCountries.push(country); 476 | }); 477 | } 478 | 479 | /** 480 | * Populates preferredCountriesInDropDown with prefferred countries. 481 | */ 482 | private updatePreferredCountries() { 483 | if (this.preferredCountries.length) { 484 | this.preferredCountriesInDropDown = []; 485 | this.preferredCountries.forEach(iso2 => { 486 | const preferredCountry = this.allCountries.filter(c => { 487 | return c.iso2 === iso2; 488 | }); 489 | 490 | this.preferredCountriesInDropDown.push(preferredCountry[0]); 491 | }); 492 | } 493 | } 494 | 495 | /** 496 | * Updates selectedCountry. 497 | */ 498 | private updateSelectedCountry() { 499 | if (this.selectedCountryISO) { 500 | // @ts-ignore 501 | this.selectedCountry = this.allCountries.find(c => { 502 | return c.iso2.toLowerCase() === this.selectedCountryISO.toLowerCase(); 503 | }); 504 | if (this.selectedCountry) { 505 | if (this.phoneNumber) { 506 | this.onPhoneNumberChange(); 507 | } else { 508 | // Reason: avoid https://stackoverflow.com/a/54358133/1617590 509 | // tslint:disable-next-line: no-null-keyword 510 | // @ts-ignore 511 | this.propagateChange(null); 512 | } 513 | } 514 | } 515 | } 516 | } 517 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/ngx-intl-tel-input.module.ts: -------------------------------------------------------------------------------- 1 | import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; 2 | 3 | import { CommonModule } from '@angular/common'; 4 | import { NgModule, ModuleWithProviders } from '@angular/core'; 5 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 6 | 7 | import { NativeElementInjectorDirective } from './directives/native-element-injector.directive'; 8 | import { NgxIntlTelInputComponent } from './ngx-intl-tel-input.component'; 9 | 10 | export const dropdownModuleForRoot: ModuleWithProviders = 11 | BsDropdownModule.forRoot(); 12 | 13 | @NgModule({ 14 | declarations: [NgxIntlTelInputComponent, NativeElementInjectorDirective], 15 | imports: [CommonModule, FormsModule, ReactiveFormsModule, dropdownModuleForRoot], 16 | exports: [NgxIntlTelInputComponent, NativeElementInjectorDirective], 17 | }) 18 | export class NgxIntlTelInputModule {} 19 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/lib/ngx-intl-tel-input.validator.ts: -------------------------------------------------------------------------------- 1 | import * as lpn from 'google-libphonenumber'; 2 | 3 | /* 4 | We use "control: any" instead of "control: FormControl" to silence: 5 | "Property 'nativeElement' does not exist on type 'FormControl'". 6 | This happens because I've expanded control with nativeElement via 7 | 'NativeElementInjectorDirective' to get an access to the element. 8 | More about this approach and reasons for this: 9 | https://github.com/angular/angular/issues/18025 10 | https://stackoverflow.com/a/54075119/1617590 11 | */ 12 | export const phoneNumberValidator = (control: any) => { 13 | if (!control.value) { 14 | return; 15 | } 16 | // Find inside injected nativeElement and get its "id". 17 | const el: HTMLElement = control.nativeElement as HTMLElement; 18 | const inputBox: HTMLInputElement | any = el ? el.querySelector('input[type="tel"]') : undefined; 19 | if (inputBox) { 20 | const id = inputBox.id; 21 | const isCheckValidation = inputBox.getAttribute('validation'); 22 | if (isCheckValidation === 'true') { 23 | const isRequired = control.errors && control.errors.required === true; 24 | const error = { validatePhoneNumber: { valid: false } }; 25 | 26 | inputBox.setCustomValidity('Invalid field.'); 27 | 28 | let number: lpn.PhoneNumber; 29 | 30 | try { 31 | number = lpn.PhoneNumberUtil.getInstance().parse( 32 | control.value.number, 33 | control.value.countryCode 34 | ); 35 | } catch (e) { 36 | if (isRequired) { 37 | return error; 38 | } else { 39 | inputBox.setCustomValidity(''); 40 | } 41 | } 42 | 43 | if (control.value) { 44 | // @ts-ignore 45 | if (!number) { 46 | return error; 47 | } else { 48 | if ( 49 | !lpn.PhoneNumberUtil.getInstance().isValidNumberForRegion( 50 | number, 51 | control.value.countryCode 52 | ) 53 | ) { 54 | return error; 55 | } else { 56 | inputBox.setCustomValidity(''); 57 | } 58 | } 59 | } 60 | } else if (isCheckValidation === 'false') { 61 | inputBox.setCustomValidity(''); 62 | 63 | control.clearValidators(); 64 | } 65 | } 66 | return; 67 | }; 68 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/public_api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ngx-intl-tel-input 3 | */ 4 | 5 | export * from './lib/ngx-intl-tel-input.component'; 6 | export * from './lib/directives/native-element-injector.directive'; 7 | export * from './lib/ngx-intl-tel-input.module'; 8 | export * from './lib/enums/country-iso.enum'; 9 | export * from './lib/enums/search-country-field.enum'; 10 | export * from './lib/enums/phone-number-format.enum'; 11 | export * from './lib/interfaces/change-data'; 12 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'core-js/proposals/reflect-metadata'; 4 | import 'zone.js'; 5 | import 'zone.js/testing'; 6 | import { getTestBed } from '@angular/core/testing'; 7 | import { 8 | BrowserDynamicTestingModule, 9 | platformBrowserDynamicTesting, 10 | } from '@angular/platform-browser-dynamic/testing'; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); 14 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../../out-tsc/lib", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [] 10 | }, 11 | "exclude": [ 12 | "src/test.ts", 13 | "**/*.spec.ts" 14 | ], 15 | "angularCompilerOptions": { 16 | "compilationMode": "partial" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /projects/ngx-intl-tel-input/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.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 | -------------------------------------------------------------------------------- /readme-assets/ngx-intl-tel-input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webcat12345/ngx-intl-tel-input/b23777932b75dff4a035cb27ee59c2fa258567dc/readme-assets/ngx-intl-tel-input.jpg -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webcat12345/ngx-intl-tel-input/b23777932b75dff4a035cb27ee59c2fa258567dc/src/app/app.component.css -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Test International Telephone Input Form

4 |
5 |
6 | 7 |
8 |
9 | 10 | 11 |
12 |
13 |
14 | 30 | 31 |
32 |
33 | 34 |
35 |
36 |
37 |
38 | Is input valid: 39 |
{{ !f.form.controls['phone'].invalid }}
40 |
41 |
42 | Is input touched: 43 |
{{ f.form.controls['phone'].touched }}
44 |
45 |
46 | Is form valid: 47 |
{{ f.form.valid }}
48 |
49 |
50 | Form value: 51 |
{{ f.form.value | json }}
52 |
53 |
54 | Form validation errors: 55 |
{{ f.form.controls['phone'].errors | json }}
56 |
57 |
58 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [AppComponent], 9 | }).compileComponents(); 10 | })); 11 | 12 | it('should create the app', () => { 13 | const fixture = TestBed.createComponent(AppComponent); 14 | const app = fixture.debugElement.componentInstance; 15 | expect(app).toBeTruthy(); 16 | }); 17 | 18 | it(`should have as title 'ngx-intl-tel-input-app'`, () => { 19 | const fixture = TestBed.createComponent(AppComponent); 20 | const app = fixture.debugElement.componentInstance; 21 | expect(app.title).toEqual('ngx-intl-tel-input-app'); 22 | }); 23 | 24 | it('should render title in a h1 tag', () => { 25 | const fixture = TestBed.createComponent(AppComponent); 26 | fixture.detectChanges(); 27 | const compiled = fixture.debugElement.nativeElement; 28 | expect(compiled.querySelector('h1').textContent).toContain( 29 | 'Welcome to ngx-intl-tel-input-app!' 30 | ); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FormControl, FormGroup, Validators } from '@angular/forms'; 3 | 4 | import { CountryISO } from 'projects/ngx-intl-tel-input/src/lib/enums/country-iso.enum'; 5 | import { PhoneNumberFormat } from 'projects/ngx-intl-tel-input/src/public_api'; 6 | import { SearchCountryField } from 'projects/ngx-intl-tel-input/src/lib/enums/search-country-field.enum'; 7 | 8 | @Component({ 9 | selector: 'app-root', 10 | templateUrl: './app.component.html', 11 | styleUrls: ['./app.component.css'], 12 | }) 13 | export class AppComponent { 14 | separateDialCode = false; 15 | SearchCountryField = SearchCountryField; 16 | CountryISO = CountryISO; 17 | PhoneNumberFormat = PhoneNumberFormat; 18 | preferredCountries: CountryISO[] = [CountryISO.UnitedStates, CountryISO.UnitedKingdom]; 19 | phoneForm = new FormGroup({ 20 | phone: new FormControl(undefined, [Validators.required]), 21 | }); 22 | 23 | changePreferredCountries() { 24 | this.preferredCountries = [CountryISO.India, CountryISO.Canada]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 5 | 6 | import { NgxIntlTelInputModule } from 'projects/ngx-intl-tel-input/src/lib/ngx-intl-tel-input.module'; 7 | 8 | import { AppComponent } from './app.component'; 9 | 10 | @NgModule({ 11 | declarations: [AppComponent], 12 | imports: [ 13 | BrowserModule, 14 | FormsModule, 15 | ReactiveFormsModule, 16 | NgxIntlTelInputModule, 17 | BrowserAnimationsModule, 18 | ], 19 | providers: [], 20 | bootstrap: [AppComponent], 21 | }) 22 | export class AppModule {} 23 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webcat12345/ngx-intl-tel-input/b23777932b75dff4a035cb27ee59c2fa258567dc/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webcat12345/ngx-intl-tel-input/b23777932b75dff4a035cb27ee59c2fa258567dc/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NgxIntlTelInputApp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/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'), 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 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /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() 12 | .bootstrapModule(AppModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /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 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js'; // Included with Angular CLI. 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | body { 3 | font-family: Roboto, Helvetica, Arial, sans-serif; 4 | } 5 | 6 | .wrapper { 7 | margin-bottom: 20px; 8 | } 9 | 10 | /***************************************************** 11 | Custom styling example bellow. 12 | *****************************************************/ 13 | 14 | .iti { 15 | display: block !important; 16 | margin-bottom: 20px; 17 | } 18 | 19 | .iti .dropdown-menu.iti__dropdown-content { 20 | border-top-left-radius: 0px; 21 | border-top-right-radius: 0px; 22 | border-color: #c7cace; 23 | margin-top: -1px; 24 | } 25 | 26 | .iti .iti__country-list { 27 | box-shadow: none; 28 | font-size: 14px; 29 | margin-left: 0; 30 | width: 244px; 31 | max-height: 170px; 32 | } 33 | 34 | .iti__flag-container.open + input { 35 | border-bottom-left-radius: 0px; 36 | border-bottom-right-radius: 0px; 37 | } 38 | 39 | .iti .search-container input { 40 | font-size: 14px; 41 | border-color: #c7cace; 42 | border-radius: 0; 43 | padding: 5px 10px; 44 | } 45 | 46 | .iti .search-container input:focus { 47 | outline: none; 48 | } 49 | 50 | @media screen and (max-width: 479px) { 51 | .iti .iti__country-list { 52 | width: 88.3vw; 53 | } 54 | } 55 | 56 | ngx-intl-tel-input input { 57 | height: 44px; 58 | margin-bottom: 20px; 59 | padding: 10px; 60 | border-style: solid; 61 | border-width: 1px; 62 | border-color: #c7cace; 63 | border-radius: 4px; 64 | font-size: 18px; 65 | } 66 | 67 | ngx-intl-tel-input.ng-invalid.ng-touched input { 68 | border: 1px solid #c0392b; 69 | } 70 | 71 | ngx-intl-tel-input input:hover { 72 | box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.24); 73 | } 74 | 75 | ngx-intl-tel-input input:focus { 76 | outline: none !important; 77 | border-color: #3498db; 78 | box-shadow: 0 0 0 0 #000; 79 | } 80 | 81 | ngx-intl-tel-input input::-webkit-input-placeholder { 82 | color: #bac2c7; 83 | } 84 | 85 | ngx-intl-tel-input input:-ms-input-placeholder { 86 | color: #bac2c7; 87 | } 88 | 89 | ngx-intl-tel-input input::-ms-input-placeholder { 90 | color: #bac2c7; 91 | } 92 | 93 | ngx-intl-tel-input input::placeholder { 94 | color: #bac2c7; 95 | } 96 | 97 | ngx-intl-tel-input input[disabled] { 98 | background-color: #e5eaf1; 99 | } 100 | -------------------------------------------------------------------------------- /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 | // First, initialize the Angular testing environment. 11 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); 12 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": ["main.ts", "polyfills.ts"], 8 | "include": ["src/**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": ["jasmine", "node"] 6 | }, 7 | "files": ["test.ts", "polyfills.ts"], 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "paths": { 15 | "my-lib": [ 16 | "dist/my-lib/my-lib", 17 | "dist/my-lib" 18 | ] 19 | }, 20 | "declaration": false, 21 | "downlevelIteration": true, 22 | "experimentalDecorators": true, 23 | "moduleResolution": "node", 24 | "strictPropertyInitialization": false, 25 | "importHelpers": true, 26 | "target": "es2022", 27 | "module": "es2022", 28 | "lib": [ 29 | "es2022", 30 | "dom" 31 | ], 32 | "useDefineForClassFields": false 33 | }, 34 | "angularCompilerOptions": { 35 | "enableI18nLegacyMessageIdFormat": false, 36 | "strictInjectionParameters": true, 37 | "strictInputAccessModifiers": true, 38 | "strictTemplates": true 39 | } 40 | } 41 | --------------------------------------------------------------------------------