Client: use ng2-tag-input for forms with video tags

This commit is contained in:
Chocobozzz 2017-04-16 14:06:48 +02:00
parent ad42bea3a5
commit 3758da9489
8 changed files with 35 additions and 141 deletions

View File

@ -58,7 +58,7 @@
"ng-router-loader": "^1.0.2", "ng-router-loader": "^1.0.2",
"ng2-file-upload": "^1.1.4-2", "ng2-file-upload": "^1.1.4-2",
"ng2-smart-table": "1.0.3", "ng2-smart-table": "1.0.3",
"ng2-tag-input": "1.0.1", "ng2-tag-input": "^1.0.5",
"ngc-webpack": "1.1.0", "ngc-webpack": "1.1.0",
"ngx-bootstrap": "1.6.6", "ngx-bootstrap": "1.6.6",
"node-sass": "^4.1.1", "node-sass": "^4.1.1",

View File

@ -38,8 +38,9 @@ export const VIDEO_DESCRIPTION = {
}; };
export const VIDEO_TAGS = { export const VIDEO_TAGS = {
VALIDATORS: [ Validators.maxLength(10) ], VALIDATORS: [ Validators.minLength(2), Validators.maxLength(10) ],
MESSAGES: { MESSAGES: {
'minlength': 'A tag should be more than 2 characters long.',
'maxlength': 'A tag should be less than 10 characters long.' 'maxlength': 'A tag should be less than 10 characters long.'
} }
}; };

View File

@ -59,25 +59,11 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="tags">Tags</label> <span class="little-information">(press enter to add the tag)</span> <label for="tags" class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
<input <tag-input
type="text" class="form-control" id="currentTag" [ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
formControlName="currentTag" (keyup)="onTagKeyPress($event)" formControlName="tags" maxItems="3" modelAsStrings="true"
> ></tag-input>
<div *ngIf="formErrors.currentTag" class="alert alert-danger">
{{ formErrors.currentTag }}
</div>
</div>
<div class="tags">
<div class="label label-primary tag" *ngFor="let tag of tags">
{{ tag }}
<span class="remove" (click)="removeTag(tag)">x</span>
</div>
</div>
<div *ngIf="tagsError" class="alert alert-danger">
{{ tagsError }}
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@ -30,6 +30,9 @@ export class VideoAddComponent extends FormReactive implements OnInit {
videoLicences = []; videoLicences = [];
videoLanguages = []; videoLanguages = [];
tagValidators = VIDEO_TAGS.VALIDATORS;
tagValidatorsMessages = VIDEO_TAGS.MESSAGES;
error: string = null; error: string = null;
form: FormGroup; form: FormGroup;
formErrors = { formErrors = {
@ -37,20 +40,17 @@ export class VideoAddComponent extends FormReactive implements OnInit {
category: '', category: '',
licence: '', licence: '',
language: '', language: '',
description: '', description: ''
currentTag: ''
}; };
validationMessages = { validationMessages = {
name: VIDEO_NAME.MESSAGES, name: VIDEO_NAME.MESSAGES,
category: VIDEO_CATEGORY.MESSAGES, category: VIDEO_CATEGORY.MESSAGES,
licence: VIDEO_LICENCE.MESSAGES, licence: VIDEO_LICENCE.MESSAGES,
language: VIDEO_LANGUAGE.MESSAGES, language: VIDEO_LANGUAGE.MESSAGES,
description: VIDEO_DESCRIPTION.MESSAGES, description: VIDEO_DESCRIPTION.MESSAGES
currentTag: VIDEO_TAGS.MESSAGES
}; };
// Special error messages // Special error messages
tagsError = '';
fileError = ''; fileError = '';
constructor( constructor(
@ -80,7 +80,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
licence: [ '', VIDEO_LICENCE.VALIDATORS ], licence: [ '', VIDEO_LICENCE.VALIDATORS ],
language: [ '', VIDEO_LANGUAGE.VALIDATORS ], language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
currentTag: [ '', VIDEO_TAGS.VALIDATORS ] tags: [ '']
}); });
this.form.valueChanges.subscribe(data => this.onValueChanged(data)); this.form.valueChanges.subscribe(data => this.onValueChanged(data));
@ -105,6 +105,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
const licence = this.form.value['licence']; const licence = this.form.value['licence'];
const language = this.form.value['language']; const language = this.form.value['language'];
const description = this.form.value['description']; const description = this.form.value['description'];
const tags = this.form.value['tags'];
form.append('name', name); form.append('name', name);
form.append('category', category); form.append('category', category);
@ -118,8 +119,8 @@ export class VideoAddComponent extends FormReactive implements OnInit {
form.append('description', description); form.append('description', description);
for (let i = 0; i < this.tags.length; i++) { for (let i = 0; i < tags.length; i++) {
form.append(`tags[${i}]`, this.tags[i]); form.append(`tags[${i}]`, tags[i]);
} }
}; };
@ -133,33 +134,18 @@ export class VideoAddComponent extends FormReactive implements OnInit {
this.fileError = 'You did not add a file.'; this.fileError = 'You did not add a file.';
} }
return this.form.valid === true && this.tagsError === '' && this.fileError === ''; return this.form.valid === true && this.fileError === '';
} }
fileChanged() { fileChanged() {
this.fileError = ''; this.fileError = '';
} }
onTagKeyPress(event: KeyboardEvent) {
// Enter press
if (event.keyCode === 13) {
this.addTagIfPossible();
}
}
removeFile() { removeFile() {
this.uploader.clearQueue(); this.uploader.clearQueue();
} }
removeTag(tag: string) {
this.tags.splice(this.tags.indexOf(tag), 1);
this.form.get('currentTag').enable();
}
upload() { upload() {
// Maybe the user forgot to press "enter" when he filled the field
this.addTagIfPossible();
if (this.checkForm() === false) { if (this.checkForm() === false) {
return; return;
} }
@ -206,25 +192,4 @@ export class VideoAddComponent extends FormReactive implements OnInit {
this.uploader.uploadAll(); this.uploader.uploadAll();
} }
private addTagIfPossible() {
const currentTag = this.form.value['currentTag'];
if (currentTag === undefined) return;
// Check if the tag is valid and does not already exist
if (
currentTag.length >= 2 &&
this.form.controls['currentTag'].valid &&
this.tags.indexOf(currentTag) === -1
) {
this.tags.push(currentTag);
this.form.patchValue({ currentTag: '' });
if (this.tags.length >= 3) {
this.form.get('currentTag').disable();
}
this.tagsError = '';
}
}
} }

