two way binding [(ngmodel)] unaffected by jquery change event - javascript

I need to update the angular model on a js change event,
this is a simplified, isolated demo:
hero-form.component.html:
<button type="button" id='btn1'>change</button>
<input type="text" id="txt1" name="txt1" [(ngModel)]="str1" />{{str1}}
hero-form.component.ts:
...
import * as $ from "jquery";
...
export class HeroFormComponent implements OnInit {
str1 = "initval";
ngAfterViewInit(){
var txt1 = $('#txt1');
$('#btn1').on('click', function(){
txt1.val('new val').change();
// when js/jquery triggers a change on the input, I need the str1
// which was bound using [(ngModel)] to be updated
});
}
when clicking the button the value of the textbox changes to new val but the interpolation {{str1}} is not affected, however if I change the value of the textbox manually it works.
is it possible to update the model bound with ngmodel on a js change event ?

In angular project we should not implement your requirement like your way.
You can use (click) event and #txt1 to get value
In ts component implement change str1 value.
export class AppComponent {
name = 'Binding data in Angular';
str1 = "initval";
ngAfterViewInit() {
}
change(val) {
console.log(val)
this.str1 = val;
}
}
Updated HTML
<hello name="{{ name }}"></hello>
<button type="button" id='btn1' (click)="change(txt1.value)">change</button>
<input type="text" #txt1 id="txt1" name="txt1" />{{str1}}
Demo: https://stackblitz.com/edit/angular-click-change-value

Related

Angular : Fetch value of textbox onclick of button

I want to print the value of textbox when i click of button. But it throws nullpointerexception. I also need to keep some value in the textbox i dont understand why?. Whatever i type in textbox and when i click on buttom i need to print the value of textbox What is the issue?
Below is my code:
ts file
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-mypage',
templateUrl: './mypage.component.html',
styleUrls: ['./mypage.component.scss']
})
export class mypageComponent implements OnInit {
constructor(private router: Router) {
}
ngOnInit() {
}
myFunc() {
var num1 = ((document.getElementById("exchageRateDate") as HTMLInputElement).value);
console.log(num1);
}
}
HTML File
<br>Welcome.<br>
Place - <input type="text" value="Sydney" ng-model="placeId" />
<button (click)="myFunc(placeId)" formtarget="_blank">Test</button>
Error:
ERROR TypeError: Cannot read property 'value' of null
Seems like you forgot to add id in input field
<input id="exchageRateDate" type="text" value="Sydney" ng-model="placeId" />
Edit: Angular way to do it
As you are using Angular so I will suggest you a better way to do this using NgModel
Try this
<br>Welcome.<br>
Place - <input type="text" value="Sydney" [(ngModel)]="placeId" />
<button (click)="myFunc(placeId)" formtarget="_blank">Test</button>
In component:
myFunc(num1) {
console.log(num1);//here you will get input value through ng-model
}
You need to set id of input tag remove ng-model because it's a angularjs(1.x.x) not angular(2/4/5/6/7/8)
In html
<br>Welcome.<br>
Place - <input id="exchageRateDate" type="text" value="Sydney" />
<button (click)="myFunc()" formtarget="_blank">Test</button>
In typescript:
myFunc() {
var num1 = ((document.getElementById("exchageRateDate") as HTMLInputElement).value);
console.log(num1);
}
Here is working example: Get value of input tag using HTMLInputElement
<input type="text" class="textbox" id="Summary" name="Summary"placeholder="Summary" value="{{Item.summary}}">
(document.getElementById("Summary") as HTMLInputElement).value;

get the closest element to a component angular 5

