Commit 027e65a7 authored by Jones Napoleon Autumn's avatar Jones Napoleon Autumn 💬

final push after copy-pasting and understanding angular app structure

parent 631215e6
Pipeline #28643 failed with stages
in 0 seconds
# Angular8MeanstackAngularMaterial
# Tugas kecil 1 jam WBD MEAN STACK tutorial (Frontend)
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.0.
App untuk student (basic CRUD (juga))
## Development server
> Repository ini harus berjalan setelah repository Backend
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Prerequisite
## Code scaffolding
```
npm
```
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`.
## Install and run
## Build
Run `npm install` to install all dependencies
Run `ng serve` for a dev server.
Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Full Credit
## 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 [Protractor](http://www.protractortest.org/).
## 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.io/cli) page.
https://www.positronx.io/angular-8-mean-stack-tutorial-build-crud-angular-material/
......@@ -19,11 +19,9 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": [
"src/favicon.ico",
"src/assets"
],
"assets": ["src/favicon.ico", "src/assets"],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.css"
],
"scripts": []
......@@ -83,11 +81,9 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"assets": ["src/favicon.ico", "src/assets"],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.css"
],
"scripts": []
......@@ -101,9 +97,7 @@
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
"exclude": ["**/node_modules/**"]
}
},
"e2e": {
......@@ -119,6 +113,7 @@
}
}
}
}},
}
},
"defaultProject": "angular8-meanstack-angular-material"
}
......@@ -242,6 +242,23 @@
"tslib": "^2.0.0"
}
},
"@angular/cdk": {
"version": "10.2.7",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-10.2.7.tgz",
"integrity": "sha512-ZQjDfTRTn7JuAKsf3jiIdU2XBaxxGBi/ZWYv5Pb3HCl6B4PISsIE5VWRhkoUogoAB0MiFHpjnWeIqknJEm11YQ==",
"requires": {
"parse5": "^5.0.0",
"tslib": "^2.0.0"
},
"dependencies": {
"parse5": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
"optional": true
}
}
},
"@angular/cli": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-10.2.0.tgz",
......@@ -513,6 +530,14 @@
"tslib": "^2.0.0"
}
},
"@angular/material": {
"version": "10.2.7",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-10.2.7.tgz",
"integrity": "sha512-uk6JkRrKHaM9VFMzX7pWC83YNLVgXPB3D8U1yjSOafCdWwrRZgUHGr8MPlSILCr3o2nxgg5SsKdWcWwHuXXUZA==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/platform-browser": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-10.2.1.tgz",
......
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AddStudentComponent } from './components/add-student/add-student.component';
import { EditStudentComponent } from './components/edit-student/edit-student.component';
import { StudentsListComponent } from './components/students-list/students-list.component';
const routes: Routes = [];
const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'add-student' },
{ path: 'add-student', component: AddStudentComponent },
{ path: 'edit-student/:id', component: EditStudentComponent },
{ path: 'students-list', component: StudentsListComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
exports: [RouterModule],
})
export class AppRoutingModule { }
export class AppRoutingModule {}
This diff is collapsed.
import { Component } from '@angular/core';
import { Component, ViewChild, HostListener, OnInit } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'angular8-meanstack-angular-material';
opened = true;
@ViewChild('sidenav') sidenav: MatSidenav;
ngOnInit() {
console.log(window.innerWidth);
if (window.innerWidth < 768) {
this.sidenav.fixedTopGap = 55;
this.opened = false;
} else {
this.sidenav.fixedTopGap = 55;
this.opened = true;
}
}
@HostListener('window:resize', ['$event'])
onResize(event) {
if (event.target.innerWidth < 768) {
this.sidenav.fixedTopGap = 55;
this.opened = false;
} else {
this.sidenav.fixedTopGap = 55;
this.opened = true;
}
}
isBiggerScreen() {
const width =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;
if (width < 768) {
return true;
} else {
return false;
}
}
}
......@@ -3,16 +3,68 @@ import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AddStudentComponent } from './components/add-student/add-student.component';
import { EditStudentComponent } from './components/edit-student/edit-student.component';
import { StudentsListComponent } from './components/students-list/students-list.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AngularMaterialModule } from './material.module';
import { ApiService } from './shared/api.service';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent
AppComponent,
AddStudentComponent,
EditStudentComponent,
StudentsListComponent,
],
imports: [
BrowserAnimationsModule,
AngularMaterialModule,
HttpClientModule,
ReactiveFormsModule,
BrowserModule,
AppRoutingModule
AppRoutingModule,
FormsModule,
],
providers: [],
bootstrap: [AppComponent]
providers: [ApiService],
bootstrap: [AppComponent],
})
export class AppModule { }
export class AppModule {}
// import { BrowserModule } from '@angular/platform-browser';
// import { NgModule } from '@angular/core';
// import { AppRoutingModule } from './app-routing.module';
// import { AppComponent } from './app.component';
// import { AddStudentComponent } from './components/add-student/add-student.component';
// import { EditStudentComponent } from './components/edit-student/edit-student.component';
// import { StudentsListComponent } from './components/students-list/students-list.component';
// import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
// @NgModule({
// declarations: [
// AppComponent,
// AddStudentComponent,
// EditStudentComponent,
// StudentsListComponent,
// ],
// imports: [BrowserModule, AppRoutingModule, BrowserAnimationsModule],
// providers: [],
// bootstrap: [AppComponent],
// })
// export class AppModule {}
// @NgModule({
// declarations: [
// AppComponent,
// AddStudentComponent,
// EditStudentComponent,
// StudentsListComponent,
// ],
// imports: [BrowserModule, AppRoutingModule, BrowserAnimationsModule],
// providers: [],
// bootstrap: [AppComponent],
// })
// export class AppModule {}
<!-- Title group -->
<div class="title-group">
<h1 class="mat-h1">Add Student</h1>
<mat-divider fxFlex="1 0"></mat-divider>
</div>
<!-- Form -->
<div class="inner-wrapper">
<form
[formGroup]="studentForm"
(ngSubmit)="submitStudentForm()"
#resetStudentForm="ngForm"
novalidate
>
<!-- Left block -->
<mat-card>
<div class="controlers-wrapper">
<!-- Name -->
<mat-form-field class="example-full-width">
<input
matInput
placeholder="Student name"
formControlName="student_name"
/>
<mat-error *ngIf="handleError('student_name', 'required')">
You must provide a<strong>student name</strong>
</mat-error>
</mat-form-field>
<!-- Email -->
<mat-form-field class="example-full-width">
<input
matInput
placeholder="Student email"
formControlName="student_email"
/>
<mat-error *ngIf="handleError('student_email', 'required')">
You must provide a<strong>student email</strong>
</mat-error>
</mat-form-field>
<!-- Section -->
<mat-form-field>
<mat-label>Section</mat-label>
<mat-select [(value)]="selected" formControlName="section">
<mat-option
[value]="sectioinArray"
*ngFor="let sectioinArray of SectioinArray"
>{{ sectioinArray }}
</mat-option>
</mat-select>
<mat-error *ngIf="handleError('section', 'required')">
Section is required
</mat-error>
</mat-form-field>
</div>
</mat-card>
<!-- Right block -->
<mat-card>
<div class="controlers-wrapper">
<!-- Add subjects -->
<mat-form-field class="multiple-items">
<mat-chip-list #chipList>
<mat-chip
*ngFor="let subjectArray of subjectArray"
[selectable]="selectable"
[removable]="removable"
(removed)="remove(subjectArray)"
>
{{ subjectArray.name }}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input
placeholder="Add subject"
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)"
/>
</mat-chip-list>
<i
class="material-icons tooltip-info"
matTooltip="Enter subject name and press enter to add subjects"
>
info
</i>
</mat-form-field>
<!-- Date of birth -->
<mat-form-field>
<input
matInput
readonly
[matDatepicker]="picker"
placeholder="Date of birth"
formControlName="dob"
(dateChange)="formatDate($event)"
/>
<mat-datepicker-toggle
matSuffix
[for]="picker"
></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
<mat-error *ngIf="handleError('dob', 'required')">
Date of birth is required
</mat-error>
</mat-form-field>
<!-- Gender -->
<div class="misc-bottom-padding">
<mat-label>Gender:</mat-label>
<mat-radio-group
aria-label="Select an option"
formControlName="gender"
>
<mat-radio-button value="Male">Male</mat-radio-button>
<mat-radio-button value="Female">Female</mat-radio-button>
</mat-radio-group>
</div>
</div>
</mat-card>
<!-- Submit & Reset -->
<mat-card>
<div class="full-wrapper button-wrapper">
<div class="button-wrapper">
<button mat-flat-button color="warn">Submit</button>
</div>
</div>
</mat-card>
</form>
</div>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AddStudentComponent } from './add-student.component';
describe('AddStudentComponent', () => {
let component: AddStudentComponent;
let fixture: ComponentFixture<AddStudentComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AddStudentComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AddStudentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Router } from '@angular/router';
import { Component, OnInit, ViewChild, NgZone } from '@angular/core';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { MatChipInputEvent } from '@angular/material/chips';
import { ApiService } from './../../shared/api.service';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
export interface Subject {
name: string;
}
@Component({
selector: 'app-add-student',
templateUrl: './add-student.component.html',
styleUrls: ['./add-student.component.css'],
})
export class AddStudentComponent implements OnInit {
visible = true;
selectable = true;
removable = true;
addOnBlur = true;
@ViewChild('chipList') chipList;
@ViewChild('resetStudentForm') myNgForm;
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
studentForm: FormGroup;
subjectArray: Subject[] = [];
SectioinArray: any = ['A', 'B', 'C', 'D', 'E'];
ngOnInit() {
this.submitBookForm();
}
constructor(
public fb: FormBuilder,
private router: Router,
private ngZone: NgZone,
private studentApi: ApiService
) {}
/* Reactive book form */
submitBookForm() {
this.studentForm = this.fb.group({
student_name: ['', [Validators.required]],
student_email: ['', [Validators.required]],
section: ['', [Validators.required]],
subjects: [this.subjectArray],
dob: ['', [Validators.required]],
gender: ['Male'],
});
}
/* Add dynamic languages */
add(event: MatChipInputEvent): void {
const input = event.input;
const value = event.value;
// Add language
if ((value || '').trim() && this.subjectArray.length < 5) {
this.subjectArray.push({ name: value.trim() });
}
// Reset the input value
if (input) {
input.value = '';
}
}
/* Remove dynamic languages */
remove(subject: Subject): void {
const index = this.subjectArray.indexOf(subject);
if (index >= 0) {
this.subjectArray.splice(index, 1);
}
}
/* Date */
formatDate(e) {
var convertDate = new Date(e.target.value).toISOString().substring(0, 10);
this.studentForm.get('dob').setValue(convertDate, {
onlyself: true,
});
}
/* Get errors */
public handleError = (controlName: string, errorName: string) => {
return this.studentForm.controls[controlName].hasError(errorName);
};
/* Submit book */
submitStudentForm() {
if (this.studentForm.valid) {
this.studentApi.AddStudent(this.studentForm.value).subscribe((res) => {
this.ngZone.run(() => this.router.navigateByUrl('/students-list'));
});
}
}
}
<p>edit-student works!</p>
<!-- Title group -->
<div class="title-group">
<h1 class="mat-h1">Add Student</h1>
<mat-divider fxFlex="1 0"></mat-divider>
</div>
<!-- Form -->
<div class="inner-wrapper">
<form
[formGroup]="studentForm"
(ngSubmit)="updateStudentForm()"
#resetStudentForm="ngForm"
novalidate
>
<!-- Left block -->
<mat-card>
<div class="controlers-wrapper">
<!-- Name -->
<mat-form-field class="example-full-width">
<input
matInput
placeholder="Student name"
formControlName="student_name"
/>
<mat-error *ngIf="handleError('student_name', 'required')">
You must provide a<strong>student name</strong>
</mat-error>
</mat-form-field>
<!-- Email -->
<mat-form-field class="example-full-width">
<input
matInput
placeholder="Student email"
formControlName="student_email"
/>
<mat-error *ngIf="handleError('student_email', 'required')">
You must provide a<strong>student email</strong>
</mat-error>
</mat-form-field>
<!-- Section -->
<mat-form-field>
<mat-label>Section</mat-label>
<mat-select [(value)]="selected" formControlName="section">
<mat-option
[value]="sectioinArray"
*ngFor="let sectioinArray of SectioinArray"
>{{ sectioinArray }}
</mat-option>
</mat-select>
<mat-error *ngIf="handleError('section', 'required')">