I have a capitalization pipe. Almost all characters are capitalized. Turkish 'ı' character is converted correctly into 'I'. However, the 'i' character is converted to 'I' when it should be converted into the 'İ' character.
Example 1: ırmak => Irmak (Correct).
Example 2: ismail => Ismail (Incorrect, should be İsmail).
My code is below:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({name: 'capitalize'})
export class CapitalizePipe implements PipeTransform {
transform(value: string, args: string[]): any {
if (!value) return value;
return value.replace(/[çğıöşüa-zA-z]\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
}
}
First, create a new file and name it "titlecase-turkish.pipe.ts".
Open the file and add the following code:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'titlecaseTurkish'
})
export class TitleCaseTurkishPipe implements PipeTransform {
transform(value: string): string {
if (!value) return null;
let words = value.split(' ');
for (var i = 0; i < words.length; i++) {
words[i] = words[i].toLocaleLowerCase('tr-TR');
words[i] = words[i].charAt(0).toLocaleUpperCase('tr-TR') + words[i].slice(1);
}
return words.join(' ');
}
}
The above code implements the basic functionality of the TitleCaseTurkishPipe. It splits the incoming string value by spaces and converts the first letter of each word to uppercase while converting all other letters to lowercase. To correctly capitalize Turkish characters, the toLocaleLowerCase() and toLocaleUpperCase() methods have been used.
To use the TitleCaseTurkishPipe, you need to first declare it in the AppModule. Add the following code to do so:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { AppComponent } from './app.component';
import { TitleCaseTurkishPipe } from './titlecase-turkish.pipe';
#NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent, TitleCaseTurkishPipe],
bootstrap: [AppComponent]
})
export class AppModule { }
You can now use the TitleCaseTurkishPipe in your HTML file. For example, the following code formats the value of the "name" variable using the TitleCaseTurkishPipe:
<h1>{{ name | titlecaseTurkish }}</h1>
Related
I have a JavaFX TextField specialized to accept numbers, including scientific notation. It does pretty much everything I want. But, because it accepts scientific notation, it is easy for a user to enter a number beyond the range that can be represented by a double. When they do, the TextField displays "Infinity" (or "-Infinity"). When that happens the field can no longer be edited to correct the problem. The contents cannot be selected and deleted either. Tapping the "Escape" key does not return to the previous contents.
Here is an SSCCE, based closely on the answer by James_D to this question a few years ago.
import java.text.DecimalFormatSymbols;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class NumericTextFieldDemo extends Application {
char sep = new DecimalFormatSymbols().getDecimalSeparator();
String negStarter = new StringBuilder("-").append(sep).toString();
String posStarter = new StringBuilder("+").append(sep).toString();
String patternStr = new StringBuilder()
.append("[+|-]?(([1-9][0-9]*)|0)?(\\")
.append(sep)
.append("[0-9]*)?(([e|E][+|-]?[0-9]*)?)")
.toString();
Pattern validEditingState = Pattern.compile(patternStr);
class NumericTextField extends TextField {
UnaryOperator<TextFormatter.Change> filter = c -> {
String text = c.getControlNewText();
if (validEditingState.matcher(text).matches()) {
return c;
} else {
return null;
}
};
StringConverter<Double> converter = new StringConverter<Double>() {
#Override
public Double fromString(String s) {
if (s.isEmpty() || "-".equals(s) || "+".equals(s)
|| negStarter.equals(s) || posStarter.equals(s)) {
return 0.0;
} else {
return Double.valueOf(s);
}
}
#Override
public String toString(Double d) {
return d.toString();
}
};
NumericTextField(double initValue) {
TextFormatter<Double> textFormatter = new TextFormatter<>(converter, initValue, filter);
textFormatter.valueProperty().addListener((ObservableValue<? extends Double> obs, Double oldValue, Double newValue) -> {
System.out.println("User entered value: " + newValue);
});
setTextFormatter(textFormatter);
}
NumericTextField() {
this(0.0);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
NumericTextField ntf = new NumericTextField();
// Setting the font seems to be required on macOS.
ntf.setFont(new Font("Arial", 14));
VBox root = new VBox(5, ntf);
root.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(root, 250, 150));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Is there any way to catch the infinities and leave the TextField in a usable state? Is there some change that could be made to the class to prevent entering such numbers in the first place?
Just use the built-in string converter for doubles:
TextFormatter<Double> tf = new TextFormatter<>(new DoubleStringConverter());
TextField ntf = new TextField();
ntf.setTextFormatter(tf);
I have a directive that should trim a value in a input box. The directive trim the value in the form but when I submit it, the value is not trimed.
// this code works and the value is trimmed after submitting the form
<input type="text" matInput formControlName="adress" oninput="this.value = this.value.trim()">
// this code trim the value on the form but NOT after submitting the form
<input type="text" matInput formControlName="adress" trimvalue>
I am missing something in the directive ?
Directive:
import { Directive, ElementRef, HostListener, Renderer2 } from '#angular/core';
#Directive({
selector: '[trimvalue]'
})
export class TrimDirective {
constructor(
private renderer: Renderer2,
private elementRef: ElementRef
) { }
#HostListener('input') onInput(event) {
let value = this.elementRef.nativeElement.value;
if (value) {
value = value.trim();
this.elementRef.nativeElement.value = value.trim();
this.renderer.setValue(this.elementRef.nativeElement, this.elementRef.nativeElement.value);
}
}
}
angular source code - setValue()
you can see setValue is woking by node.textContent = value;
setValue(node: RText, value: string): void {
node.textContent = value;
}
and textContent is string|null
export interface RText extends RNode {
textContent: string|null;
}
So, I guess setValue() didn't work as predicted is cause by typescript's type go something wrong in background...
You can trim it by nodeValue.
this.elementRef.nativeElement.childNodes.forEach((x: ChildNode, i: number) => {
if (x.nodeName === '#text') {
this.elementRef.nativeElement.childNodes[i].nodeValue = this.elementRef.nativeElement.childNodes[i].nodeValue.trim();
}
});
}
Is it possible to assert a test if the certain text is found either as full string match or as a sub string of other text?
I want the following test to pass as long as the string Foo is found anywhere, even as sub string of other strings. What should I change?
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Find sub text', (WidgetTester tester) async {
await tester.pumpWidget(Text('Error code is Foo', textDirection: TextDirection.ltr));
expect(find.text('Error code is Foo'), findsOneWidget);
expect(find.text('Foo'), findsOneWidget);
});
}
So far:
The following TestFailure object was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: _TextFinder:<zero widgets with text "Foo" (ignoring offstage widgets)>
Which: means none were found but one was expected
You can use find.textContaining:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Find sub text', (WidgetTester tester) async {
await tester.pumpWidget(Text('Error code is Foo', textDirection: TextDirection.ltr));
expect(find.text('Error code is Foo'), findsOneWidget);
expect(find.textContaining('Foo'), findsOneWidget);
});
}
Replace:
expect(find.text('Foo'), findsOneWidget);
with:
expect(find.byWidgetPredicate((widget) {
if (widget is Text) {
final Text textWidget = widget;
if (textWidget.data != null) return textWidget.data.contains('Foo');
return textWidget.textSpan.toPlainText().contains('Foo');
}
return false;
}), findsOneWidget);
You will first find Text widget, then check for substring in the Text string
I have an input type number. I have a directive that successfully blocks characters other than numbers. And this also allows only single decimal point.
What I need is, the directive should allow copy from field and paste into the field as well.
<input type="number" appNumbersOnly />
import { Directive, ElementRef, HostListener } from "#angular/core";
#Directive({
selector: '[appNumbersOnly]'
})
export class NumbersOnlyDirective {
public text;
private regex: RegExp = new RegExp(/^-?[0-9]+(\.[0-9]*){0,1}$/g);
private specialKeys: Array<string> = ['Backspace', 'Tab'];
constructor(private el: ElementRef) {}
#HostListener('keypress', ['$event']) onKeyDown(event: KeyboardEvent) {
if (this.specialKeys.indexOf(event.key) !== -1) return;
const current: string = this.el.nativeElement.value;
const next: string = current.concat(event.key);
if(next.includes('.')){
if(this.text == next) event.preventDefault();
this.text= next;
}
if ((next && !String(next).match(this.regex))) {
event.preventDefault();
}
}
}
How to make this directive allow copy paste?
I am not sure about your requirenment. But I think this can help you.
copy
Angular 5 - Copy to clipboard
Paste
Angular - On Paste Event Get Content
I'd like to know how can I create a mask with regex expression for input field.
I need to add some masks to a field, such as: yyyy/yyyy. This sounds like a period.
I saw a link that creates a mask using the pipe from Angular2. Here is the link.
So, I'd like to create a pipe with a different regex expression to allow the user writes only this: yyyy/yyyy ; and using transform method from pipe.
Is this possible?
Here is my pipe and formatter:
import { Pipe, PipeTransform } from "#angular/core";
#Pipe({ name: "mypipe" })
export class MyPipe implements PipeTransform {
private SEPARATOR: string;
constructor() {
this.SEPARATOR = "/";
}
transform(value): string {
let integer = (value || "").toString();
// Here is where the code should be, to transform the value
return integer;
}
transform(value): string {
// parse method
}
}
import { Directive, HostListener, ElementRef, OnInit } from "#angular/core";
// import { MyPipe } from ...
#Directive({ selector: "[myFormatter]" })
export class MyFormatterDirective implements OnInit {
private el: HTMLInputElement;
constructor(
private elementRef: ElementRef,
private mypipe: MyPipe
) {
this.el = this.elementRef.nativeElement;
}
ngOnInit() {
this.el.value = this.mypipe.transform(this.el.value);
}
#HostListener("keydown", ["$event.target.value"])
handleKeyboardEvent(value) {
this.el.value = this.mypipe.transform(value);
}
}