I have a text field in an component, that when in focus, needs to populate a hidden field outside of the component that is nearest to it.
At the moment I can get the field in focus, but what I need to do now is populate the hidden field.
Here is what I have so far:
HTML:
<h2>Test</h2>
<input type="hidden" id="h0" name="" value="">
<app-focus></app-focus>
<input type="hidden" id="h0" name="" value="">
<app-focus></app-focus>
<input type="hidden" id="h0" name="" value="">
<app-focus></app-focus>
<input type="hidden" id="h0" name="" value="">
<app-focus></app-focus>
App-Focus:
<p>
focus works!
<input id="inputId" type="text" name="" value="">
</p>
Component:
ngAfterViewInit(){
setTimeout(()=>{
let dummyEl = this.elRef.nativeElement.querySelectorAll("#inputId")
for(let i = 0; i < dummyEl.length; i++){
let el = dummyEl[i]
// if (document.activeElement === el){ stops working if I use this
console.log(document.activeElement === el)
console.log(el.closest("#h0"))//always returns null
// }
}
}, 3000)
}
closest searches direct descendants but not siblings of the descendants e.g.
<div>
<input id="#h0">
<app-root>
<p>
<input id="#inputId">
</p>
</app-root>
</div>
In this HTML, calling closest from the #inputId element will only find the div, not the input because it is not a direct descendant - it is a child of div.
You need to modify your html so app-root and #h0 are wrapped by a div. You can then find the closest div and select the child of that element e.g.
ngAfterViewInit() {
setTimeout(() => {
let dummyEl = this.elRef.nativeElement.querySelectorAll('#inputId');
for(let i = 0; i < dummyEl.length; i++) {
let el = dummyEl[i];
let div = el.closest('div');
if(div !== null) {
console.log(div.querySelector('#h0'));
}
}
}, 3000);
}
}
Also you id's must be unique so using #h0 for each input is invalid HTML. You might be better using a class if you want to find the elements with the same "tag" e.g.
<input class="h0" ... >
If you need to pass data from the AppFocusComponent, you could use Angular Event Emitters. The example in the documentation emits null in the $event but other data, both primitive and Objects, can be passed as well.
Here is a link to an example on Stack Blitz
app-focus.component.ts
First, set up an EventEmitter in the AppFocusComponent. The data can be emitted in an Angular Lifecycle Hook. Or can be bound to a User Input Event.
import { AfterViewInit, Component, EventEmitter, Input, Output } from
'#angular/core';
#Component({
selector: 'app-focus',
templateUrl: './app-focus.component.html'
})
export class AppFocusComponent implements AfterViewInit {
#Input() data: any = null;
#Output() focus = new EventEmitter();
ngAfterViewInit() {
setTimeout(()=>{
this.focus.emit(this.data);
}, 3000)
}
onFocus(event: Event) {
console.log(event);
this.focus.emit(this.data);
}
}
app-focus.component.html
Next, bind the focus event on the input to the onFocus() method in the component. Here, ngModel is used to bind the data that is emitted when the onFocus($event) method fires. This can either be from user input, or the data can be passed in via an #Input(). I wasn't sure where the data is coming from, so there a couple of approaches in the example.
<p>
<input type="text" (focus)="onFocus()" [(ngModel)]="data">
</p>
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
h0Value: string = '';
h1Value: string = '';
h2Value: string = '';
h3Value: string = '';
// an alternate way to set the value instead of setting it in the template
setH1Value(event: any) {
this.h1Value = event;
}
}
app.component.html
Lastly, bind the [value] of the <input>s to their respective properties and have the AppComponent listen to the (focus) event from the AppFocusComponent. The data that comes from the AppFocusComponent can be assigned directly in the template. (focus)="h0Value = $event". Or it can be wrapped in a method on the component while passing the $event through. (focus)="setH1Value($event)". If the data is being initialized via data from an API or some other source, it can be passed in via the #Input. data="h2 data".
The labels here are used for demonstration purposes so the data that's emitted by the AppFocusComponent can be viewed in the UI.
<h2>Test</h2>
<label>{{ h0Value }}</label>
<input type="hidden" id="h0" name="" [value]="h0Value">
<app-focus (focus)="h0Value = $event"></app-focus>
<label>{{ h1Value }}</label>
<input type="hidden" id="h1" name="" [value]="h1Value">
<app-focus (focus)="setH1Value($event)"></app-focus>
<label>{{ h2Value }}</label>
<input type="hidden" id="h2" name="" [value]="h2Value">
<app-focus data="h2 data" (focus)="h2Value = $event"></app-focus>
<label>{{ h3Value }}</label>
<input type="hidden" id="h3" name="" [value]="h3Value">
<app-focus (focus)="h3Value = $event"></app-focus>

Angular 2/4 need a Typescript regex to only allow numbers to be entered into input textbox

