Inital Commit
This commit is contained in:
commit
64ead91fc2
68 changed files with 16302 additions and 0 deletions
16
.editorconfig
Normal file
16
.editorconfig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
27
README.md
Normal file
27
README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# SecondApp
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 18.2.3.
|
||||
|
||||
## Development server
|
||||
|
||||
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.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
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`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
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.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||
112
angular.json
Normal file
112
angular.json
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"second-app": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"standalone": false
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"standalone": false
|
||||
},
|
||||
"@schematics/angular:pipe": {
|
||||
"standalone": false
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:application",
|
||||
"options": {
|
||||
"outputPath": "dist/second-app",
|
||||
"index": "src/index.html",
|
||||
"browser": "src/main.ts",
|
||||
"polyfills": [
|
||||
"zone.js"
|
||||
],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css",
|
||||
"node_modules/bootstrap/dist/css/bootstrap.min.css"
|
||||
],
|
||||
"scripts": [
|
||||
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kB",
|
||||
"maximumError": "4kB"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "second-app:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "second-app:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
14653
package-lock.json
generated
Normal file
14653
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
42
package.json
Normal file
42
package.json
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"name": "second-app",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "json-server -- watch produit.json --port 3500 & ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^18.2.0",
|
||||
"@angular/common": "^18.2.0",
|
||||
"@angular/compiler": "^18.2.0",
|
||||
"@angular/core": "^18.2.0",
|
||||
"@angular/forms": "^18.2.0",
|
||||
"@angular/platform-browser": "^18.2.0",
|
||||
"@angular/platform-browser-dynamic": "^18.2.0",
|
||||
"@angular/router": "^18.2.0",
|
||||
"bootstrap": "^5.3.3",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"rxjs": "~7.8.0",
|
||||
"simple-datatables": "^9.2.1",
|
||||
"sweetalert2": "^11.14.5",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^18.2.3",
|
||||
"@angular/cli": "^18.2.3",
|
||||
"@angular/compiler-cli": "^18.2.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.2.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.5.2"
|
||||
}
|
||||
}
|
||||
95
produit.json
Normal file
95
produit.json
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
"produits": [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Produit 1",
|
||||
"price": 100,
|
||||
"quantity": 5,
|
||||
"checked": true
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Produit 2",
|
||||
"price": 200,
|
||||
"quantity": 5,
|
||||
"checked": false
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"name": "Produit 3",
|
||||
"price": 300,
|
||||
"quantity": 5,
|
||||
"checked": true
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"name": "Produit 4",
|
||||
"price": 400,
|
||||
"quantity": 5,
|
||||
"checked": false
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"name": "Produit 5",
|
||||
"price": 500,
|
||||
"quantity": 5,
|
||||
"checked": true
|
||||
},
|
||||
{
|
||||
"id": "6",
|
||||
"name": "Produit 6",
|
||||
"price": 600,
|
||||
"quantity": 5,
|
||||
"checked": false
|
||||
},
|
||||
{
|
||||
"id": "7",
|
||||
"name": "Produit 7",
|
||||
"price": 700,
|
||||
"quantity": 5,
|
||||
"checked": true
|
||||
},
|
||||
{
|
||||
"id": "8",
|
||||
"name": "Produit 8",
|
||||
"price": 800,
|
||||
"quantity": 5,
|
||||
"checked": false
|
||||
},
|
||||
{
|
||||
"id": "9",
|
||||
"name": "Produit 9",
|
||||
"price": 900,
|
||||
"quantity": 5,
|
||||
"checked": true
|
||||
},
|
||||
{
|
||||
"id": "10",
|
||||
"name": "Produit 10",
|
||||
"price": 1000,
|
||||
"quantity": 5,
|
||||
"checked": false
|
||||
},
|
||||
{
|
||||
"id": "aa4a",
|
||||
"name": "tete",
|
||||
"price": "478",
|
||||
"quantity": 0,
|
||||
"checked": true
|
||||
},
|
||||
{
|
||||
"id": "d412",
|
||||
"name": "gg",
|
||||
"price": "15",
|
||||
"quantity": 0,
|
||||
"checked": true
|
||||
},
|
||||
{
|
||||
"id": "9427",
|
||||
"name": "gfdgfgf",
|
||||
"price": "hgg",
|
||||
"quantity": null,
|
||||
"checked": true
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
48
src/app/about/about.component.css
Normal file
48
src/app/about/about.component.css
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
.container {
|
||||
max-width: 400px;
|
||||
margin: 50px auto;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
form div {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-top: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
span {
|
||||
color: red;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 15px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
background-color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
border: 1px solid #007bff;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 5px;
|
||||
}
|
||||
48
src/app/about/about.component.html
Normal file
48
src/app/about/about.component.html
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
<div class="container">
|
||||
<h1>Formulaire Réactif</h1>
|
||||
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
|
||||
<div>
|
||||
<label for="nom">Nom :</label>
|
||||
<input id="nom" formControlName="nom" />
|
||||
<span *ngIf="userForm.get('nom')?.invalid && userForm.get('nom')?.touched">
|
||||
Nom requis (minimum 2 caractères).
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="prenom">Prénom :</label>
|
||||
<input id="prenom" formControlName="prenom" />
|
||||
<span *ngIf="userForm.get('prenom')?.invalid && userForm.get('prenom')?.touched">
|
||||
Prénom requis (minimum 2 caractères).
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="adresse">Adresse :</label>
|
||||
<input id="adresse" formControlName="adresse" />
|
||||
<span *ngIf="userForm.get('adresse')?.invalid && userForm.get('adresse')?.touched">
|
||||
Adresse requise.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email">Email :</label>
|
||||
<input id="email" formControlName="email" />
|
||||
<span *ngIf="userForm.get('email')?.invalid && userForm.get('email')?.touched">
|
||||
Email valide requis.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button type="submit" [disabled]="userForm.invalid">Identifier</button>
|
||||
</form>
|
||||
|
||||
<!-- Div cachée pour afficher les informations -->
|
||||
<div *ngIf="showInfo" class="info-box">
|
||||
<h2>Informations saisies :</h2>
|
||||
<p><strong>Nom :</strong> {{ userInfo?.nom }}</p>
|
||||
<p><strong>Prénom :</strong> {{ userInfo?.prenom }}</p>
|
||||
<p><strong>Adresse :</strong> {{ userInfo?.adresse }}</p>
|
||||
<p><strong>Email :</strong> {{ userInfo?.email }}</p>
|
||||
</div>
|
||||
</div>
|
||||
23
src/app/about/about.component.spec.ts
Normal file
23
src/app/about/about.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AboutComponent } from './about.component';
|
||||
|
||||
describe('AboutComponent', () => {
|
||||
let component: AboutComponent;
|
||||
let fixture: ComponentFixture<AboutComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [AboutComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AboutComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
33
src/app/about/about.component.ts
Normal file
33
src/app/about/about.component.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-about',
|
||||
templateUrl: './about.component.html',
|
||||
styleUrl: './about.component.css'
|
||||
})
|
||||
export class AboutComponent {
|
||||
userForm: FormGroup;
|
||||
showInfo: boolean = false; // Pour afficher ou cacher la div
|
||||
userInfo: any = null; // Stockage des informations saisies
|
||||
|
||||
constructor(private fb: FormBuilder) {
|
||||
// Initialiser le formulaire
|
||||
this.userForm = this.fb.group({
|
||||
nom: ['', [Validators.required, Validators.minLength(2)]],
|
||||
prenom: ['', [Validators.required, Validators.minLength(2)]],
|
||||
adresse: ['', Validators.required],
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
});
|
||||
}
|
||||
|
||||
// Méthode pour afficher les données
|
||||
onSubmit() {
|
||||
if (this.userForm.valid) {
|
||||
this.userInfo = this.userForm.value; // Stocker les informations saisies
|
||||
this.showInfo = true; // Afficher la div
|
||||
} else {
|
||||
alert('Veuillez corriger les erreurs dans le formulaire.');
|
||||
}
|
||||
}
|
||||
}
|
||||
0
src/app/affproduit/affproduit.component.css
Normal file
0
src/app/affproduit/affproduit.component.css
Normal file
1
src/app/affproduit/affproduit.component.html
Normal file
1
src/app/affproduit/affproduit.component.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<p>affproduit works!</p>
|
||||
23
src/app/affproduit/affproduit.component.spec.ts
Normal file
23
src/app/affproduit/affproduit.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AffproduitComponent } from './affproduit.component';
|
||||
|
||||
describe('AffproduitComponent', () => {
|
||||
let component: AffproduitComponent;
|
||||
let fixture: ComponentFixture<AffproduitComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [AffproduitComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AffproduitComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
10
src/app/affproduit/affproduit.component.ts
Normal file
10
src/app/affproduit/affproduit.component.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-affproduit',
|
||||
templateUrl: './affproduit.component.html',
|
||||
styleUrl: './affproduit.component.css'
|
||||
})
|
||||
export class AffproduitComponent {
|
||||
|
||||
}
|
||||
28
src/app/app-routing.module.ts
Normal file
28
src/app/app-routing.module.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { AboutComponent } from './about/about.component';
|
||||
import { ContactsComponent } from './contacts/contacts.component';
|
||||
import { UserComponent } from './user/user.component';
|
||||
import { ProductComponent } from './product/product.component';
|
||||
import { ProductList2Component } from './product-list2/product-list2.component';
|
||||
import { SimpleproduitComponent } from './simpleproduit/simpleproduit.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'about', component: AboutComponent },
|
||||
{ path: 'contacts', component: ContactsComponent },
|
||||
{ path: 'user', component: UserComponent },
|
||||
{ path: 'product', component: ProductComponent },
|
||||
{ path: 'product2', component: ProductList2Component },
|
||||
{ path: 'gestprod', component: SimpleproduitComponent },
|
||||
{
|
||||
path: '',
|
||||
redirectTo: '/about',
|
||||
pathMatch: 'full'
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
0
src/app/app.component.css
Normal file
0
src/app/app.component.css
Normal file
30
src/app/app.component.html
Normal file
30
src/app/app.component.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<nav class="p-3">
|
||||
<ul class="nav nav-pills">
|
||||
<li>
|
||||
<button routerLink="/about" class="btn btn-outline-success ms-1">A propos<i class="bi bi-house text-success"></i></button>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<button routerLink="/contacts" class="btn btn-outline-success ms-1">Contacts<i class="bi bi-arrow-down-up text-success"></i></button>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<button routerLink="/user" class="btn btn-outline-success ms-1">Usert<i class="bi bi-plus-circle text-success"></i></button>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<button routerLink="/product" class="btn btn-outline-success ms-1">Produit<i class="bi bi-plus-circle text-success"></i></button>
|
||||
</li>
|
||||
<!--<li>
|
||||
<button routerLink="/product2" class="btn btn-outline-success ms-1">Produit2<i class="bi bi-plus-circle text-success"></i></button>
|
||||
</li> -->
|
||||
<li>
|
||||
<button routerLink="/product2" class="btn btn-outline-success ms-1">Produit Observable<i class="bi bi-plus-circle text-success"></i></button>
|
||||
</li>
|
||||
<i class="bi bi-airplane" class="btn btn-outline-success ms-1" routerLink="/product2" ></i>
|
||||
<li>
|
||||
<button routerLink="/gestprod" class="btn btn-outline-success ms-1">Gestion Produit<i class="bi bi-app-indicator text-success"></i></button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<router-outlet></router-outlet>
|
||||
35
src/app/app.component.spec.ts
Normal file
35
src/app/app.component.spec.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterModule.forRoot([])
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'second-app'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('second-app');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, second-app');
|
||||
});
|
||||
});
|
||||
10
src/app/app.component.ts
Normal file
10
src/app/app.component.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.css'
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'second-app';
|
||||
}
|
||||
43
src/app/app.module.ts
Normal file
43
src/app/app.module.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { AboutComponent } from './about/about.component';
|
||||
import { ContactsComponent } from './contacts/contacts.component';
|
||||
import { ProductComponent } from './product/product.component';
|
||||
import { UserComponent } from './user/user.component';
|
||||
import { ProductFormComponent } from './product/product-form/product-form.component';
|
||||
import { ProductListComponent } from './product/product-list/product-list.component';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
import { ProductList2Component } from './product-list2/product-list2.component';
|
||||
import { SimpleproduitComponent } from './simpleproduit/simpleproduit.component';
|
||||
import { CategorieComponent } from './categorie/categorie.component';
|
||||
import { AffproduitComponent } from './affproduit/affproduit.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
AboutComponent,
|
||||
ContactsComponent,
|
||||
ProductComponent,
|
||||
UserComponent,
|
||||
ProductFormComponent,
|
||||
ProductListComponent,
|
||||
ProductList2Component,
|
||||
SimpleproduitComponent,
|
||||
CategorieComponent,
|
||||
AffproduitComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
ReactiveFormsModule,
|
||||
FormsModule
|
||||
|
||||
],
|
||||
providers: [provideHttpClient()],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
0
src/app/categorie/categorie.component.css
Normal file
0
src/app/categorie/categorie.component.css
Normal file
1
src/app/categorie/categorie.component.html
Normal file
1
src/app/categorie/categorie.component.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<p>categorie works!</p>
|
||||
23
src/app/categorie/categorie.component.spec.ts
Normal file
23
src/app/categorie/categorie.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CategorieComponent } from './categorie.component';
|
||||
|
||||
describe('CategorieComponent', () => {
|
||||
let component: CategorieComponent;
|
||||
let fixture: ComponentFixture<CategorieComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [CategorieComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CategorieComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
10
src/app/categorie/categorie.component.ts
Normal file
10
src/app/categorie/categorie.component.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-categorie',
|
||||
templateUrl: './categorie.component.html',
|
||||
styleUrl: './categorie.component.css'
|
||||
})
|
||||
export class CategorieComponent {
|
||||
|
||||
}
|
||||
0
src/app/contacts/contacts.component.css
Normal file
0
src/app/contacts/contacts.component.css
Normal file
2
src/app/contacts/contacts.component.html
Normal file
2
src/app/contacts/contacts.component.html
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<h3>Liste de contacts</h3>
|
||||
<button type="button" class="btn btn-secondary" (click)="onClick()">Retour About</button>
|
||||
23
src/app/contacts/contacts.component.spec.ts
Normal file
23
src/app/contacts/contacts.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ContactsComponent } from './contacts.component';
|
||||
|
||||
describe('ContactsComponent', () => {
|
||||
let component: ContactsComponent;
|
||||
let fixture: ComponentFixture<ContactsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ContactsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ContactsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
21
src/app/contacts/contacts.component.ts
Normal file
21
src/app/contacts/contacts.component.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contacts',
|
||||
templateUrl: './contacts.component.html',
|
||||
styleUrl: './contacts.component.css'
|
||||
})
|
||||
export class ContactsComponent implements OnInit {
|
||||
|
||||
constructor(private route: Router){}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
onClick() {
|
||||
this.route.navigate(['about']);
|
||||
}
|
||||
|
||||
}
|
||||
7
src/app/model/product.model.ts
Normal file
7
src/app/model/product.model.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export interface Product {
|
||||
id : number,
|
||||
name : string,
|
||||
price : number,
|
||||
quantity : number,
|
||||
checked : boolean
|
||||
}
|
||||
0
src/app/product-list2/product-list2.component.css
Normal file
0
src/app/product-list2/product-list2.component.css
Normal file
1
src/app/product-list2/product-list2.component.html
Normal file
1
src/app/product-list2/product-list2.component.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<p *ngFor="let product of listesProduits">{{product.name}} : {{product.price}}</p>
|
||||
23
src/app/product-list2/product-list2.component.spec.ts
Normal file
23
src/app/product-list2/product-list2.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProductList2Component } from './product-list2.component';
|
||||
|
||||
describe('ProductList2Component', () => {
|
||||
let component: ProductList2Component;
|
||||
let fixture: ComponentFixture<ProductList2Component>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ProductList2Component]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ProductList2Component);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
48
src/app/product-list2/product-list2.component.ts
Normal file
48
src/app/product-list2/product-list2.component.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Product } from '../model/product.model';
|
||||
import { ProductService } from '../services/product.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-list2',
|
||||
templateUrl: './product-list2.component.html',
|
||||
styleUrl: './product-list2.component.css'
|
||||
})
|
||||
export class ProductList2Component implements OnInit {
|
||||
listesProduits: Product[] = [];
|
||||
produitSelectionne: Product | null = null;
|
||||
|
||||
constructor(private productService:ProductService){}
|
||||
ngOnInit(): void {
|
||||
|
||||
//Méthode 1
|
||||
// this.getProducts();
|
||||
|
||||
//Méthode 2
|
||||
/*this.productService.getProduits2().subscribe(data => {
|
||||
this.listesProduits = data;
|
||||
});*/
|
||||
|
||||
//Methode 3
|
||||
this.productService.getProduits2().subscribe({
|
||||
|
||||
next: (productsList) => {
|
||||
this.listesProduits = productsList;
|
||||
},
|
||||
error: (error) => {
|
||||
console.log('http error: ', error)
|
||||
},
|
||||
complete:() => {
|
||||
console.log('Traitement finie')
|
||||
}
|
||||
},
|
||||
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
getProducts(){
|
||||
this.listesProduits = this.productService.getProduits();
|
||||
}
|
||||
|
||||
}
|
||||
0
src/app/product/product-form/product-form.component.css
Normal file
0
src/app/product/product-form/product-form.component.css
Normal file
35
src/app/product/product-form/product-form.component.html
Normal file
35
src/app/product/product-form/product-form.component.html
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<div class="p-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form [formGroup]="productForm" (ngSubmit)="onSubmit()" >
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Name</label>
|
||||
<input class="form-control" formControlName="name">
|
||||
<span *ngIf="productForm.get('name')?.invalid && productForm.get('name')?.touched">
|
||||
<span id="message-error" class="text-danger"> Le nom du produit est obligatoire !</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Price</label>
|
||||
<input class="form-control" formControlName="price">
|
||||
<span *ngIf="productForm.get('price')?.invalid && productForm.get('price')?.touched">
|
||||
<span id="message-error" class="text-danger"> Le prix du produit est obligatoire !</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Quantity</label>
|
||||
<input class="form-control" formControlName="price">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Checked</label>
|
||||
<input type="checkbox" class="form-check-input" formControlName="checked">
|
||||
</div>
|
||||
<button [disabled]="productForm.invalid" class="btn btn-success">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
23
src/app/product/product-form/product-form.component.spec.ts
Normal file
23
src/app/product/product-form/product-form.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProductFormComponent } from './product-form.component';
|
||||
|
||||
describe('ProductFormComponent', () => {
|
||||
let component: ProductFormComponent;
|
||||
let fixture: ComponentFixture<ProductFormComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ProductFormComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ProductFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
58
src/app/product/product-form/product-form.component.ts
Normal file
58
src/app/product/product-form/product-form.component.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { Product } from '../../model/product.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-form',
|
||||
templateUrl: './product-form.component.html',
|
||||
styleUrl: './product-form.component.css'
|
||||
})
|
||||
export class ProductFormComponent implements OnInit{
|
||||
public productForm!:FormGroup;
|
||||
@Input()
|
||||
product: Product | null = null;
|
||||
|
||||
// <app-product-form [product]="valeurProvenantDuParent de type Product" (productPopulated)="Attend une fonction"></app-product-form>
|
||||
|
||||
/*@Output()
|
||||
productPopulated: EventEmitter<Product> = new EventEmitter<Product>();*/
|
||||
|
||||
@Output() addProduit = new EventEmitter<Product>(); //@output permet de renvoyer les données du formulaire vers le composant parent
|
||||
|
||||
// Le composant parent gère la logique de l'application : il récupère les produits du service, les passe aux composants enfants, et réagit aux événements émis par ces derniers.
|
||||
|
||||
|
||||
constructor(private fb: FormBuilder, private router: Router) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
//Peut être initialisé dans le constructeur
|
||||
this.productForm=this.fb.group({
|
||||
name : this.fb.control('', [Validators.required]),
|
||||
price : this.fb.control('',[Validators.required, Validators.min(5)]),
|
||||
quantity : this.fb.control(0,),
|
||||
checked : this.fb.control(false),
|
||||
});
|
||||
|
||||
if (this.product) {
|
||||
this.productForm.patchValue(this.product);
|
||||
}
|
||||
}
|
||||
|
||||
/*onSubmit(): void {
|
||||
if (this.productForm.valid) {
|
||||
this.productPopulated.emit(this.productForm.value);
|
||||
}
|
||||
}*/
|
||||
|
||||
onSubmit() {
|
||||
if (this.productForm.valid) {
|
||||
this.addProduit.emit(this.productForm.value);
|
||||
this.productForm.reset();
|
||||
}
|
||||
}
|
||||
|
||||
saveProduct(): void {
|
||||
console.log(this.productForm.value);
|
||||
}
|
||||
}
|
||||
0
src/app/product/product-list/product-list.component.css
Normal file
0
src/app/product/product-list/product-list.component.css
Normal file
46
src/app/product/product-list/product-list.component.html
Normal file
46
src/app/product/product-list/product-list.component.html
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<div class="p-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<input class="p-1" type="text" [(ngModel)]="searchValue" placeholder="Rechercher un produit par nom..." >
|
||||
<button (click)="onSearch()"
|
||||
class="btn btn-outline-success ms-1">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <p *ngFor="let user of myUsers">{{user.name}} : {{user.age}}</p>
|
||||
<pre>{{users.length}}</pre>users!!!
|
||||
<pre>{{products.length}}</pre>products!!! -->
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th> <th>Price</th> <th>Quantity</th> <th>Checked</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let product of products ">
|
||||
<td>{{product.name}}</td>
|
||||
<td>{{product.price}}</td>
|
||||
<td>{{product.quantity}}</td>
|
||||
<td>
|
||||
<button (click)="onToggleDisponibilite(product)"
|
||||
class="btn btn-outline-success">
|
||||
<i [class]="product.checked?'bi bi-check':'bi bi-circle'"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<button (click)="onDelete(product)" class="btn btn-outline-danger">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="products.length === 0 && searchValue.length > 0">
|
||||
<p>Aucun produit trouvé pour "{{ searchValue }}"</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
23
src/app/product/product-list/product-list.component.spec.ts
Normal file
23
src/app/product/product-list/product-list.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProductListComponent } from './product-list.component';
|
||||
|
||||
describe('ProductListComponent', () => {
|
||||
let component: ProductListComponent;
|
||||
let fixture: ComponentFixture<ProductListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ProductListComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ProductListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
40
src/app/product/product-list/product-list.component.ts
Normal file
40
src/app/product/product-list/product-list.component.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Product } from '../../model/product.model';
|
||||
import { ProductService } from '../../services/product.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-list',
|
||||
templateUrl: './product-list.component.html',
|
||||
styleUrl: './product-list.component.css'
|
||||
})
|
||||
export class ProductListComponent implements OnInit {
|
||||
|
||||
//Le composant list-produit reçoit une liste de produits via @Input et émet des événements
|
||||
// lorsqu'un produit doit être modifié ou supprimé via @Output
|
||||
|
||||
@Input() products: Product[] = [];
|
||||
@Output() deleteProduit = new EventEmitter<Product>();
|
||||
@Output() toggleDisponibilite = new EventEmitter<Product>();
|
||||
@Output() searchProduct = new EventEmitter<string>()
|
||||
|
||||
|
||||
|
||||
searchValue: string = '';
|
||||
|
||||
constructor() {}
|
||||
|
||||
onDelete(product: Product) {
|
||||
this.deleteProduit.emit(product);
|
||||
}
|
||||
|
||||
onToggleDisponibilite(product: Product) {
|
||||
this.toggleDisponibilite.emit(product);
|
||||
}
|
||||
|
||||
onSearch() {
|
||||
this.searchProduct.emit(this.searchValue);
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
}
|
||||
0
src/app/product/product.component.css
Normal file
0
src/app/product/product.component.css
Normal file
11
src/app/product/product.component.html
Normal file
11
src/app/product/product.component.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<app-product-form
|
||||
[product]="produitSelectionne"
|
||||
(addProduit)="onAddProduit($event)"
|
||||
></app-product-form>
|
||||
<app-product-list
|
||||
[products]="listesProduits"
|
||||
(deleteProduit)="onDeleteProduit($event)"
|
||||
(toggleDisponibilite)="onToggleDisponibilite($event)"
|
||||
(searchProduct)="onSearchProduit($event)"
|
||||
>
|
||||
</app-product-list>
|
||||
23
src/app/product/product.component.spec.ts
Normal file
23
src/app/product/product.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProductComponent } from './product.component';
|
||||
|
||||
describe('ProductComponent', () => {
|
||||
let component: ProductComponent;
|
||||
let fixture: ComponentFixture<ProductComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ProductComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ProductComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
91
src/app/product/product.component.ts
Normal file
91
src/app/product/product.component.ts
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Product } from '../model/product.model';
|
||||
import { ProductService } from '../services/product.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product',
|
||||
templateUrl: './product.component.html',
|
||||
styleUrl: './product.component.css'
|
||||
})
|
||||
export class ProductComponent implements OnInit {
|
||||
|
||||
//Le composant parent gère la logique de l'application : il récupère les produits du service, les passe aux composants enfants,
|
||||
// et réagit aux événements émis par ces derniers.
|
||||
|
||||
listesProduits: Product[] = [];
|
||||
produitSelectionne: Product | null = null;
|
||||
|
||||
constructor(private productService:ProductService){}
|
||||
ngOnInit(): void {
|
||||
///this.getProducts();
|
||||
|
||||
this.productService.getProduits2().subscribe(data => {
|
||||
this.listesProduits = data;
|
||||
}
|
||||
);
|
||||
|
||||
/*this.productService.getProduits2().subscribe({
|
||||
|
||||
next: (productsList) => {
|
||||
this.listesProduits = productsList;
|
||||
},
|
||||
error: (error) => {
|
||||
console.log('http error: ', error)
|
||||
},
|
||||
complete:() => {
|
||||
console.log('Traitement finie')
|
||||
}
|
||||
},
|
||||
|
||||
);*/
|
||||
|
||||
|
||||
|
||||
/**/
|
||||
|
||||
|
||||
//this.productService.recupProduits().subscribe(data => (this.listesProduits = data));
|
||||
|
||||
|
||||
//this.loadProducts();
|
||||
}
|
||||
|
||||
getProducts(){
|
||||
this.listesProduits = this.productService.getProduits();
|
||||
}
|
||||
|
||||
loadProducts(): void {
|
||||
this.productService.recupProduits().subscribe(data => (this.listesProduits = data));
|
||||
}
|
||||
|
||||
onAddProduit(produit: Product) {
|
||||
this.productService.ajouterProduit(produit);
|
||||
}
|
||||
|
||||
onAddProduitAutre(produit: Product): void {
|
||||
this.productService.addProduct(produit).subscribe(() => {
|
||||
// this.productAdded.emit();
|
||||
});
|
||||
}
|
||||
|
||||
onDeleteProduit(product: Product) {
|
||||
this.productService.supprimerProduit(product.id);
|
||||
}
|
||||
|
||||
onToggleDisponibilite(product: Product) {
|
||||
this.productService.recupererProduitParId(product.id);
|
||||
}
|
||||
|
||||
onSearchProduitInit(name: string) {
|
||||
this.productService.searchProduit(name);
|
||||
}
|
||||
|
||||
onSearchProduit(name: string) {
|
||||
this.listesProduits = this.productService.rechercherProduit(name)
|
||||
}
|
||||
|
||||
onSearchProduit1(name: string) {
|
||||
this.productService.searchProduit(name);
|
||||
}
|
||||
|
||||
}
|
||||
16
src/app/services/mon-service.service.spec.ts
Normal file
16
src/app/services/mon-service.service.spec.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MonServiceService } from './mon-service.service';
|
||||
|
||||
describe('MonServiceService', () => {
|
||||
let service: MonServiceService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(MonServiceService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
9
src/app/services/mon-service.service.ts
Normal file
9
src/app/services/mon-service.service.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MonServiceService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
16
src/app/services/product.service.spec.ts
Normal file
16
src/app/services/product.service.spec.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProductService } from './product.service';
|
||||
|
||||
describe('ProductService', () => {
|
||||
let service: ProductService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ProductService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
132
src/app/services/product.service.ts
Normal file
132
src/app/services/product.service.ts
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Product } from '../model/product.model';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ProductService {
|
||||
|
||||
produits: Product[] = [
|
||||
{ id: 1, name: 'Produit 1', price: 100, quantity: 5, checked: true },
|
||||
{ id: 2, name: 'Produit 2', price: 200, quantity: 5, checked: false },
|
||||
{ id: 3, name: 'Produit 3', price: 300, quantity: 5, checked: true },
|
||||
{ id: 4, name: 'Produit 4', price: 400, quantity: 5, checked: false },
|
||||
{ id: 5, name: 'Produit 5', price: 500, quantity: 5, checked: true },
|
||||
{ id: 6, name: 'Produit 6', price: 600, quantity: 5, checked: false },
|
||||
{ id: 7, name: 'Produit 7', price: 700, quantity: 5, checked: true },
|
||||
{ id: 8, name: 'Produit 8', price: 800, quantity: 5, checked: false },
|
||||
{ id: 9, name: 'Produit 9', price: 900, quantity: 5, checked: true },
|
||||
{ id: 10, name: 'Produit 10', price: 1000, quantity: 5, checked: false },
|
||||
];
|
||||
|
||||
private productUrl = 'http://localhost:3600/produits';
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
recupProduits(): Observable<Product[]> {
|
||||
return this.http.get<Product[]>(this.productUrl);
|
||||
}
|
||||
|
||||
addProduit(produit: Product): Observable<Product> {
|
||||
return this.http.post<Product>(this.productUrl, produit);
|
||||
}
|
||||
|
||||
addProduct(produit: Product): Observable<Product> {
|
||||
return this.http.post<Product>(this.productUrl, produit);
|
||||
}
|
||||
|
||||
updateProduct(produit: Product): Observable<Product> {
|
||||
return this.http.put<Product>(`${this.productUrl}/${produit.id}`, produit);
|
||||
}
|
||||
|
||||
|
||||
private produitsSubject = new BehaviorSubject<Product[]>(this.produits);
|
||||
|
||||
//private produitsSubject = new BehaviorSubject<Product[]>(this.productUrl);
|
||||
private productsSubject = new BehaviorSubject<Product[]>([]);
|
||||
public products$ = this.productsSubject.asObservable();
|
||||
|
||||
private loadProducts(): void {
|
||||
this.http.get<Product[]>(this.productUrl)
|
||||
.subscribe((products) => this.productsSubject.next(products));
|
||||
}
|
||||
|
||||
// Obtenir les produits
|
||||
getProducts(): Observable<Product[]> {
|
||||
return this.products$;
|
||||
}
|
||||
|
||||
// Ajouter un produit
|
||||
addProduct2(product: Product): void {
|
||||
const current = this.productsSubject.getValue();
|
||||
const updated = [...current, product];
|
||||
this.productsSubject.next(updated);
|
||||
}
|
||||
|
||||
// Mettre à jour un produit
|
||||
updateProduct2(updatedProduct: Product): void {
|
||||
const current = this.productsSubject.getValue();
|
||||
const updated = current.map(p => p.id === updatedProduct.id ? updatedProduct : p);
|
||||
this.productsSubject.next(updated);
|
||||
}
|
||||
|
||||
// Récupérer tous les produits
|
||||
getProduits(): Product[] {
|
||||
return this.produits;
|
||||
//return this.produitsSubject.asObservable();
|
||||
}
|
||||
|
||||
getProduits2(): Observable<Product[]> {
|
||||
return this.produitsSubject.asObservable();
|
||||
}
|
||||
|
||||
// Ajouter un produit
|
||||
ajouterProduit(produit: Product): void {
|
||||
produit.id = this.produits.length + 1;
|
||||
this.produits.push(produit);
|
||||
this.produitsSubject.next(this.produits);
|
||||
}
|
||||
|
||||
// Supprimer un produit par son id
|
||||
supprimerProduit(id: number): void {
|
||||
this.produits = this.produits.filter((produit) => produit.id !== id);
|
||||
this.produitsSubject.next(this.produits);
|
||||
}
|
||||
|
||||
// Rechercher un produit par nom
|
||||
rechercherProduitParNom(nom: string): Product | undefined {
|
||||
return this.produits.find((produit) => produit.name.toLowerCase() === nom.toLowerCase());
|
||||
}
|
||||
|
||||
rechercherProduit(nom: string): Product[] {
|
||||
return this.produits.filter(produit =>
|
||||
produit.name.toLowerCase().includes(nom.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
searchProduit(name: string) {
|
||||
const filteredProduits = this.produits.filter(p => p.name.toLowerCase().includes(name.toLowerCase()));
|
||||
this.produitsSubject.next(filteredProduits);
|
||||
}
|
||||
|
||||
updateProduit(produit: Product): void {
|
||||
const index = this.produits.findIndex(p => p.id === produit.id);
|
||||
if (index !== -1) {
|
||||
this.produits[index] = produit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Récupérer un produit par son id
|
||||
recupererProduitParId(id: number): Product | undefined {
|
||||
//const filteredProduits = this.produits.filter(p => p.name.toLowerCase().includes(name.toLowerCase()));
|
||||
return this.produits.find((produit) => produit.id === id);
|
||||
//this.produitsSubject.next(filteredProduits);
|
||||
}
|
||||
|
||||
searchProduitByName(name: string): Observable<Product[]> {
|
||||
return this.http.get<Product[]>(`${this.productUrl}?name_like=${name}`);
|
||||
}
|
||||
}
|
||||
16
src/app/services/product2.service.spec.ts
Normal file
16
src/app/services/product2.service.spec.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { Product2Service } from './product2.service';
|
||||
|
||||
describe('Product2Service', () => {
|
||||
let service: Product2Service;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(Product2Service);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
34
src/app/services/product2.service.ts
Normal file
34
src/app/services/product2.service.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Product } from '../model/product.model';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class Product2Service {
|
||||
|
||||
private productUrl = 'http://localhost:3000/products'; // URL de l'API ou de JSON Server
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
// Méthode pour récupérer tous les produits
|
||||
getProducts(): Observable<Product[]> {
|
||||
return this.http.get<Product[]>(this.productUrl);
|
||||
}
|
||||
|
||||
// Méthode pour ajouter un produit
|
||||
addProduct(product: Product): Observable<Product> {
|
||||
return this.http.post<Product>(this.productUrl, product);
|
||||
}
|
||||
|
||||
// Méthode pour mettre à jour un produit
|
||||
updateProduct(product: Product): Observable<Product> {
|
||||
return this.http.put<Product>(`${this.productUrl}/${product.id}`, product);
|
||||
}
|
||||
|
||||
// Méthode pour supprimer un produit
|
||||
deleteProduct(id: number): Observable<void> {
|
||||
return this.http.delete<void>(`${this.productUrl}/${id}`);
|
||||
}
|
||||
}
|
||||
0
src/app/simpleproduit/simpleproduit.component.css
Normal file
0
src/app/simpleproduit/simpleproduit.component.css
Normal file
43
src/app/simpleproduit/simpleproduit.component.html
Normal file
43
src/app/simpleproduit/simpleproduit.component.html
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<div class="p-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<input class="p-1" type="text" [(ngModel)]="searchValue" placeholder="Rechercher un produit par nom..." >
|
||||
<button (click)="onSearch()"
|
||||
class="btn btn-outline-success ms-1">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th> <th>Price</th> <th>Quantity</th> <th>Checked</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let product of listesProduits ">
|
||||
<td>{{product.name}}</td>
|
||||
<td>{{product.price}}</td>
|
||||
<td>{{product.quantity}}</td>
|
||||
<td>
|
||||
<button (click)="onToggleDisponibilite(product)"
|
||||
class="btn btn-outline-success">
|
||||
<i [class]="product.checked?'bi bi-check':'bi bi-circle'"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<button (click)="onDeleteProduit(product)" class="btn btn-outline-danger">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="listesProduits.length === 0 && searchValue.length > 0">
|
||||
<p>Aucun produit trouvé pour "{{ searchValue }}"</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
23
src/app/simpleproduit/simpleproduit.component.spec.ts
Normal file
23
src/app/simpleproduit/simpleproduit.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SimpleproduitComponent } from './simpleproduit.component';
|
||||
|
||||
describe('SimpleproduitComponent', () => {
|
||||
let component: SimpleproduitComponent;
|
||||
let fixture: ComponentFixture<SimpleproduitComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [SimpleproduitComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SimpleproduitComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
51
src/app/simpleproduit/simpleproduit.component.ts
Normal file
51
src/app/simpleproduit/simpleproduit.component.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Product } from '../model/product.model';
|
||||
import { ProductService } from '../services/product.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-simpleproduit',
|
||||
templateUrl: './simpleproduit.component.html',
|
||||
styleUrl: './simpleproduit.component.css'
|
||||
})
|
||||
export class SimpleproduitComponent implements OnInit {
|
||||
|
||||
searchValue: string = '';
|
||||
|
||||
listesProduits: Product[] = [];
|
||||
produitSelectionne: Product | null = null;
|
||||
|
||||
constructor(private productService:ProductService){}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getProducts()
|
||||
}
|
||||
|
||||
getProducts(){
|
||||
this.listesProduits = this.productService.getProduits();
|
||||
}
|
||||
|
||||
onAddProduit(produit: Product) {
|
||||
this.productService.ajouterProduit(produit);
|
||||
}
|
||||
|
||||
onDeleteProduit(product: Product) {
|
||||
this.productService.supprimerProduit(product.id);
|
||||
}
|
||||
|
||||
onToggleDisponibilite(product: Product) {
|
||||
this.productService.recupererProduitParId(product.id);
|
||||
}
|
||||
|
||||
onSearchProduitInit(name: string) {
|
||||
this.productService.searchProduit(name);
|
||||
}
|
||||
|
||||
onSearch() {
|
||||
this.listesProduits = this.productService.rechercherProduit(this.searchValue)
|
||||
}
|
||||
|
||||
onSearchProduit1(name: string) {
|
||||
this.productService.searchProduit(name);
|
||||
}
|
||||
|
||||
}
|
||||
0
src/app/user/user.component.css
Normal file
0
src/app/user/user.component.css
Normal file
1
src/app/user/user.component.html
Normal file
1
src/app/user/user.component.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<p>user works!</p>
|
||||
23
src/app/user/user.component.spec.ts
Normal file
23
src/app/user/user.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UserComponent } from './user.component';
|
||||
|
||||
describe('UserComponent', () => {
|
||||
let component: UserComponent;
|
||||
let fixture: ComponentFixture<UserComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [UserComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(UserComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
10
src/app/user/user.component.ts
Normal file
10
src/app/user/user.component.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user',
|
||||
templateUrl: './user.component.html',
|
||||
styleUrl: './user.component.css'
|
||||
})
|
||||
export class UserComponent {
|
||||
|
||||
}
|
||||
13
src/index.html
Normal file
13
src/index.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SecondApp</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
8
src/main.ts
Normal file
8
src/main.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule, {
|
||||
ngZoneEventCoalescing: true
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
9
src/produit.json
Normal file
9
src/produit.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"produits": [
|
||||
{ "id": 1, "nom": "Produit 1", "quantite": 10, "disponibilite": true },
|
||||
{ "id": 2, "nom": "Produit 2", "quantite": 15, "disponibilite": false },
|
||||
{ "id": 3, "nom": "Produit 3", "quantite": 20, "disponibilite": true },
|
||||
{ "id": 4, "nom": "Produit 4", "quantite": 5, "disponibilite": true },
|
||||
{ "id": 5, "nom": "Produit 5", "quantite": 12, "disponibilite": false }
|
||||
]
|
||||
}
|
||||
7
src/styles.css
Normal file
7
src/styles.css
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/* You can add global styles to this file, and also import other style files */
|
||||
|
||||
/*@import 'bootstrap/dist/css/bootstrap.min.css';*/
|
||||
|
||||
@import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
|
||||
|
||||
15
tsconfig.app.json
Normal file
15
tsconfig.app.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
33
tsconfig.json
Normal file
33
tsconfig.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/out-tsc",
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "bundler",
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"lib": [
|
||||
"ES2022",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
15
tsconfig.spec.json
Normal file
15
tsconfig.spec.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue