remove special character with directive not work angular - javascript

i want transform text in uppercase and remove special character of input text using directive.
the directive is this:
import { Directive, EventEmitter, Output, Input, OnInit, ChangeDetectorRef } from '#angular/core';
#Directive({
selector: '[uppercase]',
host: {
'[value]': 'uppercase',
'(input)': 'format($event.target.value)'
}
})
export class UppercaseDirective implements OnInit {
#Input() uppercase: string;
#Output() uppercaseChange: EventEmitter<string> = new EventEmitter<string>();
constructor(private cdr: ChangeDetectorRef) {
}
ngOnInit() {
this.uppercase = this.uppercase || '';
this.format(this.uppercase);
}
format(value) {
let regNumber = /^\d+$/;
if (!value || regNumber.test(value)) return
let valueValido = value.replace(/[`~!##$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '');
valueValido = valueValido.toUpperCase();
this.uppercaseChange.next(valueValido);
this.cdr.detectChanges();
console.log(valueValido)
}
}
}
the input continue show special caracter, but in log i can see the value, and it not have more special caracter.
i use '' to replace, and not work, but if i use any caracter or space to replace ex: ' ', it work, but i need replace with no value ''. How i can do it?
#Edit
the solution not work, the code:
<div [ngSwitch]="input.controlType">
<div class="ui-g-12" *ngSwitchCase="'textbox'" [class.esconder]="input.hidden" >
<label for="input.key">{{input.label | doisPontos}}</label><br>
<input [formControlName]="input.key" [id]="input.key" [type]="input.type" [ngStyle]="{'width':input.width}"
pInputText [(uppercase)]="form.controls[input.key].value" [class.ui-state-error]="form.controls[input.key].touched && form.controls[input.key].invalid "
[value]="form.controls[input.key].value | removeEspecialCaractere" >
</div>
the pipe:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'removeEspecialCaractere'
})
export class removeEspecialCaracterePipe implements PipeTransform {
transform(value: any, args?: any): any {
return value === undefined ? '' : value.replace(/[`~!##$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '').toUpperCase();
}
}

For Text Transform use Pipe. place the pipe transform where you want to remove special character
html
{{ p | transform}}
transform.pipe.ts
transform(value: any, args?: any): any {
return value === undefined ? '' : value.replace(/[`~!##$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '').toUpperCase();
}
Example:https://stackblitz.com/edit/angular-wp12pu

Related

Search Exact String using custom pipe in Angular 8

I have created a custom pipe in order to filter my data. This is my pipe code
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filterAll'
})
export class SpecialPipe implements PipeTransform {
transform(value: any, searchText: any): any {
if(!searchText) {
return value;
}
return value.filter((data) => JSON.stringify(data).toLowerCase().includes(searchText) );
}
}
This filter is totally working well, but my requirement is to search the exact string. I have to return the values begins with my searchText (not included). I have also tried .startsWith(), which is also not working. Is there any way to achive this?
startsWith is what you're looking for.
Here's the working snippet:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filter',
})
export class FilterPipe implements PipeTransform {
transform(items: any[], filterdata: string): any[] {
if (!items) return [];
if (!filterdata) return items;
filterdata = filterdata.toString().toLowerCase();
return items.filter((it) => {
return it.name.toLowerCase().startsWith(filterdata);
});
}
}
Working StackBlitz demo

How can I execute action after data-bind in Angular 2?

I'm developing an Angular 2 SPA. My application is composed by:
One component
One directive
I've builded one directive that format text input using onfocus and onblur events. On focus event remove dots to text value, on blur event add thousand dots to text value.
Following component's code:
<div>
<input id="input" [(ngModel)]="numero" InputNumber />
</div>
Following component's TypeScript code:
import { Component } from '#angular/core';
#Component({
selector: 'counter',
templateUrl: './counter.component.html'
})
export class CounterComponent {
numero: number;
public incrementCounter() {
}
ngOnInit() {
this.numero = 100100100;
}
}
Following directive's TypeScript code:
import { Directive, HostListener, ElementRef, OnInit } from "#angular/core";
#Directive({ selector: "[InputNumber]" })
export class InputNumber implements OnInit, OnChanges {
private el: HTMLInputElement;
constructor(private elementRef: ElementRef) {
this.el = this.elementRef.nativeElement;
}
ngOnInit(): void {
// this.el.value is empty
console.log("Init " + this.el.value);
this.el.value = this.numberWithCommas(this.el.value);
}
ngOnChanges(changes: any): void {
// OnChanging value this code is not executed...
console.log("Change " + this.el.value);
this.el.value = this.numberWithCommas(this.el.value);
}
#HostListener("focus", ["$event.target.value"])
onFocus(value: string) {
this.el.value = this.replaceAll(value, ".", "");
}
#HostListener("blur", ["$event.target.value"])
onBlur(value: string) {
this.el.value = this.numberWithCommas(value);
}
private numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}
private escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
private replaceAll(str, find, replace) {
return str.replace(new RegExp(this.escapeRegExp(find), 'g'), replace);
}
}
The following code works except that I need lost focus for show my number like "100.100.100". How can I perform this action on init data loading?
I add one example at this link: Plnkr example
Thanks
You can do this by using a Pipe which takes a boolean parameter that represents your focus/no focus action.
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({name: 'dots'})
export class DotsPipe implements PipeTransform {
transform(value: number, hasFocus:boolean): any {
if(hasFocus){
return value.toString().replace(/\./g,'');
}else{
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}
}
}
Then you have to apply the Pipe on your [ngModel] and use Angular events (focus) and (focusout) to change your variable.
<input [ngModel]="numero | dots : hasFocus" (focus)="hasFocus=true" (focusout)="hasFocus=false" (ngModelChange)="numero=$event" />
I think that your directive should implement ControlValueAccessor interface https://angular.io/docs/ts/latest/api/forms/index/ControlValueAccessor-interface.html
It is needed for writing model in your directive. ControlValueAccessor interface has writeValue(value: any) method that will be initially called.
So your writeValue method will be something like this:
private onChange: (_: any) => {};
...
writeValue(val) {
const editedValue = this.numberWithCommas(val);
this._onChange(val);
}
registerOnChange(fn: any) : void {
this._onChange = fn;
}

Angular2 min directive validator

I'm writing an angular2 validator directive. I have the following situation:
There's a number A and there's a number B, i need to validate if the number in the B field is lesser or equal the number in A field, i'm using template driven forms.
The code in directive is
import { Directive, Input, OnChanges, SimpleChanges } from '#angular/core';
import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } from '#angular/forms';
export function validateLesserOrEqual(number: number): ValidatorFn {
console.log(number);
return (c: AbstractControl) => {
return c.value <= number ? null : {
validateLesserOrEqual: {
valid: false
}
}
}
}
#Directive({
selector: '[lesserOrEqual][ngModel]'
})
export class LesserOrEqualValidator implements Validator, OnChanges {
#Input() lesserOrEqualInput: number;
private _validator = Validators.nullValidator;
ngOnChanges(changes: SimpleChanges) {
const change = changes['lesserOrEqual'];
if(change) {
const val: number = change.currentValue;
this._validator = validateLesserOrEqual(val);
}
else {
this._validator = Validators.nullValidator;
}
}
validate(c: AbstractControl): {[number: number]: any} {
return this._validator(c);
}
}
and in my input i have the following [lesserOrEqual]="movement.parcel_number", but when i put the square brackets surrounding the directive i got the following error Unhandled Promise rejection: Template parse errors:
Can't bind to 'lesserOrEqual' since it isn't a known property of 'input'. ("dirty}"

Use AngularJS 2 Component like a function in the element attribute

Hi guys!
I'm learning AngularJS 2 for a while now and now creating my own app based on Laravel 5 REST API. Anyway - that isn't very important atm.
What is important is that I want to provide the translation for the whole application and I found an issue that is hard to solve for me.
So - from the beginning... I'm created my ResourcesService that's translating the string:
getTranslation ( key: string, replace: Array<TranslationReplace> = null, locale: string = null, fallback: boolean = null ): Observable<Resource> {
var params = "key=" + key +
( replace ? "&replace=" + JSON.stringify(replace) : '') +
( locale ? "&locale=" + locale : '') +
( fallback ? "&fallback=" + fallback : '');
var headers = new Headers({'Content-Type':'application/x-www-form-urlencoded'});
return this.http.post(this.apiUrl + 'getTranslation', params, {headers: headers})
.map(this.extractData)
.startWith({ name: 'Loading...', value: 'Translating...' })
.catch(this.handleError);
}
And I created a TranslateComponent that's providing the translation, here's the whole component:
import {Component, Input, Injectable, OnInit, OnChanges, SimpleChange} from "#angular/core";
import {ResourcesService} from "../services/resources.service";
import {TranslationReplace} from "../models/TranslationReplace";
#Component({
selector: 'translate',
template: `{{translation}}`
})
#Injectable()
export class TranslateComponent implements OnInit, OnChanges {
#Input() ref: string;
#Input() replace: Array<TranslationReplace>;
#Input() locale: string;
#Input() fallback: boolean;
private translation: string;
constructor(private resourcesService: ResourcesService) {}
ngOnInit() : void {
this.getTranslation();
}
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
for (let propName in changes) {
if(propName == 'replace') {
this.getTranslation();
}
}
}
private getTranslation(): void {
this.resourcesService.getTranslation(this.ref, this.replace, this.locale, this.fallback).forEach(translation => this.translation = translation.value );
}
}
All is working just perfect and to call for the translation I have to simply call the selector like that:
<translate [ref]="'string.to_translate'"></translate>
But...
Now I'd like to use the translation in the attribute.
So I found the ugly way to achieve it by creating the reference of the translation and the call it in the attribute. But it's very nasty...
First of all I need to add this bit to my template:
<translate [ref]="'string.to_translate'" style="display:none;" #myStringTranslation></translate>
And next in my element call it and ask for the property by the reference:
<input type="text" [(ngModel)]="input" #input="ngModel [placeholder]="myStringTranslation.translation">
And I really don't like the idea.
What I'm looking for is to call it somehow, I don't know... emit it? And make it looks better. Don't create extra elements.
So my question is:
Can I do it better? Can I somehow call the translation directly from the attribute without the reference?
** ----- UPDATE ----- **
Ok, I learn my lesson :) Thanks to Meir for showing me the right direction and also the Angular.io site for the tutorials.
So finally I added a TranslateDirective to my application:
import {Directive, Input, ElementRef, OnChanges, OnInit, SimpleChange, Renderer} from "#angular/core";
import {TranslationReplace} from "../models/TranslationReplace";
import {ResourcesService} from "../services/resources.service";
#Directive({
selector: '[translate]'
})
export class TranslateDirective implements OnInit, OnChanges {
#Input('translate') ref: string;
#Input('translateReplace') replace: Array<TranslationReplace>;
#Input('translateLocale') locale: string;
#Input('translateFallback') fallback: boolean;
#Input('translateAttr') attr: string;
private translation: string;
constructor(
private elRef: ElementRef,
private renderer: Renderer,
private resourcesService: ResourcesService
) {}
ngOnInit():void {
this.getTranslation();
}
ngOnChanges(changes: {[propKey: string]: SimpleChange}):void {
for (let propName in changes) {
if(propName == 'replace') {
this.getTranslation();
}
}
}
private getTranslation(): void {
if(this.attr)
this.resourcesService.getTranslation(this.ref, this.replace, this.locale, this.fallback).forEach(translation =>
{
this.translation = translation.value;
this.renderer.setElementAttribute(this.elRef.nativeElement,this.attr,this.translation);
});
}
}
And now can easily add the translations to the attributes like that:
<input type="text" [(ngModel)]="input" #input="ngModel [translate]="'string.to_translate'" [translateAttr]="'placeholder'">
Thanks for your help!!
You can turn it into an attribute directive:
#Directive({
selector: 'translate'
})
export class TranslateDirectiev {
#Input() translate: string;
constructor(private elRef: ElementRef){}
ngOnChanges(changes: SimpleChanges): void {
if(this.translate){
var translatedText: string = translateSvc.translate(this.translate);
this.renderer.setElementProperty(this.elementRef.nativeElement, 'innerHTML', translatedText);
}
}
}
This is a simple example without the service injection. Also, for input fields you might need to have a different approach and update the value attribute and not the innerHtml

innerHtml doesn't work with ionic 2 pipes, how to?

I have a simple pipe that returns some html
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'rating',
pure: false
})
export class RatingPipe implements PipeTransform {
transform(value: any): string {
let stars = "<ion-icon name='star'>" + value + "</ion-icon>";
return stars;
}
}
the problem is when i use it, i get nothing
// this works fine
<p><span innerHtml="{{'<h1>some text</h1>'}}"></span></p>
// if I add a pipe, it doesn't work
<p><span innerHtml="{{variableFromControler | rating}}"></span></p>
// if I add a pipe, it doesn't work
<p><span [innerHtml]="variableFromControler | rating"></span></p>
any ideas?
One solution
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizationService } from '#angular/platform-browser'; // to become DomSanitizer
#Pipe({
name: 'rating',
pure: false
})
export class RatingPipe implements PipeTransform {
sanitizer: any;
constructor(private domSanitizationService: DomSanitizationService) {
this.sanitizer = domSanitizationService;
}
transform(value: any): string {
value = parseInt(value);
let stars = '';
for(let i = 1; i <= 5; i++) {
stars += i <= value ? "<ion-icon class='ion-ios-star'></ion-icon>" : "<ion-icon class='ion-ios-star-outline'></ion-icon>";
}
return this.sanitizer.bypassSecurityTrustHtml(stars);
}
}
documentation on DomSanitizationService
It won't work with this html
"<ion-icon name='star'>" + value + "</ion-icon>"
because ion-icon is a ionic-angular component and it should load via angular2 instead of just using innerHTML.
Anyway you should use DomSanitanizeService for your html pipe like this:
#Pipe({
name: 'rating',
pure: false
})
export class RatingPipe implements PipeTransform {
constructor(private domSanitizer: DomSanitizationService){}
transform(value: any): string {
let stars = "<div>" + value + "</div>";
return this.domSanitizer.bypassSecurityTrustHtml(stars);
}
}
And in your html you have to use property binding:
<span [innerHtml]="text | rating"></span>
I would leverage a custom icon wrapper for your case:
#Component({
selector: 'ion-rating-icon',
template: '<ion-icon name="star">{{rating}}</ion-icon>'
})
class RatingIconComponent {
#Input() rating;
}
Then use it like:
<ion-rating-icon [rating]="text"></ion-rating-icon>
See all examples in Plunker

Categories

Resources