diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 6e40470..940a3f5 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -1,40 +1,61 @@
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BrowserModule } from '@angular/platform-browser';
-import { EffectsModule } from '@ngrx/effects';
import { NgModule } from '@angular/core';
+import { ReactiveFormsModule, FormsModule } from '@angular/forms';
+
+import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
-import { MatToolbarModule } from '@angular/material/toolbar';
-import { MatCardModule } from '@angular/material/card';
+import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatChipsModule } from '@angular/material/chips';
+import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { MatInputModule } from '@angular/material/input';
import { AppComponent } from './app.component';
import { reducers, metaReducers } from './reducers';
import { CommentStoreModule } from './store';
+import { PipesModule } from './pipes/pipes.module';
+import { DirectivesModule } from './directives/directives.module';
+
import { CommentCardComponent } from './comment-card/comment-card.component';
import { CommentsListComponent } from './comments-list/comments-list.component';
-import { PipesModule } from './pipes/pipes.module';
+import { CommentCardEditComponent } from './comment-card-edit/comment-card-edit.component';
+
+const materialModules = [
+ MatAutocompleteModule,
+ MatButtonModule,
+ MatCardModule,
+ MatChipsModule,
+ MatFormFieldModule,
+ MatIconModule,
+ MatToolbarModule,
+ MatInputModule
+];
@NgModule({
declarations: [
AppComponent,
CommentCardComponent,
- CommentsListComponent
+ CommentsListComponent,
+ CommentCardEditComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
+ ReactiveFormsModule,
+ FormsModule,
StoreModule.forRoot(reducers, {
metaReducers
}),
EffectsModule.forRoot([]),
CommentStoreModule,
- MatToolbarModule,
- MatCardModule,
- MatButtonModule,
- MatIconModule,
- PipesModule
+ ...materialModules,
+ PipesModule,
+ DirectivesModule
],
providers: [],
bootstrap: [AppComponent]
diff --git a/src/app/comment-card-edit/comment-card-edit.component.html b/src/app/comment-card-edit/comment-card-edit.component.html
new file mode 100644
index 0000000..e0cb72b
--- /dev/null
+++ b/src/app/comment-card-edit/comment-card-edit.component.html
@@ -0,0 +1,36 @@
+
\ No newline at end of file
diff --git a/src/app/comment-card-edit/comment-card-edit.component.scss b/src/app/comment-card-edit/comment-card-edit.component.scss
new file mode 100644
index 0000000..1c15ddd
--- /dev/null
+++ b/src/app/comment-card-edit/comment-card-edit.component.scss
@@ -0,0 +1,11 @@
+:host {
+ display: block;
+}
+
+.comment-card {
+ max-width: 420px;
+}
+
+.full-width-field {
+ width: 100%;
+}
\ No newline at end of file
diff --git a/src/app/comment-card-edit/comment-card-edit.component.spec.ts b/src/app/comment-card-edit/comment-card-edit.component.spec.ts
new file mode 100644
index 0000000..2a0cd5f
--- /dev/null
+++ b/src/app/comment-card-edit/comment-card-edit.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CommentCardEditComponent } from './comment-card-edit.component';
+
+describe('CommentCardEditComponent', () => {
+ let component: CommentCardEditComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CommentCardEditComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CommentCardEditComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/comment-card-edit/comment-card-edit.component.ts b/src/app/comment-card-edit/comment-card-edit.component.ts
new file mode 100644
index 0000000..98ebfe9
--- /dev/null
+++ b/src/app/comment-card-edit/comment-card-edit.component.ts
@@ -0,0 +1,105 @@
+import { COMMA, ENTER } from '@angular/cdk/keycodes';
+import { Component, ElementRef, ViewChild, OnInit, Input } from '@angular/core';
+import { FormBuilder, Validators, FormGroup } from '@angular/forms';
+import { MatAutocompleteSelectedEvent, MatAutocomplete } from '@angular/material/autocomplete';
+import { MatChipInputEvent } from '@angular/material/chips';
+
+import { Observable } from 'rxjs';
+import { map, startWith, withLatestFrom } from 'rxjs/operators';
+
+import { Comment, CommentFacade } from '../store/comment'
+
+@Component({
+ selector: 'app-comment-card-edit',
+ templateUrl: './comment-card-edit.component.html',
+ styleUrls: ['./comment-card-edit.component.scss']
+})
+export class CommentCardEditComponent implements OnInit {
+ @ViewChild('tagInput') tagInput: ElementRef;
+ @ViewChild('auto') matAutocomplete: MatAutocomplete;
+ @Input() data: Comment;
+ form: FormGroup;
+ tagCtrl = this.fb.control([]);
+ filteredTags: Observable;
+ separatorKeysCodes: number[] = [ENTER, COMMA];
+
+ constructor(
+ private readonly fb: FormBuilder,
+ private readonly commentFacade: CommentFacade
+ ) { }
+
+ ngOnInit(): void {
+ if (!!this.data) {
+ this.form = this.fb.group({
+ id: [this.data.id],
+ title: [this.data.title, [Validators.required]],
+ tags: [this.data.tags],
+ text: [this.data.text, [Validators.required]],
+ });
+ } else {
+ this.form = this.fb.group({
+ id: [null],
+ title: [null, [Validators.required]],
+ tags: [[]],
+ text: [null, [Validators.required]],
+ });
+ }
+ this.filteredTags = this.tagCtrl.valueChanges.pipe(
+ startWith(null),
+ withLatestFrom(this.commentFacade.tags$),
+ map(([tag, allTags]) => {
+ if (tag === null) {
+ return [...allTags];
+ }
+ const value = tag.toLowerCase()
+ return allTags.filter(t => t.toLowerCase().includes(value));
+ })
+ );
+ }
+
+ submit(event, commentForm): void {
+ event.preventDefault();
+ if (!!this.form.value.id) {
+ this.commentFacade.edit(this.form.value);
+ } else {
+ this.commentFacade.add(this.form.value);
+ }
+ this.form.reset();
+ commentForm.resetForm();
+ }
+
+ cancel(): void {
+ this.commentFacade.toggleEdit(undefined);
+ }
+
+ selected(event: MatAutocompleteSelectedEvent): void {
+ const tags = [...this.form.value.tags];
+ this.form.get('tags').setValue([...tags, event.option.viewValue]);
+ this.tagInput.nativeElement.value = '';
+ this.tagCtrl.setValue(null);
+ }
+
+
+ addTag(event: MatChipInputEvent): void {
+ const input = event.input;
+ const value = event.value;
+
+ if ((value || '').trim()) {
+ const tags = [...this.form.value.tags];
+ this.form.get('tags').setValue([...tags, value.trim()]);
+ }
+
+ if (input) {
+ input.value = '';
+ }
+
+ this.tagCtrl.setValue(null);
+ }
+
+ removeTag(tag: string): void {
+ const tags = [...this.form.value.tags];
+
+ this.form.get('tags').setValue([...tags.filter(t => t !== tag)]);
+ }
+
+}
diff --git a/src/app/comment-card/comment-card.component.html b/src/app/comment-card/comment-card.component.html
index 949de2e..b095de0 100644
--- a/src/app/comment-card/comment-card.component.html
+++ b/src/app/comment-card/comment-card.component.html
@@ -1,13 +1,17 @@