├── .editorconfig ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json └── tasks.json ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── src ├── app │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.config.ts │ ├── app.routes.ts │ ├── pages │ │ ├── employee-form │ │ │ ├── employee-form.component.html │ │ │ ├── employee-form.component.scss │ │ │ ├── employee-form.component.spec.ts │ │ │ └── employee-form.component.ts │ │ ├── employee │ │ │ ├── employee.component.html │ │ │ ├── employee.component.scss │ │ │ ├── employee.component.spec.ts │ │ │ └── employee.component.ts │ │ └── shared │ │ │ ├── models │ │ │ └── Employee.ts │ │ │ └── ui │ │ │ └── model │ │ │ ├── model.component.html │ │ │ ├── model.component.scss │ │ │ ├── model.component.spec.ts │ │ │ └── model.component.ts │ └── services │ │ ├── employee.service.spec.ts │ │ └── employee.service.ts ├── assets │ └── .gitkeep ├── favicon.ico ├── index.html ├── main.ts └── styles.scss ├── tailwind.config.js ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 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 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ng17CrudApp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.0. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "ng17-crud-app": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:application", 19 | "options": { 20 | "outputPath": "dist/ng17-crud-app", 21 | "index": "src/index.html", 22 | "browser": "src/main.ts", 23 | "polyfills": [ 24 | "zone.js" 25 | ], 26 | "tsConfig": "tsconfig.app.json", 27 | "inlineStyleLanguage": "scss", 28 | "assets": [ 29 | "src/favicon.ico", 30 | "src/assets" 31 | ], 32 | "styles": [ 33 | "src/styles.scss" 34 | ], 35 | "scripts": [] 36 | }, 37 | "configurations": { 38 | "production": { 39 | "budgets": [ 40 | { 41 | "type": "initial", 42 | "maximumWarning": "500kb", 43 | "maximumError": "1mb" 44 | }, 45 | { 46 | "type": "anyComponentStyle", 47 | "maximumWarning": "2kb", 48 | "maximumError": "4kb" 49 | } 50 | ], 51 | "outputHashing": "all" 52 | }, 53 | "development": { 54 | "optimization": false, 55 | "extractLicenses": false, 56 | "sourceMap": true 57 | } 58 | }, 59 | "defaultConfiguration": "production" 60 | }, 61 | "serve": { 62 | "builder": "@angular-devkit/build-angular:dev-server", 63 | "configurations": { 64 | "production": { 65 | "buildTarget": "ng17-crud-app:build:production" 66 | }, 67 | "development": { 68 | "buildTarget": "ng17-crud-app:build:development" 69 | } 70 | }, 71 | "defaultConfiguration": "development" 72 | }, 73 | "extract-i18n": { 74 | "builder": "@angular-devkit/build-angular:extract-i18n", 75 | "options": { 76 | "buildTarget": "ng17-crud-app:build" 77 | } 78 | }, 79 | "test": { 80 | "builder": "@angular-devkit/build-angular:karma", 81 | "options": { 82 | "polyfills": [ 83 | "zone.js", 84 | "zone.js/testing" 85 | ], 86 | "tsConfig": "tsconfig.spec.json", 87 | "inlineStyleLanguage": "scss", 88 | "assets": [ 89 | "src/favicon.ico", 90 | "src/assets" 91 | ], 92 | "styles": [ 93 | "src/styles.scss" 94 | ], 95 | "scripts": [] 96 | } 97 | } 98 | } 99 | } 100 | }, 101 | "cli": { 102 | "analytics": false 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng17-crud-app", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^17.0.0", 14 | "@angular/common": "^17.0.0", 15 | "@angular/compiler": "^17.0.0", 16 | "@angular/core": "^17.0.0", 17 | "@angular/forms": "^17.0.0", 18 | "@angular/platform-browser": "^17.0.0", 19 | "@angular/platform-browser-dynamic": "^17.0.0", 20 | "@angular/router": "^17.0.0", 21 | "ngx-toastr": "^18.0.0", 22 | "rxjs": "~7.8.0", 23 | "tslib": "^2.3.0", 24 | "zone.js": "~0.14.2" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "^17.0.0", 28 | "@angular/cli": "^17.0.0", 29 | "@angular/compiler-cli": "^17.0.0", 30 | "@types/jasmine": "~5.1.0", 31 | "autoprefixer": "^10.4.16", 32 | "jasmine-core": "~5.1.0", 33 | "karma": "~6.4.0", 34 | "karma-chrome-launcher": "~3.2.0", 35 | "karma-coverage": "~2.2.0", 36 | "karma-jasmine": "~5.1.0", 37 | "karma-jasmine-html-reporter": "~2.1.0", 38 | "postcss": "^8.4.32", 39 | "tailwindcss": "^3.4.0", 40 | "typescript": "~5.2.2" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdcoders/ng17-crud-app/c5b9c3c491700cc681cdd92573dd1386a69a54b1/src/app/app.component.scss -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async () => { 6 | await TestBed.configureTestingModule({ 7 | imports: [AppComponent], 8 | }).compileComponents(); 9 | }); 10 | 11 | it('should create the app', () => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.componentInstance; 14 | expect(app).toBeTruthy(); 15 | }); 16 | 17 | it(`should have the 'ng17-crud-app' title`, () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app.title).toEqual('ng17-crud-app'); 21 | }); 22 | 23 | it('should render title', () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | fixture.detectChanges(); 26 | const compiled = fixture.nativeElement as HTMLElement; 27 | expect(compiled.querySelector('h1')?.textContent).toContain('Hello, ng17-crud-app'); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterOutlet } from '@angular/router'; 4 | 5 | @Component({ 6 | selector: 'app-root', 7 | standalone: true, 8 | imports: [CommonModule, RouterOutlet], 9 | templateUrl: './app.component.html', 10 | styleUrls: ['./app.component.scss'] 11 | }) 12 | export class AppComponent { 13 | title = 'ng17-crud-app'; 14 | } 15 | -------------------------------------------------------------------------------- /src/app/app.config.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationConfig, importProvidersFrom } from '@angular/core'; 2 | import { provideRouter } from '@angular/router'; 3 | import { provideAnimations } from '@angular/platform-browser/animations'; 4 | import { routes } from './app.routes'; 5 | import { HttpClientModule } from '@angular/common/http'; 6 | import { provideToastr } from 'ngx-toastr'; 7 | 8 | export const appConfig: ApplicationConfig = { 9 | providers: [ 10 | provideRouter(routes), 11 | importProvidersFrom(HttpClientModule), 12 | provideAnimations(), 13 | provideToastr({ 14 | timeOut: 5000, 15 | positionClass: 'toast-top-center', 16 | preventDuplicates: true, 17 | }), 18 | ], 19 | }; 20 | -------------------------------------------------------------------------------- /src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | import { EmployeeComponent } from './pages/employee/employee.component'; 3 | 4 | export const routes: Routes = [{ path: '', component: EmployeeComponent }]; 5 | -------------------------------------------------------------------------------- /src/app/pages/employee-form/employee-form.component.html: -------------------------------------------------------------------------------- 1 |
Employee Details
2 |
3 |
4 | 5 | 6 | @if (employeeForm.get('name')?.hasError('required') && employeeForm.get('name')?.touched) { 7 |
Name is required
8 | } 9 |
10 |
11 | 12 | 13 | @if (employeeForm.get('email')?.hasError('required') && employeeForm.get('email')?.touched) { 14 |
Email is required
15 | } 16 |
17 |
18 | 19 | 20 | @if (employeeForm.get('mobile')?.hasError('required') && employeeForm.get('mobile')?.touched) { 21 |
Mobile is required
22 | } 23 |
24 |
25 | 26 | 27 | @if (employeeForm.get('dob')?.hasError('required') && employeeForm.get('dob')?.touched) { 28 |
Date of Birth is required
29 | } 30 |
31 |
32 | 33 | 34 | @if (employeeForm.get('doj')?.hasError('required') && employeeForm.get('doj')?.touched) { 35 |
Date of Joining is required
36 | } 37 |
38 | 40 | 42 |
-------------------------------------------------------------------------------- /src/app/pages/employee-form/employee-form.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdcoders/ng17-crud-app/c5b9c3c491700cc681cdd92573dd1386a69a54b1/src/app/pages/employee-form/employee-form.component.scss -------------------------------------------------------------------------------- /src/app/pages/employee-form/employee-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EmployeeFormComponent } from './employee-form.component'; 4 | 5 | describe('EmployeeFormComponent', () => { 6 | let component: EmployeeFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [EmployeeFormComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(EmployeeFormComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/pages/employee-form/employee-form.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | EventEmitter, 4 | Input, 5 | OnChanges, 6 | Output, 7 | } from '@angular/core'; 8 | import { IEmployee } from '../shared/models/Employee'; 9 | import { 10 | FormGroup, 11 | FormBuilder, 12 | FormControl, 13 | Validators, 14 | ReactiveFormsModule, 15 | } from '@angular/forms'; 16 | import { CommonModule, formatDate } from '@angular/common'; 17 | import { RouterModule } from '@angular/router'; 18 | import { EmployeeService } from '../../services/employee.service'; 19 | import { ToastrService } from 'ngx-toastr'; 20 | @Component({ 21 | selector: 'app-employee-form', 22 | standalone: true, 23 | imports: [CommonModule, ReactiveFormsModule, RouterModule], 24 | templateUrl: './employee-form.component.html', 25 | styleUrl: './employee-form.component.scss', 26 | }) 27 | export class EmployeeFormComponent implements OnChanges { 28 | @Input() data: IEmployee | null = null; 29 | @Output() onCloseModel = new EventEmitter(); 30 | 31 | employeeForm!: FormGroup; 32 | 33 | constructor( 34 | private fb: FormBuilder, 35 | private employeeService: EmployeeService, 36 | private toastr: ToastrService 37 | ) { 38 | this.employeeForm = this.fb.group({ 39 | name: new FormControl('', [Validators.required]), 40 | email: new FormControl('', [Validators.required, Validators.email]), 41 | mobile: new FormControl('', [Validators.required]), 42 | dob: new FormControl('', [Validators.required]), 43 | doj: new FormControl('', [Validators.required]), 44 | }); 45 | } 46 | 47 | onClose() { 48 | this.onCloseModel.emit(false); 49 | } 50 | 51 | ngOnChanges(): void { 52 | if (this.data) { 53 | this.employeeForm.patchValue({ 54 | name: this.data.name, 55 | email: this.data.email, 56 | mobile: this.data.mobile, 57 | dob: formatDate(this.data.dob, 'yyyy-MM-dd', 'en'), 58 | doj: this.data.doj, 59 | }); 60 | } 61 | } 62 | 63 | onSubmit() { 64 | if (this.employeeForm.valid) { 65 | if (this.data) { 66 | this.employeeService 67 | .updateEmployee(this.data._id as string, this.employeeForm.value) 68 | .subscribe({ 69 | next: (response: any) => { 70 | this.resetEmployeeForm(); 71 | this.toastr.success(response.message); 72 | }, 73 | }); 74 | } else { 75 | this.employeeService.createEmployee(this.employeeForm.value).subscribe({ 76 | next: (response: any) => { 77 | this.resetEmployeeForm(); 78 | this.toastr.success(response.message); 79 | }, 80 | }); 81 | } 82 | } else { 83 | this.employeeForm.markAllAsTouched(); 84 | } 85 | } 86 | 87 | resetEmployeeForm() { 88 | this.employeeForm.reset(); 89 | this.onClose(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/app/pages/employee/employee.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | 6 |
7 |
8 | 9 | 13 | 14 | 15 | 18 | 21 | 24 | 27 | 30 | 31 | 32 | 33 | @for (item of employees; track $index) { 34 | 35 | 38 | 41 | 44 | 47 | 53 | 54 | } 55 | 56 |
11 | Manage Employees 12 |
16 | Name 17 | 19 | Email 20 | 22 | Mobile 23 | 25 | DOB 26 | 28 | Edit 29 |
36 | {{item.name}} 37 | 39 | {{item.email}} 40 | 42 | {{item.mobile}} 43 | 45 | {{item.dob}} 46 | 48 | 50 | 52 |
57 |
58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/app/pages/employee/employee.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdcoders/ng17-crud-app/c5b9c3c491700cc681cdd92573dd1386a69a54b1/src/app/pages/employee/employee.component.scss -------------------------------------------------------------------------------- /src/app/pages/employee/employee.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EmployeeComponent } from './employee.component'; 4 | 5 | describe('EmployeeComponent', () => { 6 | let component: EmployeeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [EmployeeComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(EmployeeComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/pages/employee/employee.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ModelComponent } from '../shared/ui/model/model.component'; 3 | import { EmployeeFormComponent } from '../employee-form/employee-form.component'; 4 | import { ToastrService } from 'ngx-toastr'; 5 | import { EmployeeService } from '../../services/employee.service'; 6 | import { IEmployee } from '../shared/models/Employee'; 7 | @Component({ 8 | selector: 'app-employee', 9 | standalone: true, 10 | imports: [ModelComponent, EmployeeFormComponent], 11 | templateUrl: './employee.component.html', 12 | styleUrl: './employee.component.scss', 13 | }) 14 | export class EmployeeComponent implements OnInit { 15 | isModelOpen = false; 16 | employees: IEmployee[] = []; 17 | employee!: IEmployee; 18 | 19 | constructor( 20 | private employeeService: EmployeeService, 21 | private toastr: ToastrService 22 | ) {} 23 | 24 | ngOnInit(): void { 25 | this.getAllEmployee(); 26 | } 27 | 28 | getAllEmployee() { 29 | this.employeeService.getAllEmployee().subscribe({ 30 | next: (response) => { 31 | if (response.data) { 32 | this.employees = response.data; 33 | } 34 | }, 35 | }); 36 | } 37 | 38 | loadEmployee(employee: IEmployee) { 39 | this.employee = employee; 40 | this.openModel(); 41 | } 42 | 43 | deleteEmployee(id: string) { 44 | this.employeeService.deleteEmployee(id).subscribe({ 45 | next: (response) => { 46 | this.toastr.success(response.message); 47 | this.getAllEmployee(); 48 | }, 49 | }); 50 | } 51 | 52 | openModel() { 53 | this.isModelOpen = true; 54 | } 55 | 56 | closeModel() { 57 | this.isModelOpen = false; 58 | this.getAllEmployee(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/app/pages/shared/models/Employee.ts: -------------------------------------------------------------------------------- 1 | export interface ApiResponse { 2 | message?: string; 3 | data: T; 4 | } 5 | 6 | export interface IEmployee { 7 | _id?: string; 8 | name: string; 9 | email: string; 10 | mobile: string; 11 | dob: string; 12 | doj: string; 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/shared/ui/model/model.component.html: -------------------------------------------------------------------------------- 1 | @if (isOpen) { 2 |
3 |
4 | 5 |
6 |
7 |
8 | } -------------------------------------------------------------------------------- /src/app/pages/shared/ui/model/model.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdcoders/ng17-crud-app/c5b9c3c491700cc681cdd92573dd1386a69a54b1/src/app/pages/shared/ui/model/model.component.scss -------------------------------------------------------------------------------- /src/app/pages/shared/ui/model/model.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ModelComponent } from './model.component'; 4 | 5 | describe('ModelComponent', () => { 6 | let component: ModelComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ModelComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ModelComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/pages/shared/ui/model/model.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | @Component({ 5 | selector: 'app-model', 6 | standalone: true, 7 | imports: [], 8 | templateUrl: './model.component.html', 9 | styleUrl: './model.component.scss', 10 | }) 11 | export class ModelComponent { 12 | @Input() isOpen = false; 13 | @Output() closeModel = new EventEmitter(); 14 | 15 | onCloseModel() { 16 | this.closeModel.emit(false); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/app/services/employee.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { EmployeeService } from './employee.service'; 4 | 5 | describe('EmployeeService', () => { 6 | let service: EmployeeService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(EmployeeService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/services/employee.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | import { ApiResponse, IEmployee } from '../pages/shared/models/Employee'; 5 | 6 | @Injectable({ 7 | providedIn: 'root', 8 | }) 9 | export class EmployeeService { 10 | apiurl = 'http://localhost:4000/employee'; 11 | constructor(private http: HttpClient) {} 12 | 13 | getAllEmployee(): Observable> { 14 | return this.http.get>(`${this.apiurl}`); 15 | } 16 | 17 | getEmployee(id: string): Observable> { 18 | return this.http.get>(`${this.apiurl}/${id}`); 19 | } 20 | 21 | createEmployee(employee: IEmployee): Observable { 22 | return this.http.post(`${this.apiurl}`, employee); 23 | } 24 | 25 | updateEmployee(id: string, employee: IEmployee): Observable { 26 | return this.http.put(`${this.apiurl}/${id}`, employee); 27 | } 28 | 29 | deleteEmployee(id: string): Observable> { 30 | return this.http.delete>(`${this.apiurl}/${id}`); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdcoders/ng17-crud-app/c5b9c3c491700cc681cdd92573dd1386a69a54b1/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdcoders/ng17-crud-app/c5b9c3c491700cc681cdd92573dd1386a69a54b1/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ng17CrudApp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { bootstrapApplication } from '@angular/platform-browser'; 2 | import { appConfig } from './app/app.config'; 3 | import { AppComponent } from './app/app.component'; 4 | 5 | bootstrapApplication(AppComponent, appConfig) 6 | .catch((err) => console.error(err)); 7 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Roboto:100,100italic,300,300italic,regular,italic,500,500italic,700,700italic,900,900italic); 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | @import "ngx-toastr/toastr"; 6 | body { 7 | font-family: "Roboto", sans-serif; 8 | font-size: 1rem; 9 | @apply bg-slate-50; 10 | } 11 | 12 | @layer components { 13 | .form-control { 14 | @apply bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500; 15 | } 16 | 17 | .form-error { 18 | @apply text-red-600 text-sm mt-1; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ["./src/**/*.{html,js}"], 3 | theme: { 4 | container: { 5 | center: true, 6 | padding: { 7 | DEFAULT: "1rem", 8 | sm: "2rem", 9 | lg: "4rem", 10 | xl: "5rem", 11 | "2xl": "6rem", 12 | }, 13 | }, 14 | extend: {}, 15 | }, 16 | plugins: [], 17 | }; 18 | -------------------------------------------------------------------------------- /tsconfig.app.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/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "outDir": "./dist/out-tsc", 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "esModuleInterop": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "lib": [ 23 | "ES2022", 24 | "dom" 25 | ] 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tsconfig.spec.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/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | --------------------------------------------------------------------------------