i'm working on a Angular2 application. I'm trying to mask a creditcard. Everything is fine but I got an issue.
For example I enterd 2222-3333-1111. After that I realized I forgot to enter 0000 between 2 and 3. When I try to enter the value between 2 and 3, the cursor moving to end and the output is like "2222-0333-3111-1000".
I tried some solutions from stackOverFlow but nothing helped me. Please suggest me some solution to solve this.
Below is the code which I have implimented
protected digitPattern = /\d{1,4}\-{0,1}\d{0,4}\-{0,1}\d{0,4}-{0,1}\d{0,4}-{0,1}\d{0,4}/;
constructor(model: FormControlName) {
this.model = model;
}
#HostListener('input', ['$event']) onInput(event: any) {
const currentValue = this.model.value;
this.updateValue(currentValue);
}
#HostListener('ngModelChange', ['$event']) onNgModelChange(currentValue: string) {
this.updateValue(currentValue);
}
// updates the actual and displayed values
updateValue(currentValue: string) {
const actualValue = this.getActualValue(currentValue);
const maskedValue = this.getMaskedValue(actualValue);
if (currentValue !== actualValue) {
// This is the actual binding (unmasked) value
this.model.control.setValue(actualValue, {emitModelToViewChange: false});
}
// This is the displaying (masked) value
this.model.valueAccessor.writeValue(maskedValue);
}
// Returns the masked value
getMaskedValue(actualValue: string): string {
let maskedValue = '';
const unmaskedValue = actualValue.replace(/\D+/g, '');
for (let i = 0; i < unmaskedValue.length && i < 23; i++) {
if (!(i % 4) && (i > 0)) {
maskedValue += this.separator;
}
maskedValue += unmaskedValue[i];
}
if (actualValue.endsWith(this.separator)) {
if (maskedValue.length === 3 || maskedValue.length === 7) {
maskedValue += this.separator;
}
}
return maskedValue;
}
// Returns the actual (unmasked) value
getActualValue(currentValue: string): string {
let result = '';
// Check if something is available to mask
if (currentValue && currentValue.length > 0) {
const digits = currentValue.match(this.digitPattern);
if (digits) {
for (const value of digits) {
result += value;
}
}
}
return result;
}
Related
I'm working on the coding exercise to build a text editor and add some operations like append, delete and move cursor. Can anyone please explain me why in the delete function, text.substring(cursorPosition + 1) gives me an empty string instead of 'ou!' like when I do text.substring(6).
function textEditor2_2(queries) {
// create cursurPosition, text and result text array variables
let cursorPosition = 0;
let text = "";
let textArray = [];
// append text function
const appendText = (string) => {
text += string;
cursorPosition += string.length;
textArray.push(text);
}
// move cursur position function
const moveCursor = (specifiedPosition) => {
if (specifiedPosition < 0) {
cursorPosition = 0;
} else if (specifiedPosition > cursorPosition) {
return;
} else {
cursorPosition = specifiedPosition
}
}
// delete text function
const deleteText = () => {
console.log(text) // 'Hey, you!'
console.log(cursorPosition) // '5'
console.log(text.substring(6)) // 'ou!'
console.log(text.substring(cursorPosition + 1)) // ''
text = string.substring(0, cursorPosition) + string.substring(cursorPosition + 1);
textArray.push(text);
}
// iterate thru queries and apply callback based on operation type
queries.forEach(operation => {
if (operation[0] === 'APPEND') {
appendText(operation[1])
} else if (operation[0] === 'MOVE') {
moveCursor(operation[1])
} else if (operation[0] === 'DELETE') {
deleteText()
}
})
return textArray;
}
let queriesSample = [
["APPEND", "Hey, you!"],
["MOVE", "5"],
["DELETE"],
]
console.log(textEditor2_2(queriesSample));
i have these inputs and i wanted to check every one of them has value then do something;
const tch_family_name = document.getElementById('tch_family_name');
const tch_lastname = document.getElementById('tch_lastname');
const tch_name = document.getElementById('tch_name');
const tch_phone = document.getElementById('tch_phone');
const first_alph = document.getElementById('first_alph');
const second_alph = document.getElementById('second_alph');
const third_alph = document.getElementById('third_alph');
const tch_bday = document.getElementById('tch_bday');
const textarea1 = document.getElementById('textarea1');
and I'm checking they have value or not like this
function checkEmpty(check) {
for (i = 0; i < check.length; i++) {
if (check[i].value == "" || check[i].value == " " || check[i].value == null) {
check[i].classList.add('inputErrorBorder')
} else {
check[i].classList.remove('inputErrorBorder')
}
}
}
//mainInfo button id
mainInfo.addEventListener('click', () => {
test = [tch_family_name, tch_lastname, tch_name, tch_phone, first_alph, second_alph, third_alph, tch_bday, textarea1]
checkEmpty(test)
})
now how to do something when all input have value;
I tried else if() but it gave an incorrect result for example when first input don't value then it wont add inputErrorBorder class to a second or third inputs.
Please help;
One of the easiest ways to add this to your current setup is to add a flag variable to the checkEmpty function and return that value. Then process the results in the EventListener
checkEmpty With hasEmpty Flag
function checkEmpty(check) {
let hasEmpty = false;
for (let i = 0; i < check.length; i++) {
if (check[i].value === "" || check[i].value === " " || check[i].value == null) {
check[i].classList.add('inputErrorBorder');
hasEmpty = true;
} else {
check[i].classList.remove('inputErrorBorder');
}
}
return hasEmpty;
}
Using hasEmpty flag from checkEmpty
mainInfo.addEventListener('click', () => {
let test = [tch_family_name, tch_lastname, tch_name, tch_phone,
first_alph, second_alph, third_alph, tch_bday, textarea1];
let hasEmpty = checkEmpty(test);
if (!hasEmpty) {
// All Have Value
} else {
// Something has missing value
}
})
I have a simple bit of code for reading input for a terminal-based build script.
async function readLine(): Promise<string> {
return new Promise<string>(resolve => {
const callback = (data: any) => {
process.stdin.off('data', callback);
resolve(data.toString().trim());
};
process.stdin.on('data', callback);
});
}
This works well enough, but I'd like to be able to detect if an up-arrow is pressed so a user can back up to a previous prompt.
Every example I've seen so far that would allow me to detect an up-arrow key requires totally abandoning line-based input, instead handling all input one character at a time. I'd rather not do that.
What I'd like is to have a callback that's triggered only by the up-arrow key (and maybe other special keys later on), with all other keys coming through the usual 'data' callback, one full Enter-terminated line at a time.
Is there a way to do this?
Having found no better answer, I settled for handling all characters one character at a time, and writing my own terminal line input routine.
import * as readline from 'readline';
import { Key } from 'readline';
readline.emitKeypressEvents(process.stdin);
process.stdin.setRawMode(true);
function write(s: string): void {
process.stdout.write(s);
}
async function readUserInput(): Promise<string> {
return new Promise<string>(resolve => {
let buffer = '';
let length = 0;
const clearLine = () => write('\x08 \x08'.repeat(length));
const callback = (ch: string, key: Key) => {
if (ch === '\x03') { // ctrl-C
write('^C\n');
process.exit(130);
}
else if (ch === '\x15') { // ctrl-U
clearLine();
length = 0;
}
else if (key.name === 'enter' || key.name === 'return') {
write('\n');
process.stdin.off('keypress', callback);
resolve(buffer.substr(0, length).trim());
}
else if (key.name === 'backspace' || key.name === 'left') {
if (length > 0) {
write('\x08 \x08');
--length;
}
}
else if (key.name === 'delete') {
if (length > 0) {
write('\x08 \x08');
buffer = buffer.substr(0, --length) + buffer.substr(length + 1);
}
}
else if (key.name === 'up') {
clearLine();
write('\n');
process.stdin.off('keypress', callback);
resolve('\x18');
}
else if (key.name === 'right') {
if (length < buffer.length) {
write(buffer.charAt(length++));
}
}
else if (ch != null && ch >= ' ' && !key.ctrl && !key.meta) {
write(ch);
buffer = buffer.substr(0, length) + ch + buffer.substr(length++);
}
};
process.stdin.on('keypress', callback);
});
}
I got these two functions, and they work great.
But since I only call global.replaceFields from global.translateAll then I want to get rid of global.replaceFields and put its functionality inside global.translateAll
How would you go about merging global.replaceFields into global.translateAll without losing the current functionality?
Thanks :)
// Translate everything in that field
global.translateAll = (textfield, usersLanguage) => {
for (var property in textfield) {
if (!textfield.hasOwnProperty(property)) {
return false;
} else if (typeof textfield[property] !== "object") {
textfield[property] = global.replaceFields(textfield[property], usersLanguage);
} else {
global.translateAll(textfield[property], usersLanguage);
}
}
}
// Translate everything in that field
global.replaceFields = (textfield, usersLanguage) => {
// Keep running until all fields are replaced
while (textfield.indexOf("{{") != -1) {
// isolate the field
let fromField = textfield.substring((textfield.indexOf("{{") + 2), (textfield.indexOf("}}")));
let toField = ""
// If its a translated text
if (fromField.indexOf("trans") != -1) {
toField = usersLanguage[fromField];
textfield = textfield.replace("{{" + fromField + "}}", toField);
}
}
return (textfield);
}
This should work
global.translateAll = (textfield, usersLanguage) => {
var replaceFields = (textfield, usersLanguage) => {
// Keep running until all fields are replaced
while (textfield.indexOf("{{") != -1) {
// isolate the field
let fromField = textfield.substring((textfield.indexOf("{{") + 2), (textfield.indexOf("}}")));
let toField = ""
// If its a translated text
if (fromField.indexOf("trans") != -1) {
toField = usersLanguage[fromField];
textfield = textfield.replace("{{" + fromField + "}}", toField);
}
}
return (textfield);
}
for (var property in textfield) {
if (!textfield.hasOwnProperty(property)) {
return false;
} else if (typeof textfield[property] !== "object") {
textfield[property] = replaceFields(textfield[property], usersLanguage);
} else {
global.translateAll(textfield[property], usersLanguage);
}
}
}
var fNum = parseFloat("32.23.45"); results in 32.23 but I need the string from last decimal point: 23.45
For example, the following strings should return the following values:
"12.234.43.234" -> 43.234,
"345.234.32.34" -> 32.34 and
"234.34.34.234w" -> 34.34
A fairly direct solution:
function toFloat(s) {
return parseFloat(s.match(/\d+(\.|$)/g).slice(-2).join('.'));
}
For example:
toFloat("32.23.45") // 23.45
toFloat("12.234.43.234") // 43.234
toFloat("345.234.32.34") // 32.34
toFloat("234.34.34.234w") // 34.34
Update: Here's an alternative version which will more effectively handle strings with non-digits mixed in.
function toFloat(s) {
return parseFloat(s.match(/.*(\.|^)(\d+\.\d+)(\.|$)/)[2]);
}
The following will do exactly what you would like (I'm presuming that the last one should return 34.234, not 34.24).
alert (convText("12.234.43.234"));
alert (convText("345.234.32.34"));
alert (convText("234.34.34.234w"));
function convText(text) {
var offset = text.length - 1;
var finished = false;
var result = '';
var nbrDecimals = 0;
while(!finished && offset > -1) {
if(!isNaN(text[offset]) || text[offset] === '.') {
if(text[offset] === '.') {
nbrDecimals++;
}
if(nbrDecimals > 1) {
finished = true;
} else {
result = text[offset] + result;
}
}
offset--;
}
return result;
}