In my Angular 4 application I have this input box in which I ONLY want numbers... 0-9 to be entered.. otherwise I want it to clear out onkeyup
HTML
<input type="number" (keyup)="numbersOnly($event)" placeholder="0000000000" formControlName="phone" maxlength="10"/>
Above works to call this function in the component
but it is not working to prevent letters.
numbersOnly(val) {
let y = this.trackerForm.controls['phone'].value
y.value = y.value.replace(/[^0-9.-]/g, '');
console.log('y', y);
}
Is .value the wrong approach?
Should I be using event preventdefault?
The console log for 'y' shows correctly.
What do I need to do?
Since you are using ReactiveForm, you should understand that FormConrtol's value only has a getter.
If you want to change formControl's value, use patchValue or setValue.
let y = this.trackerForm.controls['phone'];
this.trackerForm.controls['phone'].patchValue(y.value.replace(/[^0-9.-]/g, ''));
// OR
this.trackerForm.controls['phone'].setValue(y.value.replace(/[^0-9.-]/g, ''));
Refer demo.
You should probably have a model on the input and pass that into your function with the event. Change the model instead of the event value. Also your solution may not be working because the input probably has the value updated on the (keypress) event.
let y = this.trackerForm.controls['phone'].value
^^^^^
y.value = y.value.replace(/[^0-9.-]/g, '');
^^^^
You are already taking the value.
Change it to
let y = this.trackerForm.controls['phone'];
y.value = y.value.replace(/[^0-9.-]/g, '');
You use ngModel instead.
<input type="number" (keyup)="numbersOnly()" placeholder="0000000000" formControlName="phone" maxlength="10" [(ngModel)]="value"/>
value = "";
numbersOnly() {
this.value = this.value.replace(/[^0-9.-]/g, '');
}
To access the value of the input field, use ngModel (documentation)
For form validation, have a look at the built-in tools. If you use these, you can simply use the HTML attribute pattern to achieve a validation of an input field by a regular expression. (documentation)
Updated code:
<input type="number" name="phoneNumber" placeholder="0000000000" pattern="[0-9.-]*" maxlength="10" [(ngModel)]="phoneNumber" #phoneNumber="ngModel"/>
Please note that you need to define a new field named phoneNumber in your component.
For this kind of things angular has directives that listen to the events coming from components.
If you have your input mapped to a model then the way you assign the value will not be reflected into model. So that should be taken care of as well.
#Directive({
selector: '[restrict]',
})
export class RestrictDirective {
constructor(private control: NgControl) {}
#HostListener('keyup', ['$event.target'])
#HostListener('paste', ['$event.target'])
private onInputEvent(input) {
if (input.value) {
let truncated = input.value.replace(PATTERN, ''); //put your pattern here
// change value only if it contains disallowed characters
if (truncated !== input.value) {
this.control.valueAccessor.writeValue(truncated); //write to model
this.control.viewToModelUpdate(truncated); //write to view
}
}
}
}
Then just get to use the directive in the input
<input type="text" restrict/>
For integers the pattern would be
const PATTERN = /[\D]/g;
Improving Damask's answer. If we are using Reactive Forms, I's necesary the last line: "this.control.control.setValue(truncated); "
<input type="text" [restrict]="'[^0-9]'" />
The directive
#Directive({
selector: '[restrict]',
})
export class RestrictDirective {
regexp:any;
#Input('restrict')
set pattern(value)
{
this.regexp=new RegExp(value,"g");
}
constructor(private control: NgControl) {}
#HostListener('input', ['$event.target'])
#HostListener('paste', ['$event.target'])
private onInputEvent(input) {
if (input.value) {
let truncated = input.value.replace(this.regexp, '');
if (truncated !== input.value) {
this.control.valueAccessor.writeValue(truncated); //write to model
this.control.viewToModelUpdate(truncated); //write to view
this.control.control.setValue(truncated); //send to control
}
}
}
}
create a simple directive something like this
import { Directive, HostListener } from '#angular/core';
#Directive({
selector: '[appNumberOnly]'
})
export class NumberOnlyDirective {
constructor() { }
#HostListener('keypress', ['$event'])
onInput(event: any) {
const pattern = /[0-9]/;
const inputChar = String.fromCharCode(event.which ? event.which : event.keyCode);
if (!pattern.test(inputChar)) {
event.preventDefault();
return false;
}
return true;
}
}
import this in your module
and in HTML
<input type="number" appNumberOnly placeholder="0000000000" formControlName="phone" maxlength="10"/>
Also inside your component.ts, inside formBuilder you can have something like this
phone: ['', Validators.compose([Validators.maxLength(10), Validators.pattern('[6-9]\\d{9}'), Validators.required])],

