0

I am an aspiring full-stack developer with back-end experience. My application built on angular has a textarea which allows non ASCII characters. Now requirement is to only allow ASCII characters.

My backend brain thought of using a regex to get rid off the non-ASCII characters and filter the ASCII ones before sending the data to backend. The PO however has a diff idea, she wants only ASCII characters to be allowed in the textarea as opposed to filtering it.

Commom use case is users copy pasting remarks or info from some other document and non-ASCII characters get copied along. Is there any way of handlig this. I couldn't find any Agular or HTML tag which supports this out of the box, but again I am just a beginner in front end.

Any pointers are appreciated. Code is as below (the div with class="dialog-panel__content" corresponds to the text area):

<div 
    class="dialog-panel__close"
    aria-label="Close" 
    data-selector="dialog-close"
    *ngIf="showCloseButton" 
    (click)="onClose()">
</div>

<div class="dialog-panel__header">
    <ng-content select="[dialog-header]"></ng-content>
</div>

<div class="dialog-panel__content" [ngClass]="{'scroll':dialog.config.enableScroll}">
    <ng-content></ng-content>
</div>

<div class="dialog-panel__footer">
    <ng-content select="[dialog-footer]"></ng-content>
</div>

Component class code is as below:

import { Component, HostBinding, Input, OnInit } from '@angular/core'; import { Dialog } from '@core/helpers/dialog/dialog';

@Component({
    selector: 'alm-dialog-panel',
    templateUrl: './dialog-panel.component.html',
    styleUrls: ['./dialog-panel.component.scss'],
})
export class DialogPanelComponent implements OnInit {
    @Input() showCloseButton = true;
    @Input() dialog: Dialog<any>;
    @HostBinding('class.large-x-large') largeXlarge: boolean = false;
    @HostBinding('class.medium') medium: boolean = false;
    @HostBinding('class.rectangle') rectangle: boolean = false;
    constructor() {
    }

    ngOnInit() {
        if (!this.dialog) {
            throw new Error('Attribute \'dialog\' is required');
        }
        if (this.dialog.config) {
            this.largeXlarge = this.dialog.config.size === 'large-x-large';
            this.medium = this.dialog.config.size === 'medium';
            this.rectangle = this.dialog.config.size === 'rectangle';
        }
    }

    public onClose(): void {
        this.dialog.close();
    }

}

Dialog:

export const APP_DIALOG_DATA = new InjectionToken<any>('AppDialogData');

export class Dialog<T, D = any, R = any> {
    private overlayRef;
    private contentRef;
    private readonly _afterClosed = new Subject<R | undefined>();

    constructor(
        componentType: ComponentType<T>,
        private overlay: Overlay,
        private injector: Injector,
        public  config: DialogConfig<D>,
    ) {
        const positionStrategy = this.overlay.position().global()
            .centerHorizontally().centerVertically();

        const overlayConfig = new OverlayConfig({
            scrollStrategy: this.overlay.scrollStrategies.block(),
            hasBackdrop: config.hasBackdrop,
            positionStrategy,
        });

        this.overlayRef = this.overlay.create(overlayConfig);
        const portal: ComponentPortal<any> = new ComponentPortal(componentType, null, this.createInjector(config.data));
        this.contentRef = this.overlayRef.attach(portal);
    }

    private createInjector(data: any = ''): PortalInjector {
        const injectionTokens = new WeakMap();

        injectionTokens.set(Dialog, this);
        injectionTokens.set(APP_DIALOG_DATA, data);

        return new PortalInjector(this.injector, injectionTokens);
    }

    close(result?: R) {
        this.overlayRef.dispose();
        this._afterClosed.next(result);
        this._afterClosed.complete();
    }

    public get instance(): ComponentType<T> {
        return this.contentRef.instance;
    }

    public get afterClosed(): Observable<R | undefined> {
        return this._afterClosed.asObservable();
    }

}

Style classes:

@import 'variables';

$alm-modal-container-bg: white;
$alm-modal-container-color: $alm-color-secondary;
$alm-modal-container-border-top-color: $alm-color-bright-blue;

$alm-modal-color-success: $alm-color-green;
$alm-modal-color-info: $alm-color-bright-blue;
$alm-modal-color-warning: $alm-color-amber;
$alm-modal-color-error: $alm-color-red;

:host {
    display: flex;
    flex-direction: column;
    position: relative;
    background: $alm-modal-container-bg;
    color: $alm-modal-container-color;
    border-top: 4px solid $alm-modal-container-border-top-color;
    max-height: 100%;
    height: auto;
    overflow-y: hidden;


    &.large-x-large {
        width: 98vw;
        height: 95vh;
    }

    &.medium {
        width: 500px;
    }

    &.rectangle {
        height: 85vh;
        width: 900px;
    }

    &.success{
        border-color: $alm-modal-color-success;
    }

    &.error{
        border-color: $alm-modal-color-error;
    }

    &.warning{
        border-color: $alm-modal-color-warning;
    }

    &.info{
        border-color: $alm-modal-color-info;
    }

}
   
.dialog-panel__footer:empty {
    display: none;
}
Akash Sharma
  • 330
  • 3
  • 18

1 Answers1

1

From the UX perspective, I'd say you shouldn't BLOCK the input of the characters or delete characters on the fly. If a user pastes something, he expects the contents of the field to be same as the contents of his clipboard. Usually he will not double-check it as that's the expected behavior.

What you should is to validate the contents of the form before submitting it and display information if any of the fields is invalid. Common practice is e.g. showing red outline on the invalid fields and display error message underneath it.

It's hard to give you any further advice since you don't provide the relevant code for the actual form - you can read further about form validation in the official docs here.

Concerning the built-in method - you can look at the pattern HTML attribute. Also, check this SO question for correct regex pattern.

TotallyNewb
  • 3,884
  • 1
  • 11
  • 16