I have written a directive for text input, to support int values.
Here is it
import { NgControl } from '#angular/forms';
import { HostListener, Directive } from '#angular/core';
#Directive({
exportAs: 'number-directive',
selector: 'number-directive, [number-directive]'
})
export class NumberDirective {
private el: NgControl;
constructor(ngControl: NgControl) {
this.el = ngControl;
}
// Listen for the input event to also handle copy and paste.
#HostListener('input', ['$event.target.value'])
onInput(value: string) {
// Use NgControl patchValue to prevent the issue on validation
this.el.control.patchValue(value.replace(/[^0-9]/g, ''));
}
}
And HTML
<div class="form-group">
<label>{{ l("RoomWidth") }}</label>
<input
decimal-number-directive
#roomWidthInput="ngModel"
class="form-control nospinner-input"
type="text"
name="roomWidth"
[(ngModel)]="room.roomWidth"
maxlength="32"
/>
</div>
But I need it to support decimal values. For example 99.5
How do I need to modify it?
Try this:
#HostListener('input', ['$event.target.value'])
onInput(value: string) {
// Use NgControl patchValue to prevent the issue on validation
this.el.control.patchValue(value.replace(/[^0-9].[^0-9]/g, ''));
}
Working_Demo
In my case I have need to considerate two consegutive point too and replace caracter. Maybe is writable with regex but this work for me.
Example if you type or paste 45.456.6 it will be repaced with 45.4566
#HostListener('input', ['$event']) onInputChange(event) {
let initalValue: string = this.el.nativeElement.value;
initalValue = initalValue.replace(/[^\.|0-9]/g, '');
// elimina le seconde occorrenze del punto
const count = (initalValue.match(/\./g) || []).length;
for (let i = 1; i < count; i++) {
initalValue = this.repaceSecondDotOccurrence(initalValue);
}
this.el.nativeElement.value = initalValue;
}
repaceSecondDotOccurrence(inputString): string {
let t = 0;
return inputString.replace(/\./g, function (match) {
t++;
return (t === 2) ? '' : match;
});
}
Related
I have a email subject textbox where I can input combination of dynamic dropdown value and other text entered by user, here I can enter only one dynamic value at start, cant add another dynamic value after that please help.
its an email subject for example there are 3 dynamic value here ["creditcard","accountno","Amount"].
sample output - "Hi jack your creditcard with accoutno has due Amount" here creditcard accoutno and Amount are dynamic value from dropdown and rest are normal text
HTML
<div class="textbox">
<label class="textbox__label" [for]="id">{{label}}</label>
<input class="textbox__input" [type]="type" [id]="id" [placeholder]="placeholder" [value]="value" [name]="name"
autocomplete="off" (input)="onChange($event)" (keyup.Space)="doSomething()" [(ngModel)]="model" />
<ul class="textbox__dropdown" *ngIf="show">
<ng-container *ngFor="let list of listData ; let i = index">
<li (click)="handleSetValue(list)">
<span [style.background-color]="colors[i % colors.length]">{{list.value.charAt(0)}}</span>
{{list.value}}
</li>
</ng-container>
</ul>
</div>
TS
import { Component, VERSION,Output, EventEmitter } from '#angular/core';
import { isEmpty } from 'lodash';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
public dynamicList = ["creditcard","accountno","Amount"]
public value;
public listData: any;
public show: boolean = true;
public model: any;
#Output() selectedValue = new EventEmitter();
onChange(event: any) {
if (event.target.value !== '' && this.dynamicList) {
console.log(event.target.value);
this.show = true;
const item = this.dynamicList.filter((items) => items.toLowerCase().includes(event.target.value));
if (!isEmpty(item)) {
this.listData = item;
console.log(item)
} else {
this.show = false;
this.selectedValue.emit(event.target.value)
}
} else {
this.listData = this.dynamicList;
this.show = false
}
}
Stackblitz-link
You can split the event.target.value that you are making in onChange() method like,
const getLastSearch = event.target.value.split(' ');
Then in the filter method you can use the last recent search into includes to check and display the latest search result like,
const item = this.dynamicList.filter((items) => items.toLowerCase().includes(getLastSearch[getLastSearch.length - 1]));
In app.component.html , for the input box you could use space bar event and call a method to show the dropdown items like,
<input class="textbox__input" type="type" id="id" name="name"
autocomplete="off" (input)="onChange($event)" (keyup.Space)= "spaceEvent($event)" [(ngModel)]="model" />
And the spaceEvent() as follows,
spaceEvent(event: any){
this.listData = this.dynamicList;
this.show = true;
}
Then finally you could split the strings available in the text box and then you can join it by removing the last one and append the clicked list item to as the last item like,
handleSetValue(list) {
let splittedSearch = this.model.split(' '); // Split each string with space
splittedSearch[splittedSearch.length - 1] = ''; // Make the last string empty
splittedSearch = splittedSearch.join(' ') // Join all the splitted string with space
splittedSearch += list; // Concat the splitted search with the selected list item
this.model = splittedSearch; // Assign the splittedsearch to model
this.show = false;
}
Forked Stackblitz here...
Please make the changes as per this
. In TS file
public model: any = "";
onChange(event: any) {
var value = event.target.value;
var inputarray = value.split(" ");
var lastinput = inputarray[inputarray.length - 1]
console.log(lastinput)
if ((value !== '' || inputarray.length> 1) && this.dynamicList) {
console.log(value);
this.show = true;
const item = this.dynamicList.filter((items) => items.toLowerCase().includes(lastinput));
if (!isEmpty(item)) {
this.listData = item;
console.log(item)
} else {
this.show = false;
this.selectedValue.emit(value)
}
} else {
this.listData = this.dynamicList;
this.show = false
}
}
handleSetValue(list) {
debugger
if(this.dynamicList.find(s=>s == list)){
this.model += " "+list;
}
this.show = false;
// this.selectedValue.emit(list.key)
}
in HTML
<div class="textbox">
<input class="textbox__input" type="type" id="id" name="name"
[ngModel]="model" autocomplete="off" (input)="onChange($event)"/>
<ul class="textbox__dropdown" *ngIf="show">
<ng-container *ngFor="let list of listData">
<li (click)="handleSetValue(list)">
{{list}}
</li>
</ng-container>
</ul>
</div>
I am working on making custom multi select using text box.if user enter 1,2,3,4 then 1 2 3 4 should be considered as separate value.i am bale to make this using <input type="text"> but instead of text box i want to div so user can click anywhere in the div and able to add item.
following image is my current implementation.
custom-autocomplete.component.html
<div name="test">
<ul class="autocomplete-text base-auto-select-cointainer">
<li class="d-inline-flex selected-item" *ngFor="let item of itemList;let i=index" title="{{item}}">{{item}}
<span class="remove-item pointer" role="presentation" (click)="handelOnItemRemove(i)">×</span></li>
<li class="d-inline-flex">
<input class="item-input" type="text" (keyup)="handelOnItemKeyUp($event)"
tabindex="0" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
role="textbox">
</li>
</ul>
</div>
custom-autocomplete.component.ts
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'app-custom-autocomplete',
templateUrl: './custom-autocomplete.component.html',
styleUrls: ['./custom-autocomplete.component.css']
})
export class CustomAutocompleteComponent implements OnInit {
itemList: any[] = []; // for collection selcted items
userInputs: any;
model = 'some text';
constructor() { }
// event emiters for passing data to parent componet.
#Output() handelItemSelection: EventEmitter<any> = new EventEmitter<any>();
ngOnInit() {
}
handelOnItemKeyUp(event) {
if (event.target.value) {
let userInput: string = event.target.value;
let splitChar = userInput.charAt(userInput.length - 1);
let tempArray: any[] = userInput.split(',');
if (tempArray.length > 1) {
if (tempArray[0] != "" && tempArray[0] != undefined) {
this.itemList.push(tempArray[0])
this.handelItemSelection.emit(this.itemList); //passing updated items to parent
}
}
console.log('')
splitChar == ',' ?event.target.value = null : '' // setting empty value to text box when user enter ,
}
}
// code block for handel item removal from list.
handelOnItemRemove(index: number) {
this.itemList.splice(index, 1);
this.handelItemSelection.emit(this.itemList); //passing updated items to parent
}
}
can someone suggest me to how to implement this using <div contenteditable="true"></div>
I have two radio buttons (they're not dynamically generated):
<input type="radio" name="orderbydescending" [(ngModel)]="orderbydescending" [value]="['+recordStartDate']">Ascending<br>
<input type="radio" name="orderbydescending" [(ngModel)]="orderbydescending" [value]="['-recordStartDate']">Descending
How do I make one of the radio buttons checked by default?
Thank you!
Edit
The button's values are being passed through this pipe (i.e. not a component, per se...not sure this is worth mentioning?). The app is pretty simple, and the radio buttons are just hardcoded into app.component. Is the pipe the correct place to initialize which radio button is checked by default?
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({name: 'orderBy', pure: false})
export class OrderByPipe implements PipeTransform {
static _OrderByPipeComparator(a:any, b:any):number{
if((isNaN(parseFloat(a)) || !isFinite(a)) || (isNaN(parseFloat(b)) || !isFinite(b))){
//Isn't a number so lowercase the string to properly compare
if(a.toLowerCase() < b.toLowerCase()) return -1;
if(a.toLowerCase() > b.toLowerCase()) return 1;
}
else{
//Parse strings as numbers to compare properly
if(parseFloat(a) < parseFloat(b)) return -1;
if(parseFloat(a) > parseFloat(b)) return 1;
}
return 0; //equal each other
}
transform(input:any, [config = '+']): any{
if(!Array.isArray(input)) return input;
if(!Array.isArray(config) || (Array.isArray(config) && config.length == 1)){
var propertyToCheck:string = !Array.isArray(config) ? config : config[0];
var desc = propertyToCheck.substr(0, 1) == '-';
//Basic array
if(!propertyToCheck || propertyToCheck == '-' || propertyToCheck == '+'){
return !desc ? input.sort() : input.sort().reverse();
}
else {
var property:string = propertyToCheck.substr(0, 1) == '+' || propertyToCheck.substr(0, 1) == '-'
? propertyToCheck.substr(1)
: propertyToCheck;
return input.sort(function(a:any,b:any){
return !desc
? OrderByPipe._OrderByPipeComparator(a[property], b[property])
: -OrderByPipe._OrderByPipeComparator(a[property], b[property]);
});
}
}
else {
//Loop over property of the array in order and sort
return input.sort(function(a:any,b:any){
for(var i:number = 0; i < config.length; i++){
var desc = config[i].substr(0, 1) == '-';
var property = config[i].substr(0, 1) == '+' || config[i].substr(0, 1) == '-'
? config[i].substr(1)
: config[i];
var comparison = !desc
? OrderByPipe._OrderByPipeComparator(a[property], b[property])
: -OrderByPipe._OrderByPipeComparator(a[property], b[property]);
//Don't return 0 yet in case of needing to sort by next property
if(comparison != 0) return comparison;
}
return 0; //equal each other
});
}
}
Edit 2
So in component.app.ts I've edited my export class AppComponent{ to the following:
export class AppComponent {
artists = ARTISTS;
currentArtist: Artist;
orderbydescending = ['-recordStartDate'];
showArtist(item) {
this.currentArtist = item;
}
}
This works in terms of preventing the previous errors, but it doesn't actually make the radio button selected. It still appears as though it's unselected - even though it functions as though it is. Does this make sense?
If you're doing this in Angular 2+ with 2 way binding, in the component where this HTML is being used, you could just try initializing the value associated with the input.
// in your component ts file
orderbydescending: boolean = true;
and you could leave the HTML the same. Although, you seem to have 2 radio buttons associated with the same data value, orderbydescending. I don't know if that's what you intend, but it looks like it could cause problems.
Here's some code from my personal side project to give you a better idea.
#Component({
selector: 'gmu-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
// here you would put your variables
myFlag: boolean = true;
constructor() { }
ngOnInit() {
}
}
If orderbydescending and recordStartDate are members of your component class:
#Component({
...
})
export class MyComponent {
public recordStartDate: any = ...
public orderbydescending: any = +recordStartDate;
...
}
the appropriate radio button will be checked if you assign the radio button values with [value]:
<input type="radio" name="order" [(ngModel)]="orderbydescending" [value]="+recordStartDate">Ascending<br>
<input type="radio" name="order" [(ngModel)]="orderbydescending" [value]="-recordStartDate">Descending
In the case shown above, the ascending order radio button will be checked by default because the orderbydescending variable is initially set to +recordStartDate.
Note: The variables in my sample code are of type any because I don't know exactly what kind of data you are using. Your data will probably have a more specific data type.
Try this in the component
radioValue = {valueAsc: 'Asc', valueDesc: 'Desc'} ;
orderbydescending = 'Asc';
and in the template put this
<input type="radio" name="radioGroup" [(ngModel)]="orderbydescending" [value]="radioValue.valueAsc">Ascending
<input type="radio" name="radioGroup" [(ngModel)]="orderbydescending" [value]="radioValue.valueDesc">Descending
With this the first radio button is checked, if you don't want any radio button selected assign to the variable orderbydescending null.
orderbydescending = 'null;
Is there anyway to detect removed character from a text using ngModel in Angular 2 ?
I want something like:
Original text: #Hello World !
Modified text : Hello World !
Console.log
Removed character: '#'
I've found a cool example on Javascript with Jquery by Arie Xiao below:
https://stackoverflow.com/a/17005983/5668956
But I wonder if I can use another thing beside Jquery, as I find that Jquery is pretty hard to implement in Angular 2
I would suggest a Forms controller for acting on changes on the input field. The snippet displays the character add or deleted from the input field.
Check out my Plunker to see the code running.
#Component({
selector: 'app-root',
template: `
<input type="text" [formControl]="form" class="form-control" >
<h3 *ngIf="initial">
Text <span [style.color]="textadd ? 'green' : 'red'" > {{textadd ? "add" : "removed" }} </span>: {{change}}
</h3>
`,
})
export class App {
form;
textadd;
text = "#Hello World!";
initial = false;
change;
ngOnInit() {
this.form = new FormControl({ value: this.text, disabled: false });
this.form.valueChanges.subscribe(val => {
let change;
if (val.length > this.text.length) {
change = val;
for (let variable of this.text) {
change = change.replace(variable, '');
this.textadd = true;
}
} else {
change = this.text;
for (let variable of val) {
change = change.replace(variable, '');
this.textadd = false;
}
}
this.change = change;
this.text = val;
this.initial = true;
});
}
}
What is the event to handle "enter" or "go" keyboard key on an input?
The input is not used within a form. So clicking on it will not "submit". I just need the event.
(Running android + Ionic 2 on Beta 11)
I did like this:
<ion-input type="text" [(ngModel)]="username" (keyup.enter)="handleLogin()"></ion-input>
And:
handleLogin() {
// Do your stuff here
}
For my case, I'm not getting next button within a form for both Android and IOS. I'm only getting done. so I handled done as a next by using following directive.
import { Directive, HostListener, Output, EventEmitter, ElementRef, Input } from '#angular/core';
import { Keyboard } from '#ionic-native/keyboard';
#Directive({
selector: '[br-data-dependency]' // Attribute selector
})
export class BrDataDependency {
#Output() input: EventEmitter<string> = new EventEmitter<string>();
#Input('br-data-dependency') nextIonInputId: any = null;
constructor(public Keyboard: Keyboard,
public elementRef: ElementRef) {
}
#HostListener('keydown', ['$event'])
keyEvent(event) {
if (event.srcElement.tagName !== "INPUT") {
return;
}
var code = event.keyCode || event.which;
if (code === TAB_KEY_CODE) {
event.preventDefault();
this.onNext();
let previousIonElementValue = this.elementRef.nativeElement.children[0].value;
this.input.emit(previousIonElementValue)
} else if (code === ENTER_KEY_CODE) {
event.preventDefault();
this.onEnter();
let previousIonElementValue = this.elementRef.nativeElement.children[0].value;
this.input.emit(previousIonElementValue)
}
}
onEnter() {
console.log("onEnter()");
if (!this.nextIonInputId) {
return;
}
let nextInputElement = document.getElementById(this.nextIonInputId);
// On enter, go to next input field
if (nextInputElement && nextInputElement.children[0]) {
let element: any = nextInputElement.children[0];
if (element.tagName === "INPUT") {
element.focus();
}
}
}
onNext() {
console.log("onNext()");
if (!this.nextIonInputId) {
return;
}
let nextInputElement = document.getElementById(this.nextIonInputId);
// On enter, go to next input field
if (nextInputElement && nextInputElement.children[0]) {
let element: any = nextInputElement.children[0];
if (element.tagName === "INPUT") {
element.focus();
}
}
}
}
const TAB_KEY_CODE = 9;
const ENTER_KEY_CODE = 13;
How to use?
<form [formGroup]="loginForm" (ngSubmit)="login(loginForm.value)">
<ion-input br-data-dependency="password" type="text" formControlName="username" placeholder="USERNAME" (input)="userNameChanged($event)"></ion-input>
<ion-input id="password" password type="password" formControlName="password" placeholder="PASSWORD"></ion-input>
<button submit-button ion-button type="submit" block>Submit</button>
</form>
Hope this help someone!!
Edit: Let me know if you are abled to show next button for the first input box?
The right way to do that might be to use Ionic2 forms. I'v found this: https://blog.khophi.co/ionic-2-forms-formbuilder-and-validation/
Otherwise - If you "just want the "Enter" event handler" this is quite complex (!) and not out of the box as you might be thinking:
HTML:
<ion-input id="myInput" #myInput type="submit" [(model)]="textValue" (input)="setText( $event.target.value )" placeholder="Send Message ..." autocorrect="off"></ion-input>
TS:
...
declare let DeviceUtil: any;
...
export class Component_OR_PAGE
{
public textValue: string;
#ViewChild( 'myInput') inputElm : ElementRef;
#HostListener( 'keydown', ['$event'] )
keyEvent( e )
{
var code = e.keyCode || e.which;
log.d( "HostListener.keyEvent() - code=" + code );
if( code === 13 )
{
log.d( "e.srcElement.tagName=" + e.srcElement.tagName );
if( e.srcElement.tagName === "INPUT" )
{
log.d( "HostListener.keyEvent() - here" );
e.preventDefault();
this.onEnter();
DeviceUtil.closeKeyboard();
}
}
};
...
setText( text )
{
log.d( "setText() - text=" + text );
this.textValue = text;
}
onEnter()
{
console.log( "onEnter()" );
this.inputText.emit( this.textValue );
this.textValue = "";
// ionic2 beta11 has issue with data binding
let myInput = document.getElementById( 'myInput' );
let innerInput: HTMLInputElement = <HTMLInputElement>myInput.children[0];
innerInput.value = "";
}
}
JS:
DeviceUtil =
{
closeKeyboard: function()
{
cordova.plugins.Keyboard.close();
}
}