View File

@ -50,3 +50,7 @@ div.file-to-upload {
font-size: 0.8em; font-size: 0.8em;
font-style: italic; font-style: italic;
} }
.label-tags {
margin-bottom: 0;
}

View File

@ -59,25 +59,11 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="tags">Tags</label> <span class="little-information">(press enter to add the tag)</span> <label for="tags" class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
<input <tag-input
type="text" class="form-control" id="currentTag" [ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
formControlName="currentTag" (keyup)="onTagKeyPress($event)" formControlName="tags" maxItems="3" modelAsStrings="true"
> ></tag-input>
<div *ngIf="formErrors.currentTag" class="alert alert-danger">
{{ formErrors.currentTag }}
</div>
</div>
<div class="tags">
<div class="label label-primary tag" *ngFor="let tag of tags">
{{ tag }}
<span class="remove" (click)="removeTag(tag)">x</span>
</div>
</div>
<div *ngIf="tagsError" class="alert alert-danger">
{{ tagsError }}
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@ -30,6 +30,9 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
videoLanguages = []; videoLanguages = [];
video: Video; video: Video;
tagValidators = VIDEO_TAGS.VALIDATORS;
tagValidatorsMessages = VIDEO_TAGS.MESSAGES;
error: string = null; error: string = null;
form: FormGroup; form: FormGroup;
formErrors = { formErrors = {
@ -37,20 +40,16 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
category: '', category: '',
licence: '', licence: '',
language: '', language: '',
description: '', description: ''
currentTag: ''
}; };
validationMessages = { validationMessages = {
name: VIDEO_NAME.MESSAGES, name: VIDEO_NAME.MESSAGES,
category: VIDEO_CATEGORY.MESSAGES, category: VIDEO_CATEGORY.MESSAGES,
licence: VIDEO_LICENCE.MESSAGES, licence: VIDEO_LICENCE.MESSAGES,
language: VIDEO_LANGUAGE.MESSAGES, language: VIDEO_LANGUAGE.MESSAGES,
description: VIDEO_DESCRIPTION.MESSAGES, description: VIDEO_DESCRIPTION.MESSAGES
currentTag: VIDEO_TAGS.MESSAGES
}; };
// Special error messages
tagsError = '';
fileError = ''; fileError = '';
constructor( constructor(
@ -73,7 +72,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
licence: [ '', VIDEO_LICENCE.VALIDATORS ], licence: [ '', VIDEO_LICENCE.VALIDATORS ],
language: [ '', VIDEO_LANGUAGE.VALIDATORS ], language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
currentTag: [ '', VIDEO_TAGS.VALIDATORS ] tags: [ '' ]
}); });
this.form.valueChanges.subscribe(data => this.onValueChanged(data)); this.form.valueChanges.subscribe(data => this.onValueChanged(data));
@ -99,33 +98,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
); );
} }
checkForm() {
this.forceCheck();
return this.form.valid === true && this.tagsError === '' && this.fileError === '';
}
onTagKeyPress(event: KeyboardEvent) {
// Enter press
if (event.keyCode === 13) {
this.addTagIfPossible();
}
}
removeTag(tag: string) {
this.tags.splice(this.tags.indexOf(tag), 1);
this.form.get('currentTag').enable();
}
update() { update() {
// Maybe the user forgot to press "enter" when he filled the field
this.addTagIfPossible();
if (this.checkForm() === false) {
return;
}
this.video.patch(this.form.value); this.video.patch(this.form.value);
this.videoService.updateVideo(this.video) this.videoService.updateVideo(this.video)
@ -143,27 +116,6 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
} }
private addTagIfPossible() {
const currentTag = this.form.value['currentTag'];
if (currentTag === undefined) return;
// Check if the tag is valid and does not already exist
if (
currentTag.length >= 2 &&
this.form.controls['currentTag'].valid &&
this.tags.indexOf(currentTag) === -1
) {
this.tags.push(currentTag);
this.form.patchValue({ currentTag: '' });
if (this.tags.length >= 3) {
this.form.get('currentTag').disable();
}
this.tagsError = '';
}
}
private hydrateFormFromVideo() { private hydrateFormFromVideo() {
this.form.patchValue(this.video.toJSON()); this.form.patchValue(this.video.toJSON());
} }

View File

@ -1,6 +1,6 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
// import { TagInputModule } from 'ng2-tag-input'; import { TagInputModule } from 'ng2-tag-input';
import { VideosRoutingModule } from './videos-routing.module'; import { VideosRoutingModule } from './videos-routing.module';
import { VideosComponent } from './videos.component'; import { VideosComponent } from './videos.component';
@ -18,7 +18,7 @@ import { SharedModule } from '../shared';
@NgModule({ @NgModule({
imports: [ imports: [
// TagInputModule, TagInputModule,
VideosRoutingModule, VideosRoutingModule,
SharedModule SharedModule