├── src ├── assets │ └── .gitkeep ├── app │ ├── app.component.scss │ ├── app.component.html │ ├── app-routing.module.ts │ ├── shared │ │ ├── interface │ │ │ └── user.interface.ts │ │ ├── helper │ │ │ └── subscription.helper.ts │ │ └── service │ │ │ └── user.service.ts │ ├── app.component.ts │ ├── app.module.ts │ └── view │ │ └── user │ │ ├── user-routing.module.ts │ │ ├── delete │ │ ├── delete.component.scss │ │ ├── delete.component.html │ │ └── delete.component.ts │ │ ├── user.module.ts │ │ ├── index │ │ ├── index.component.html │ │ ├── index.component.ts │ │ └── index.component.scss │ │ ├── create │ │ ├── create.component.scss │ │ ├── create.component.ts │ │ └── create.component.html │ │ └── edit │ │ ├── edit.component.scss │ │ ├── edit.component.ts │ │ └── edit.component.html ├── favicon.ico ├── styles.scss ├── environments │ ├── environment.common.ts │ ├── environment.ts │ ├── environment.production.ts │ └── environment.development.ts ├── main.ts └── index.html ├── server ├── mock │ └── user │ │ ├── db.json │ │ └── index.js ├── json-generator.js ├── json-server.js └── generator │ └── user │ └── index.js ├── nodemon.json ├── .vscode ├── extensions.json ├── settings.json ├── launch.json └── tasks.json ├── .prettierrc.json ├── tsconfig.app.json ├── .editorconfig ├── .prettierignore ├── .eslintignore ├── .gitignore ├── tsconfig.json ├── .eslintrc.json ├── README.md ├── package.json └── angular.json /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/mock/user/db.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /server/json-generator.js: -------------------------------------------------------------------------------- 1 | const generateUsers = require('./generator/user'); 2 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudhakar-jonnakuti/angular-mock-jsonserver/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | body { 2 | color: #566787; 3 | background: #f5f5f5; 4 | font-family: 'Varela Round', sans-serif; 5 | font-size: 13px; 6 | } 7 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": [ 3 | "server" 4 | ], 5 | "ext": ".js", 6 | "exec": "npm run server:generator && npm run server:json-server" 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /src/environments/environment.common.ts: -------------------------------------------------------------------------------- 1 | export const commonEnv = { 2 | production: false, 3 | environmentName: 'development', 4 | baseUrl: 'http://localhost:3000/api/', 5 | }; 6 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | import { commonEnv } from './environment.common'; 2 | 3 | const env: Partial = {}; 4 | 5 | export const environment = Object.assign(commonEnv, env); 6 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | 3 | import { AppModule } from './app/app.module'; 4 | 5 | platformBrowserDynamic() 6 | .bootstrapModule(AppModule) 7 | .catch(err => console.error(err)); 8 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | "singleQuote": true, 5 | "semi": true, 6 | "bracketSpacing": true, 7 | "arrowParens": "avoid", 8 | "trailingComma": "es5", 9 | "bracketSameLine": true, 10 | "printWidth": 80, 11 | "endOfLine": "auto" 12 | } 13 | -------------------------------------------------------------------------------- /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": ["src/main.ts"], 9 | "include": ["src/**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /src/environments/environment.production.ts: -------------------------------------------------------------------------------- 1 | import { commonEnv } from './environment.common'; 2 | 3 | const env: Partial = { 4 | production: true, 5 | environmentName: 'production', 6 | baseUrl: 'http://portal-service/api/', 7 | }; 8 | 9 | export const environment = Object.assign(commonEnv, env); 10 | -------------------------------------------------------------------------------- /src/environments/environment.development.ts: -------------------------------------------------------------------------------- 1 | import { commonEnv } from './environment.common'; 2 | 3 | const env: Partial = { 4 | production: false, 5 | environmentName: 'development', 6 | baseUrl: 'http://localhost:3000/api/', 7 | }; 8 | 9 | export const environment = Object.assign(commonEnv, env); 10 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | const routes: Routes = [ 5 | { path: '', redirectTo: 'user/index', pathMatch: 'full' }, 6 | ]; 7 | 8 | @NgModule({ 9 | imports: [RouterModule.forRoot(routes)], 10 | exports: [RouterModule], 11 | }) 12 | export class AppRoutingModule {} 13 | -------------------------------------------------------------------------------- /src/app/shared/interface/user.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IUser { 2 | id: number; 3 | name: string; 4 | email: string; 5 | address: string; 6 | phone: number; 7 | } 8 | 9 | export interface IResponse { 10 | statusCode: number; 11 | payload: T; 12 | } 13 | 14 | export type IUsersResponse = IResponse; 15 | export type IUserResponse = IResponse; 16 | -------------------------------------------------------------------------------- /server/json-server.js: -------------------------------------------------------------------------------- 1 | const jsonServer = require('json-server'); 2 | const userModule = require('./mock/user'); 3 | 4 | const server = jsonServer.create(); 5 | const middleware = jsonServer.defaults({ 6 | logger: true, 7 | noCors: false 8 | }); 9 | 10 | server.use(middleware); 11 | server.use(jsonServer.bodyParser); 12 | 13 | userModule(server); 14 | 15 | server.listen(3000, () => { 16 | console.log('JSON Server is running'); 17 | }); 18 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[html]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll.eslint": true 6 | }, 7 | "editor.formatOnSave": false 8 | }, 9 | "[typescript]": { 10 | "editor.defaultFormatter": "dbaeumer.vscode-eslint", 11 | "editor.codeActionsOnSave": { 12 | "source.fixAll.eslint": true 13 | }, 14 | "editor.formatOnSave": false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { environment } from '@environments/environment'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.scss'], 8 | }) 9 | export class AppComponent { 10 | private _environmentName: string; 11 | 12 | constructor() { 13 | this._environmentName = environment.environmentName; 14 | console.log('Environment: ', this._environmentName); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { HttpClientModule } from '@angular/common/http'; 4 | 5 | import { AppRoutingModule } from './app-routing.module'; 6 | import { AppComponent } from './app.component'; 7 | import { UserModule } from '@view/user/user.module'; 8 | 9 | @NgModule({ 10 | declarations: [AppComponent], 11 | imports: [BrowserModule, AppRoutingModule, UserModule, HttpClientModule], 12 | providers: [], 13 | bootstrap: [AppComponent], 14 | }) 15 | export class AppModule {} 16 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Compiled output 2 | /dist 3 | /tmp 4 | /out-tsc 5 | /bazel-out 6 | 7 | # Node 8 | /node_modules 9 | npm-debug.log 10 | yarn-error.log 11 | 12 | # IDEs and editors 13 | .idea/ 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | *.sublime-workspace 20 | 21 | # Visual Studio Code 22 | .vscode/* 23 | !.vscode/settings.json 24 | !.vscode/tasks.json 25 | !.vscode/launch.json 26 | !.vscode/extensions.json 27 | .history/* 28 | 29 | # Miscellaneous 30 | /.angular/cache 31 | .sass-cache/ 32 | /connect.lock 33 | /coverage 34 | /libpeerconnection.log 35 | testem.log 36 | /typings 37 | 38 | # System files 39 | .DS_Store 40 | Thumbs.db 41 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Compiled output 2 | /dist 3 | /tmp 4 | /out-tsc 5 | /bazel-out 6 | /server 7 | 8 | # Node 9 | /node_modules 10 | npm-debug.log 11 | yarn-error.log 12 | 13 | # IDEs and editors 14 | .idea/ 15 | .project 16 | .classpath 17 | .c9/ 18 | *.launch 19 | .settings/ 20 | *.sublime-workspace 21 | 22 | # Visual Studio Code 23 | .vscode/* 24 | !.vscode/settings.json 25 | !.vscode/tasks.json 26 | !.vscode/launch.json 27 | !.vscode/extensions.json 28 | .history/* 29 | 30 | # Miscellaneous 31 | /.angular/cache 32 | .sass-cache/ 33 | /connect.lock 34 | /coverage 35 | /libpeerconnection.log 36 | testem.log 37 | /typings 38 | 39 | # System files 40 | .DS_Store 41 | Thumbs.db 42 | -------------------------------------------------------------------------------- /src/app/shared/helper/subscription.helper.ts: -------------------------------------------------------------------------------- 1 | import { Subscription } from 'rxjs/internal/Subscription'; 2 | 3 | class SubscriptionHelper { 4 | private subs: Subscription[] = []; 5 | 6 | private isValidSubscription(sub: Subscription) { 7 | return sub && typeof sub.unsubscribe === 'function'; 8 | } 9 | 10 | set add(sub: Subscription) { 11 | if (this.isValidSubscription(sub)) { 12 | this.subs.push(sub); 13 | } 14 | } 15 | 16 | public unsubscribe() { 17 | this.subs.forEach( 18 | (sub: Subscription) => this.isValidSubscription(sub) && sub.unsubscribe() 19 | ); 20 | this.subs = []; 21 | } 22 | } 23 | 24 | export default SubscriptionHelper; 25 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/app/view/user/user-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { IndexComponent } from './index/index.component'; 4 | import { CreateComponent } from './create/create.component'; 5 | import { EditComponent } from './edit/edit.component'; 6 | 7 | const routes: Routes = [ 8 | { path: 'user', redirectTo: 'user/index', pathMatch: 'full' }, 9 | { path: 'user/index', component: IndexComponent }, 10 | { path: 'user/create', component: CreateComponent }, 11 | { path: 'user/:id/edit', component: EditComponent }, 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forChild(routes)], 16 | exports: [RouterModule], 17 | }) 18 | export class UserRoutingModule {} 19 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularMockInmemory 6 | 7 | 10 | 11 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /server/generator/user/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { faker } = require('@faker-js/faker'); 3 | 4 | function createRandomUser(number) { 5 | const userData = []; 6 | while (number >= 0) { 7 | userData.push({ 8 | id: faker.string.nanoid(10), 9 | name: faker.internet.userName(), 10 | email: faker.internet.email(), 11 | address: faker.location.streetAddress(), 12 | phone: faker.phone.number('#####-#####'), 13 | }); 14 | number--; 15 | } 16 | return userData; 17 | } 18 | 19 | let dataObj = createRandomUser(5); 20 | 21 | fs.writeFileSync( 22 | 'server/mock/user/db.json', 23 | JSON.stringify(dataObj, null, '\t'), 24 | function (err) { 25 | if (err) { 26 | return console.log(err); 27 | } else { 28 | console.log('Mock data generated.'); 29 | } 30 | } 31 | ); 32 | -------------------------------------------------------------------------------- /src/app/view/user/delete/delete.component.scss: -------------------------------------------------------------------------------- 1 | .modal-header, 2 | .modal-body, 3 | .modal-footer { 4 | padding: 15px 30px; 5 | } 6 | 7 | .modal-footer { 8 | background: #ecf0f1; 9 | border-radius: 0 0 3px 3px; 10 | } 11 | 12 | .modal-title { 13 | display: inline-block; 14 | } 15 | 16 | .form-control { 17 | border-radius: 2px; 18 | box-shadow: none; 19 | border-color: #dddddd; 20 | } 21 | 22 | textarea.form-control { 23 | resize: vertical; 24 | } 25 | 26 | .btn { 27 | border-radius: 2px; 28 | min-width: 100px; 29 | } 30 | 31 | button.close { 32 | border: 0; 33 | background-color: transparent; 34 | float: right; 35 | font-size: 1.5rem; 36 | font-weight: 700; 37 | line-height: 1; 38 | color: #000; 39 | text-shadow: 0 1px 0 #fff; 40 | opacity: 0.5; 41 | } 42 | 43 | form label { 44 | font-weight: normal; 45 | } 46 | -------------------------------------------------------------------------------- /src/app/view/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import { IndexComponent } from './index/index.component'; 6 | import { CreateComponent } from '@view/user/create/create.component'; 7 | import { EditComponent } from '@view/user/edit/edit.component'; 8 | import { UserRoutingModule } from '@view/user/user-routing.module'; 9 | import { ReactiveFormsModule } from '@angular/forms'; 10 | import { DeleteComponent } from '@view/user/delete/delete.component'; 11 | 12 | @NgModule({ 13 | declarations: [ 14 | IndexComponent, 15 | CreateComponent, 16 | EditComponent, 17 | DeleteComponent, 18 | ], 19 | imports: [CommonModule, ReactiveFormsModule, NgbModule, UserRoutingModule], 20 | }) 21 | export class UserModule {} 22 | -------------------------------------------------------------------------------- /src/app/view/user/delete/delete.component.html: -------------------------------------------------------------------------------- 1 |
2 | 12 | 19 | 31 |
32 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./src", 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 | "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": ["ES2022", "dom"], 23 | "resolveJsonModule": true, 24 | "paths": { 25 | "@shared/*": ["app/shared/*"], 26 | "@service/*": ["app/shared/service/*"], 27 | "@view/*": ["app/view/*"], 28 | "@environments/*": ["environments/*"] 29 | } 30 | }, 31 | "angularCompilerOptions": { 32 | "enableI18nLegacyMessageIdFormat": false, 33 | "strictInjectionParameters": true, 34 | "strictInputAccessModifiers": true, 35 | "strictTemplates": true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["projects/**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.js"], 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:@angular-eslint/recommended", 11 | "plugin:@angular-eslint/template/process-inline-templates", 12 | "plugin:prettier/recommended" 13 | ], 14 | "rules": { 15 | "@angular-eslint/directive-selector": [ 16 | "error", 17 | { 18 | "type": "attribute", 19 | "prefix": "app", 20 | "style": "camelCase" 21 | } 22 | ], 23 | "@angular-eslint/component-selector": [ 24 | "error", 25 | { 26 | "type": "element", 27 | "prefix": "app", 28 | "style": "kebab-case" 29 | } 30 | ] 31 | } 32 | }, 33 | { 34 | "files": ["*.html"], 35 | "extends": [ 36 | "plugin:@angular-eslint/template/recommended", 37 | "plugin:@angular-eslint/template/accessibility", 38 | "plugin:prettier/recommended" 39 | ], 40 | "rules": { 41 | "prettier/prettier": [ 42 | "error", 43 | { 44 | "parser": "angular" 45 | } 46 | ] 47 | } 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /src/app/view/user/delete/delete.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 3 | import SubscriptionHelper from '@shared/helper/subscription.helper'; 4 | 5 | import { IUser } from '@shared/interface/user.interface'; 6 | import { UserService } from '@shared/service/user.service'; 7 | 8 | @Component({ 9 | selector: 'app-delete', 10 | templateUrl: './delete.component.html', 11 | styleUrls: ['./delete.component.scss'], 12 | }) 13 | export class DeleteComponent { 14 | @Input() public user!: IUser; 15 | @Output() isUserDeleted: EventEmitter = new EventEmitter(); 16 | private _subscriptionHelper = new SubscriptionHelper(); 17 | 18 | constructor( 19 | public activeModal: NgbActiveModal, 20 | private _userService: UserService 21 | ) {} 22 | 23 | deleteRecord() { 24 | this.isUserDeleted.emit(this.user); 25 | this._userServiceDelete(this.user); 26 | } 27 | 28 | private _userServiceDelete(user: IUser) { 29 | this._subscriptionHelper.add = this._userService.delete(user.id).subscribe({ 30 | next: (response: unknown) => { 31 | console.log('User deleted successfully!', response); 32 | this.activeModal.close(this.user); 33 | }, 34 | error: (errorMessage: string) => console.log(errorMessage), 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-mock-jsonserver 2 | 3 | ``` 4 | Output: 5 | 6 | Start JsonServer:- 7 | 8 | C:\git-repo\git-angular\angular-mock-jsonserver> npm run mock:server 9 | 10 | > angular-mock-jsonserver@0.0.0 mock:server 11 | > nodemon 12 | 13 | [nodemon] 3.0.1 14 | [nodemon] to restart at any time, enter `rs` 15 | [nodemon] watching path(s): server\**\* 16 | [nodemon] watching extensions: js 17 | [nodemon] starting `npm run server:generator && npm run server:json-server` 18 | 19 | > angular-mock-jsonserver@0.0.0 server:generator 20 | > node server/json-generator.js 21 | 22 | 23 | > angular-mock-jsonserver@0.0.0 server:json-server 24 | > node server/json-server.js 25 | 26 | JSON Server is running 27 | 28 | Start Client:- 29 | 30 | C:\git-repo\git-angular\angular-mock-jsonserver> npm run start:dev 31 | 32 | > angular-mock-jsonserver@0.0.0 start:dev 33 | > ng serve --configuration development 34 | 35 | ✔ Browser application bundle generation complete. 36 | 37 | Angular Live Development Server is listening on localhost:4200, 38 | open your browser on http://localhost:4200/ 39 | 40 | Reference 41 | 42 | 1. How to Set Up a Mock Backend with Angular 13 Applications 43 | https://medium.com/geekculture/setting-up-a-mock-backend-with-angular-13-applications-26a21788f7da 44 | 45 | 2. How to create a Mock Server using Faker.js and JSON server 46 | https://itnext.io/how-to-generate-mock-data-using-faker-js-and-json-server-1d17007a08e4 47 | 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /src/app/view/user/index/index.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |

List of Users

8 |
9 | 15 |
16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 49 | 50 | 51 |
NameEmailAddressPhoneActions
{{ user.name }}{{ user.email }}{{ user.address }}{{ user.phone }} 34 | 38 | edit 39 | 40 | 44 | 45 | 46 | 47 | 48 |
52 |
53 |
54 |
55 | -------------------------------------------------------------------------------- /src/app/view/user/create/create.component.scss: -------------------------------------------------------------------------------- 1 | .card { 2 | border: 0; 3 | border-radius: 0px; 4 | margin-bottom: 30px; 5 | -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, 0.03); 6 | box-shadow: 0 2px 3px rgba(0, 0, 0, 0.03); 7 | -webkit-transition: 0.5s; 8 | transition: 0.5s; 9 | } 10 | 11 | .padding { 12 | padding: 3rem !important; 13 | } 14 | 15 | h5.card-title { 16 | font-size: 15px; 17 | } 18 | 19 | .fw-400 { 20 | font-weight: 400 !important; 21 | } 22 | 23 | .card-title { 24 | font-family: Roboto, sans-serif; 25 | font-weight: 300; 26 | line-height: 1.5; 27 | margin-bottom: 0; 28 | padding: 15px 20px; 29 | border-bottom: 1px solid rgba(77, 82, 89, 0.07); 30 | } 31 | 32 | .card-body { 33 | -ms-flex: 1 1 auto; 34 | flex: 1 1 auto; 35 | padding: 1.25rem; 36 | } 37 | 38 | .form-group { 39 | margin-bottom: 1rem; 40 | } 41 | 42 | .form-control { 43 | border-color: #ebebeb; 44 | border-radius: 2px; 45 | color: #8b95a5; 46 | padding: 5px 12px; 47 | font-size: 14px; 48 | line-height: inherit; 49 | -webkit-transition: 0.2s linear; 50 | transition: 0.2s linear; 51 | } 52 | 53 | .card-body > *:last-child { 54 | margin-bottom: 0; 55 | width: 100%; 56 | display: block; 57 | } 58 | 59 | .btn-primary { 60 | color: #fff; 61 | } 62 | 63 | .btn-bold { 64 | font-family: Roboto, sans-serif; 65 | text-transform: uppercase; 66 | font-weight: 500; 67 | font-size: 12px; 68 | } 69 | 70 | .btn-primary:hover { 71 | color: #fff; 72 | } 73 | 74 | .btn:hover { 75 | cursor: pointer; 76 | } 77 | 78 | .form-control:focus { 79 | color: #4d5259; 80 | -webkit-box-shadow: 0 0 0 0.1rem rgba(51, 202, 187, 0.15); 81 | box-shadow: 0 0 0 0.1rem rgba(51, 202, 187, 0.15); 82 | } 83 | 84 | .custom-radio { 85 | cursor: pointer; 86 | } 87 | 88 | .custom-control { 89 | display: -webkit-box; 90 | display: flex; 91 | min-width: 18px; 92 | } 93 | -------------------------------------------------------------------------------- /src/app/view/user/edit/edit.component.scss: -------------------------------------------------------------------------------- 1 | .card { 2 | border: 0; 3 | border-radius: 0px; 4 | margin-bottom: 30px; 5 | -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, 0.03); 6 | box-shadow: 0 2px 3px rgba(0, 0, 0, 0.03); 7 | -webkit-transition: 0.5s; 8 | transition: 0.5s; 9 | } 10 | 11 | .padding { 12 | padding: 3rem !important; 13 | } 14 | 15 | h5.card-title { 16 | font-size: 15px; 17 | } 18 | 19 | .fw-400 { 20 | font-weight: 400 !important; 21 | } 22 | 23 | .card-title { 24 | font-family: Roboto, sans-serif; 25 | font-weight: 300; 26 | line-height: 1.5; 27 | margin-bottom: 0; 28 | padding: 15px 20px; 29 | border-bottom: 1px solid rgba(77, 82, 89, 0.07); 30 | } 31 | 32 | .card-body { 33 | -ms-flex: 1 1 auto; 34 | flex: 1 1 auto; 35 | padding: 1.25rem; 36 | } 37 | 38 | .form-group { 39 | margin-bottom: 1rem; 40 | } 41 | 42 | .form-control { 43 | border-color: #ebebeb; 44 | border-radius: 2px; 45 | color: #8b95a5; 46 | padding: 5px 12px; 47 | font-size: 14px; 48 | line-height: inherit; 49 | -webkit-transition: 0.2s linear; 50 | transition: 0.2s linear; 51 | } 52 | 53 | .card-body > *:last-child { 54 | margin-bottom: 0; 55 | width: 100%; 56 | display: block; 57 | } 58 | 59 | .card-body > *:nth-last-child(2) { 60 | margin-bottom: 5px; 61 | width: 100%; 62 | display: block; 63 | } 64 | 65 | .btn-primary { 66 | color: #fff; 67 | } 68 | 69 | .btn-bold { 70 | font-family: Roboto, sans-serif; 71 | text-transform: uppercase; 72 | font-weight: 500; 73 | font-size: 12px; 74 | } 75 | 76 | .btn-primary:hover { 77 | color: #fff; 78 | } 79 | 80 | .btn:hover { 81 | cursor: pointer; 82 | } 83 | 84 | .form-control:focus { 85 | color: #4d5259; 86 | -webkit-box-shadow: 0 0 0 0.1rem rgba(51, 202, 187, 0.15); 87 | box-shadow: 0 0 0 0.1rem rgba(51, 202, 187, 0.15); 88 | } 89 | 90 | .custom-radio { 91 | cursor: pointer; 92 | } 93 | 94 | .custom-control { 95 | display: -webkit-box; 96 | display: flex; 97 | min-width: 18px; 98 | } 99 | -------------------------------------------------------------------------------- /src/app/shared/service/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient, HttpErrorResponse } from '@angular/common/http'; 3 | import { Observable, catchError, throwError } from 'rxjs'; 4 | 5 | import { 6 | IUser, 7 | IUserResponse, 8 | IUsersResponse, 9 | } from '@shared/interface/user.interface'; 10 | import { environment } from '@environments/environment'; 11 | 12 | @Injectable({ 13 | providedIn: 'root', 14 | }) 15 | export class UserService { 16 | private readonly _baseUrl = environment.baseUrl; 17 | 18 | constructor(private _http: HttpClient) {} 19 | 20 | public getAll(): Observable { 21 | return this._http 22 | .get(this._baseUrl + 'user') 23 | .pipe(catchError(this.errorHandler)); 24 | } 25 | 26 | public find(id: string): Observable { 27 | return this._http 28 | .get(`${this._baseUrl + 'user'}/${id}`) 29 | .pipe(catchError(this.errorHandler)); 30 | } 31 | 32 | public delete(id: number): Observable { 33 | return this._http 34 | .delete(`${this._baseUrl + 'user'}/${id}`) 35 | .pipe(catchError(this.errorHandler)); 36 | } 37 | 38 | public add(user: IUser): Observable { 39 | return this._http 40 | .post(`${this._baseUrl + 'user'}`, user) 41 | .pipe(catchError(this.errorHandler)); 42 | } 43 | 44 | public update(user: IUser): Observable { 45 | return this._http 46 | .put(`${this._baseUrl + 'user'}/${user.id}`, user) 47 | .pipe(catchError(this.errorHandler)); 48 | } 49 | 50 | errorHandler(error: HttpErrorResponse): Observable { 51 | let errorMessage = ''; 52 | if (error.error instanceof ErrorEvent) { 53 | errorMessage = error.error.message; 54 | } else { 55 | errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`; 56 | } 57 | return throwError(() => errorMessage); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-mock-jsonserver", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "start:dev": "ng serve --configuration development", 8 | "start:prd": "ng serve --configuration production", 9 | "build": "ng build", 10 | "build:dev": "ng build --configuration development", 11 | "build:prd": "ng build --configuration production", 12 | "lint": "ng lint", 13 | "prettier": "npx prettier --write .", 14 | "server:generator": "node server/json-generator.js", 15 | "server:json-server": "node server/json-server.js", 16 | "mock:server": "nodemon" 17 | }, 18 | "private": true, 19 | "dependencies": { 20 | "@angular/animations": "^16.2.0", 21 | "@angular/common": "^16.2.0", 22 | "@angular/compiler": "^16.2.0", 23 | "@angular/core": "^16.2.0", 24 | "@angular/forms": "^16.2.0", 25 | "@angular/platform-browser": "^16.2.0", 26 | "@angular/platform-browser-dynamic": "^16.2.0", 27 | "@angular/router": "^16.2.0", 28 | "@ng-bootstrap/ng-bootstrap": "^15.1.1", 29 | "bootstrap": "^5.3.1", 30 | "rxjs": "~7.8.0", 31 | "tslib": "^2.3.0", 32 | "zone.js": "~0.13.0" 33 | }, 34 | "devDependencies": { 35 | "@angular-devkit/build-angular": "^16.2.0", 36 | "@angular-eslint/builder": "16.1.0", 37 | "@angular-eslint/eslint-plugin": "16.1.0", 38 | "@angular-eslint/eslint-plugin-template": "16.1.0", 39 | "@angular-eslint/schematics": "16.1.0", 40 | "@angular-eslint/template-parser": "16.1.0", 41 | "@angular/cli": "~16.2.0", 42 | "@angular/compiler-cli": "^16.2.0", 43 | "@faker-js/faker": "^8.0.2", 44 | "@typescript-eslint/eslint-plugin": "5.62.0", 45 | "@typescript-eslint/parser": "5.62.0", 46 | "eslint": "^8.44.0", 47 | "eslint-config-prettier": "^9.0.0", 48 | "eslint-plugin-prettier": "^5.0.0", 49 | "json-server": "^0.17.3", 50 | "nodemon": "^3.0.1", 51 | "prettier": "^3.0.2", 52 | "prettier-eslint": "^15.0.1", 53 | "typescript": "~5.1.3" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/app/view/user/create/create.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, OnInit } from '@angular/core'; 2 | import { 3 | AbstractControl, 4 | FormBuilder, 5 | FormGroup, 6 | Validators, 7 | } from '@angular/forms'; 8 | import { Router } from '@angular/router'; 9 | import SubscriptionHelper from '@shared/helper/subscription.helper'; 10 | 11 | import { IUser, IUsersResponse } from '@shared/interface/user.interface'; 12 | import { UserService } from '@shared/service/user.service'; 13 | 14 | @Component({ 15 | selector: 'app-create', 16 | templateUrl: './create.component.html', 17 | styleUrls: ['./create.component.scss'], 18 | }) 19 | export class CreateComponent implements OnInit, OnDestroy { 20 | submitted = false; 21 | createForm!: FormGroup; 22 | private _subscriptionHelper = new SubscriptionHelper(); 23 | 24 | constructor( 25 | private _formBuilder: FormBuilder, 26 | private _userService: UserService, 27 | private _router: Router 28 | ) {} 29 | 30 | ngOnInit(): void { 31 | this.createFormBuilder(); 32 | } 33 | 34 | ngOnDestroy(): void { 35 | this._subscriptionHelper.unsubscribe(); 36 | } 37 | 38 | createFormBuilder() { 39 | this.createForm = this._formBuilder.group({ 40 | name: ['', Validators.required], 41 | email: ['', Validators.required], 42 | address: ['', Validators.required], 43 | phone: ['', Validators.required], 44 | }); 45 | } 46 | 47 | get fc(): { [key: string]: AbstractControl } { 48 | return this.createForm.controls; 49 | } 50 | 51 | onSubmit(): void { 52 | this.submitted = true; 53 | 54 | if (this.createForm.valid) { 55 | this._userServiceCreate(); 56 | } 57 | } 58 | 59 | private _userServiceCreate() { 60 | const id: number = Math.round(Math.random() * 1000000); 61 | const user: IUser = { id, ...this.createForm.value }; 62 | 63 | this._subscriptionHelper.add = this._userService.add(user).subscribe({ 64 | next: (response: IUsersResponse) => { 65 | console.log('User created successfully!', response); 66 | this._router.navigateByUrl('user/index'); 67 | }, 68 | error: (errorMessage: string) => console.log(errorMessage), 69 | }); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/app/view/user/index/index.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ModalDismissReasons, NgbModal } from '@ng-bootstrap/ng-bootstrap'; 3 | import SubscriptionHelper from '@shared/helper/subscription.helper'; 4 | 5 | import { IUser, IUsersResponse } from '@shared/interface/user.interface'; 6 | import { UserService } from '@shared/service/user.service'; 7 | import { DeleteComponent } from '@view/user/delete/delete.component'; 8 | 9 | @Component({ 10 | selector: 'app-index', 11 | templateUrl: './index.component.html', 12 | styleUrls: ['./index.component.scss'], 13 | }) 14 | export class IndexComponent implements OnInit { 15 | errorMessage = ''; 16 | user!: IUser; 17 | users: IUser[] = []; 18 | private _subscriptionHelper = new SubscriptionHelper(); 19 | 20 | constructor( 21 | private _userService: UserService, 22 | private _modalService: NgbModal 23 | ) {} 24 | 25 | ngOnInit() { 26 | this._getAllUsers(); 27 | } 28 | 29 | private _getAllUsers = () => { 30 | this._subscriptionHelper.add = this._userService.getAll().subscribe({ 31 | next: (users: IUsersResponse) => { 32 | this.users = users.payload; 33 | }, 34 | error: (errorMessage: string) => { 35 | this.errorMessage = errorMessage; 36 | }, 37 | }); 38 | }; 39 | 40 | public deleteUserModal(event: Event, user: IUser) { 41 | event.preventDefault(); 42 | const modalRef = this._modalService.open(DeleteComponent); 43 | modalRef.componentInstance.user = user; 44 | modalRef.result.then( 45 | result => { 46 | console.log(`Closed with: ${JSON.stringify(result, null, 2)}`); 47 | modalRef.close(); 48 | this._getAllUsers(); 49 | }, 50 | reason => { 51 | console.log(`Dismissed ${this.getDismissReason(reason)}`); 52 | modalRef.close(); 53 | } 54 | ); 55 | } 56 | 57 | private getDismissReason(reason: unknown): string { 58 | if (reason === ModalDismissReasons.ESC) { 59 | return 'by pressing ESC'; 60 | } else if (reason === ModalDismissReasons.BACKDROP_CLICK) { 61 | return 'by clicking on a backdrop'; 62 | } else { 63 | return `with: ${reason}`; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/app/view/user/index/index.component.scss: -------------------------------------------------------------------------------- 1 | .table-responsive { 2 | margin: 30px 0; 3 | } 4 | 5 | .table-wrapper { 6 | background: #fff; 7 | padding: 20px 25px; 8 | border-radius: 3px; 9 | min-width: 1000px; 10 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); 11 | } 12 | 13 | .table-title { 14 | padding-bottom: 15px; 15 | background: #435d7d; 16 | color: #fff; 17 | padding: 16px 30px; 18 | min-width: 100%; 19 | margin: -20px -25px 10px; 20 | border-radius: 3px 3px 0 0; 21 | } 22 | 23 | .table-title h2 { 24 | margin: 5px 0 0; 25 | font-size: 24px; 26 | } 27 | 28 | .table-title .btn-group { 29 | float: right; 30 | } 31 | 32 | .table-title .btn { 33 | color: #fff; 34 | float: right; 35 | font-size: 13px; 36 | border: none; 37 | min-width: 50px; 38 | border-radius: 2px; 39 | border: none; 40 | outline: none !important; 41 | margin-left: 10px; 42 | } 43 | 44 | .table-title .btn i { 45 | float: left; 46 | font-size: 21px; 47 | margin-right: 5px; 48 | } 49 | 50 | .table-title .btn span { 51 | float: left; 52 | margin-top: 2px; 53 | } 54 | 55 | table.table tr th, 56 | table.table tr td { 57 | border-color: #e9e9e9; 58 | padding: 12px 15px; 59 | vertical-align: middle; 60 | } 61 | 62 | table.table tr th:first-child { 63 | width: 150px; 64 | } 65 | 66 | table.table tr th:last-child { 67 | width: 130px; 68 | } 69 | 70 | table.table-striped tbody tr:nth-of-type(odd) { 71 | background-color: #fcfcfc; 72 | } 73 | 74 | table.table-striped.table-hover tbody tr:hover { 75 | background: #f5f5f5; 76 | } 77 | 78 | table.table th i { 79 | font-size: 13px; 80 | margin: 0 5px; 81 | cursor: pointer; 82 | } 83 | 84 | table.table td:last-child i { 85 | opacity: 0.9; 86 | font-size: 22px; 87 | margin: 0 5px; 88 | } 89 | 90 | table.table td a { 91 | font-weight: bold; 92 | color: #566787; 93 | display: inline-block; 94 | text-decoration: none; 95 | outline: none !important; 96 | } 97 | 98 | table.table td a:hover { 99 | color: #2196f3; 100 | } 101 | 102 | table.table td a.edit { 103 | color: #ffc107; 104 | } 105 | 106 | table.table td a.delete { 107 | color: #f44336; 108 | } 109 | 110 | table.table td i { 111 | font-size: 19px; 112 | } 113 | 114 | table.table .avatar { 115 | border-radius: 50%; 116 | vertical-align: middle; 117 | margin-right: 10px; 118 | } 119 | -------------------------------------------------------------------------------- /src/app/view/user/edit/edit.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { 3 | AbstractControl, 4 | FormBuilder, 5 | FormGroup, 6 | Validators, 7 | } from '@angular/forms'; 8 | import { ActivatedRoute, Router } from '@angular/router'; 9 | import SubscriptionHelper from '@shared/helper/subscription.helper'; 10 | 11 | import { 12 | IUser, 13 | IUserResponse, 14 | IUsersResponse, 15 | } from '@shared/interface/user.interface'; 16 | import { UserService } from '@shared/service/user.service'; 17 | 18 | @Component({ 19 | selector: 'app-edit', 20 | templateUrl: './edit.component.html', 21 | styleUrls: ['./edit.component.scss'], 22 | }) 23 | export class EditComponent implements OnInit { 24 | id!: string; 25 | user!: IUser; 26 | submitted = false; 27 | editForm!: FormGroup; 28 | private _subscriptionHelper = new SubscriptionHelper(); 29 | 30 | constructor( 31 | private _formBuilder: FormBuilder, 32 | private _userService: UserService, 33 | private _activeRoute: ActivatedRoute, 34 | private _router: Router 35 | ) {} 36 | 37 | ngOnInit(): void { 38 | this._userServiceFind(); 39 | this.editFormBuilder(); 40 | } 41 | 42 | editFormBuilder() { 43 | this.editForm = this._formBuilder.group({ 44 | name: ['', Validators.required], 45 | email: ['', Validators.required], 46 | address: ['', Validators.required], 47 | phone: ['', Validators.required], 48 | }); 49 | } 50 | 51 | get fc(): { [key: string]: AbstractControl } { 52 | return this.editForm.controls; 53 | } 54 | 55 | private _userServiceFind() { 56 | this.id = this._activeRoute.snapshot.params['id']; 57 | this._subscriptionHelper.add = this._userService.find(this.id).subscribe({ 58 | next: (user: IUserResponse) => this._setValueEditForm(user.payload), 59 | error: (errorMessage: string) => console.log(errorMessage), 60 | }); 61 | } 62 | 63 | private _setValueEditForm(user: IUser) { 64 | this.user = user; 65 | this.editForm.patchValue({ ...user }); 66 | } 67 | 68 | onSubmit(): void { 69 | this.submitted = true; 70 | 71 | if (this.editForm.valid) { 72 | this._userServiceUpdate(); 73 | } 74 | } 75 | 76 | private _userServiceUpdate() { 77 | const id = this._activeRoute.snapshot.params['id']; 78 | const user = { id, ...this.editForm.value }; 79 | this._subscriptionHelper.add = this._userService.update(user).subscribe({ 80 | next: (response: IUsersResponse) => { 81 | console.log('User updated successfully!', response); 82 | this._router.navigateByUrl('user/index'); 83 | }, 84 | error: (errorMessage: string) => console.log(errorMessage), 85 | }); 86 | } 87 | 88 | onReset(): void { 89 | this.submitted = false; 90 | this.editForm.reset({ ...this.user }); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /server/mock/user/index.js: -------------------------------------------------------------------------------- 1 | const { faker } = require('@faker-js/faker'); 2 | const userDB = require('./db.json'); 3 | 4 | const getUsers = (req, res) => { 5 | res.status(200).send({ 6 | statusCode: 200, 7 | payload: userDB, 8 | }); 9 | }; 10 | 11 | const getUserById = (req, res) => { 12 | const { id } = req.params; 13 | 14 | const user = userDB.filter(user => { 15 | return user.id === id; 16 | })[0]; 17 | 18 | if (!user) { 19 | return res.status(404).send({ 20 | statusCode: 404, 21 | payload: { 22 | errorCode: 404, 23 | errorName: 'Not Found', 24 | errorMessage: 'The requested resource could not be found.', 25 | }, 26 | }); 27 | } 28 | 29 | return res.status(200).send({ 30 | statusCode: 200, 31 | payload: user, 32 | }); 33 | }; 34 | 35 | const createUser = (req, res) => { 36 | const { name, email, address, phone } = req.body; 37 | 38 | 39 | const id = faker.string.nanoid(10); 40 | userDB.push({ id, name, email, address, phone }); 41 | 42 | return res.status(200).send({ 43 | statusCode: 200, 44 | payload: { id, name, email, address, phone }, 45 | }); 46 | }; 47 | 48 | const updateUser = (req, res) => { 49 | const { name, email, address, phone } = req.body; 50 | const { id } = req.params; 51 | 52 | const user = userDB.filter((user) => { 53 | return user.id === id; 54 | })[0]; 55 | 56 | if (!user) { 57 | return res.status(404).send({ 58 | statusCode: 404, 59 | payload: { 60 | errorCode: 404, 61 | errorName: 'Not Found', 62 | errorMessage: 'The requested resource could not be found.', 63 | }, 64 | }); 65 | } 66 | 67 | userDB.splice(userDB.findIndex((user) => { 68 | return user.id === id; 69 | }), 1); 70 | userDB.push({ id, name, email, address, phone }); 71 | 72 | return res.status(200).send({ 73 | statusCode: 200, 74 | payload: { id, name, email, address, phone }, 75 | }); 76 | }; 77 | 78 | const deleteUser = (req, res) => { 79 | const { id } = req.params; 80 | 81 | const userIndex = userDB.findIndex((user) => { 82 | return user.id === id; 83 | }); 84 | 85 | if (userIndex === -1) { 86 | return res.status(404).send({ 87 | statusCode: 404, 88 | payload: { 89 | errorCode: 404, 90 | errorName: 'Not Found', 91 | errorMessage: 'The requested resource could not be found.', 92 | }, 93 | }); 94 | } 95 | 96 | userDB.splice(userIndex, 1); 97 | 98 | return res.status(200).send({ 99 | statusCode: 200, 100 | payload: { id }, 101 | }); 102 | }; 103 | 104 | function userModule(server) { 105 | server.get('/api/user', getUsers); 106 | server.get('/api/user/:id', getUserById); 107 | server.post('/api/user', createUser); 108 | server.put('/api/user/:id', updateUser); 109 | server.delete('/api/user/:id', deleteUser); 110 | } 111 | 112 | module.exports = userModule; 113 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-mock-inmemory": { 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:browser", 19 | "options": { 20 | "outputPath": "dist/angular-mock-inmemory", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": ["zone.js"], 24 | "tsConfig": "tsconfig.app.json", 25 | "inlineStyleLanguage": "scss", 26 | "assets": ["src/favicon.ico", "src/assets"], 27 | "styles": [ 28 | "node_modules/bootstrap/scss/bootstrap.scss", 29 | "src/styles.scss" 30 | ], 31 | "scripts": [ 32 | "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js" 33 | ] 34 | }, 35 | "configurations": { 36 | "production": { 37 | "fileReplacements": [ 38 | { 39 | "replace": "src/environments/environment.ts", 40 | "with": "src/environments/environment.production.ts" 41 | } 42 | ], 43 | "budgets": [ 44 | { 45 | "type": "initial", 46 | "maximumWarning": "500kb", 47 | "maximumError": "1mb" 48 | }, 49 | { 50 | "type": "anyComponentStyle", 51 | "maximumWarning": "2kb", 52 | "maximumError": "4kb" 53 | } 54 | ], 55 | "outputHashing": "all" 56 | }, 57 | "development": { 58 | "buildOptimizer": false, 59 | "optimization": false, 60 | "vendorChunk": true, 61 | "extractLicenses": false, 62 | "sourceMap": true, 63 | "namedChunks": true, 64 | "fileReplacements": [ 65 | { 66 | "replace": "src/environments/environment.ts", 67 | "with": "src/environments/environment.development.ts" 68 | } 69 | ] 70 | } 71 | }, 72 | "defaultConfiguration": "production" 73 | }, 74 | "serve": { 75 | "builder": "@angular-devkit/build-angular:dev-server", 76 | "configurations": { 77 | "production": { 78 | "browserTarget": "angular-mock-inmemory:build:production" 79 | }, 80 | "development": { 81 | "browserTarget": "angular-mock-inmemory:build:development" 82 | } 83 | }, 84 | "defaultConfiguration": "development" 85 | }, 86 | "extract-i18n": { 87 | "builder": "@angular-devkit/build-angular:extract-i18n", 88 | "options": { 89 | "browserTarget": "angular-mock-inmemory:build" 90 | } 91 | }, 92 | "lint": { 93 | "builder": "@angular-eslint/builder:lint", 94 | "options": { 95 | "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"] 96 | } 97 | } 98 | } 99 | } 100 | }, 101 | "cli": { 102 | "analytics": false 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/app/view/user/create/create.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
11 |
Add User
12 | 13 |
14 | 15 |
16 | 28 |
33 |

Name is required

34 |
35 |
36 | 37 | 38 |
39 | 52 |
58 |

Email is required

59 |
60 |
61 | 62 | 63 |
64 | 77 |
83 |

84 | Address is required 85 |

86 |
87 |
88 | 89 |
90 | 91 | 104 |
110 |

Phone is required

111 |
112 |
113 | 114 | 120 |
121 |
122 |
123 |
124 |
125 |
126 | -------------------------------------------------------------------------------- /src/app/view/user/edit/edit.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
11 |
Edit User
12 | 13 |
14 | 15 |
16 | 28 |
33 |

Name is required

34 |
35 |
36 | 37 | 38 |
39 | 52 |
58 |

Email is required

59 |
60 |
61 | 62 | 63 |
64 | 77 |
83 |

84 | Address is required 85 |

86 |
87 |
88 | 89 | 90 |
91 | 104 |
110 |

Phone is required

111 |
112 |
113 | 114 | 120 | 126 |
127 |
128 |
129 |
130 |
131 |
132 | --------------------------------------------------------------------------------