Get element by id - Angular2

I have a code:
document.getElementById('loginInput').value = '123';
But while compiling the code I receive following error:
Property value does not exist on type HTMLElement.
I have declared a var: value: string;.
How can I avoid this error?
Thank you.
if you want to set value than you can do the same in some function on click or on some event fire.
also you can get value using ViewChild using local variable like this
<input type='text' id='loginInput' #abc/>
and get value like this
this.abc.nativeElement.value
here is working example
Update
okay got it , you have to use ngAfterViewInit method of angualr2 for the same like this
ngAfterViewInit(){
document.getElementById('loginInput').value = '123344565';
}
ngAfterViewInit will not throw any error because it will render after template loading
(<HTMLInputElement>document.getElementById('loginInput')).value = '123';
Angular cannot take HTML elements directly thereby you need to specify the element type by binding the above generic to it.
UPDATE::
This can also be done using ViewChild with #localvariable as shown here, as mentioned in here
<textarea #someVar id="tasknote"
name="tasknote"
[(ngModel)]="taskNote"
placeholder="{{ notePlaceholder }}"
style="background-color: pink"
(blur)="updateNote() ; noteEditMode = false " (click)="noteEditMode = false"> {{ todo.note }}
</textarea>
import {ElementRef,Renderer2} from '#angular/core';
#ViewChild('someVar') el:ElementRef;
constructor(private rd: Renderer2) {}
ngAfterViewInit() {
console.log(this.rd);
this.el.nativeElement.focus(); //<<<=====same as oldest way
}
A different approach, i.e: You could just do it 'the Angular way' and use ngModel and skip document.getElementById('loginInput').value = '123'; altogether. Instead:
<input type="text" [(ngModel)]="username"/>
<input type="text" [(ngModel)]="password"/>
and in your component you give these values:
username: 'whatever'
password: 'whatever'
this will preset the username and password upon navigating to page.
Complate Angular Way ( Set/Get value by Id ):
// In Html tag
<button (click) ="setValue()">Set Value</button>
<input type="text" #userNameId />
// In component .ts File
export class testUserClass {
#ViewChild('userNameId') userNameId: ElementRef;
ngAfterViewInit(){
console.log(this.userNameId.nativeElement.value );
}
setValue(){
this.userNameId.nativeElement.value = "Sample user Name";
}
}

How to bind current object to text input?

MessageModel
function MessageModel(content) {
var self = this;
self.content = content;
}
RoomViewModel
self.currentMessage = ko.observable(new MessageModel(""));
self.addMessage = function () {
self.messages.push(self.currentMessage());
self.currentMessage(new MessageModel(""));
};
View
<form data-bind="submit: addMessage">
<input data-bind='value: currentMessage.content, valueUpdate: "afterkeydown"' />
<button id="ButtonSendMessage" type="submit">Send</button>
</form>
When user types in input box want the current message content property to update and when I click add I want the currentMessage to be added with content. But the content is always blank.
Maybe because the content isn't an observable and the value bind is wrong beacuse currentMessage is an observable so to bind any property of you must to do like currentMessage().prop or use the with: currentMessage binding in an element context, try something like this:
function MessageModel(content) {
var self = this;
self.content = ko.observable(content);
}
And also i suggest you to use the textInput bind:
<form data-bind="submit: addMessage">
<input type="text" data-bind='textInput: currentMessage().content' />
<button id="ButtonSendMessage" type="submit">Send</button>
</form>
textInput Binding:
The textInput binding links a text box () or text area () with a viewmodel property, providing two-way updates between the viewmodel property and the element’s value. Unlike the value binding, textInput provides instant updates from the DOM for all types of user input, including autocomplete, drag-and-drop, and clipboard events.
Ref:TextInput Bind

Categories