How to trigger a change event on a textarea when setting the value via ngModel Binding - html

I have a <textarea> within a template driven form of an Angular 7 project.
When editing an object, the form is prefilled with the current values. I want to automatically resize the <textarea> when the content has changed via the [(ngModel)]="property" binding by modifying the element-style.
area.style.overflow = 'hidden';
area.style.height = '0';
area.style.height = area.scrollHeight + 'px';
The code generally is working, but I cannot find a suitable event to trigger it.
Subscribing to the change event of the <textarea> is only working on keyboard input. Using (ngModelChange)="adjustTextAreaSize($event)" has the same behavior.
I tried to execute my resizing code at the end of the ngOnInit() function, but the actual html-control seems to not have any content yet at this point.
Does anyone have an idea which event could do the trick here?
Seemed a rather easy task in the beginning, but I'm breaking my had over this for over an hour now... can not be such a difficult task, can it?

Yes there is a very simple solution for this.
Wrap your textarea inside a form and try the code below:-
HTML
<form #form="ngForm">
<textarea>....</textarea>
</form>
TS
#ViewChild('form') ngForm: NgForm;
ngOnInit() {
this.subscription = this.ngForm.form.valueChanges.subscribe(resp =>
{
console.log(resp); // You get your event here
}
)
}
ngOnDestroy() {
this.subscription.unsubscribe();
}

trigger a change event on a textarea when setting the value via ngModel Binding
This will cause infinite triggering if you do so.
If you don't want to monitor the input model change in a more reactive way, a quicker solution (but a bit hacky) will be simply wrap your code inside setTimeout in ngOnInit() or ngAfterViewInit() where you mentioned it was not working.
setTimeout(() => {
updateSize();
});

Related

How to detect changes in a prefilled Angular Reactive Form in Edit Mode

I want to detect changes on a Reactive Form while working in Edit Mode.
I tried using valueChanges but the issue is when I am loading an already submitted form for editing it, it is triggering events for each prefilled control.
While my requirement is to only trigger when user made any changes to the form.
Anyone can please suggest
Try to subscribe to valueChanges in the ngAfterViewInit() method.
export class MyComponent implements AfterViewInit {
ngAfterViewInit() {
this.myForm.controls['name'].valueChanges.subscribe(change => {
console.log(change);
});
}
...
Using valueChanges would be a correct approach for you.
I assume you are using setValue or patchValue to set the prefilled values. Both these take as optional emitEvent property. If you set it to false, it will not fire valueChanges. So.... when you set the prefill values, use that:
this.form.setValue({ test: "test" }, { emitEvent: false });
This action will now not trigger valueChanges.
all FormControl objects have methods such as markAsUntouched() or markAsPristine() so, in line with what #uminder has indicated, to set the entire form as pristine after either the trigger of ngAfterViewInit or directly after your form has initialized you could simply traverse all FormControl objects and set them as 'pristine'? Any changes thereafter by the user will -by definition- trigger the valueChanges of either the form or the control?
below a recursive method for setting all FormControl item as touched (to trigger validation settings) you can use the same for control.markAsUntouched or control.markAsPristine ?
export function markFormGroupTouched(formGroup: FormGroup): void {
const fa = new FormArray([]).constructor.name;
Object.values(formGroup.controls).forEach((control: any, i) => {
if (control.constructor.name === fa) {
control.controls.forEach((ctrl: any) => markFormGroupTouched(ctrl));
}
else{
control.markAsTouched();
}
});
}
The functions is recursive for FormArray so it will traverse the entire form.controls tree.
NOTE: the const fa = new FormArray([]).constructor.name; is to avoid
problems on minification of your code. Because typeof FormArray
comes back as FormGroup you will have to compare on the control
constructor, but the factory for the FormArray gets renamed on
minification, therefore you cannot hardcode ..=="FormArray" because that will not be the constructor name when minified. This method allows for that contingency.

Angular 5 - Auto-reload the HTML page of the specific component at some fixed intervals

The manual solutions for Auto Reloading the HTML page of a specific component:
Either by navigating to the HTML page on click.
Or calling the ngOnInit() of that component on click.
I am doing it manually using a click event from the HTML code as follows:
HTML Code: app.component.html
<button (click) = reloadPage()>
TS Code: app.component.ts
reloadPage() {
// Solution 1:
this.router.navigate('localhost:4200/new');
// Solution 2:
this.ngOnInit();
}
But I need to achieve this automatically. I hope I am clear. The page should auto-reload after some specific interval and call the ngOnInit() on each interval.
Add correct call to setInterval anywhere in your call:
setInterval(() => reloadPage(), 150000); and inside the method reloadPage put the same logic you have for the button.
An example:
Just put the reloadPage function call inside the constructor:
export class SomeComponent {
constructor() {
setInterval(() => this.reloadPage(), 150000);
}
reloadPage() {
// anything your button doeas
}
}
also note, that correct call of setInterval would be:
setInterval(() => this.reloadPage(), 150000);
Note: My answer just fixes the code you presented. But it seems there is some bigger logical misunderstanding of "reloading page" in angular and using ngOnInit

After Input goes Invalid in HTML5 set error message and prevent default error message from kendo in a grid

I stuck with the inline validation in the kendo grid.
I don't want to validate after losing focus. I want to validate immediately after typing. So I start using the HTML validator. It works pretty well but the problem is I cant answer these two questions:
which event set the input from valid to invalid.
which event displays the error message.
My Current work: https://dojo.telerik.com/OSONo/56
which event set the input from valid to invalid.
...
which event displays the error message.
Just run your kendoValidator with validator.validate();
The error messages are also set with validate().
Something like this should work:
$(document).on('input propertychange', function() {
validator.validate();
});
The warning seems to be hidden behind some elements, so you can also add the folowing errorTemplate to your kendoValidator:
errorTemplate: '<div class="k-widget k-tooltip k-tooltip-validation" style="margin: 0.5em; display: block;"><span class="k-icon k-i-warning"></span>#=message#<div class="k-callout k-callout-n"></div></div>'
And the whole solution:
https://dojo.telerik.com/OSONo/66
Solved my Problem on my Own. I will edit the post so you can see what i mean but first i just give the dojo projcet.
https://dojo.telerik.com/OSONo/64
my edit:
I am sorry for my previous anwser, i just want to give him my solution i mention in my comment.
In my solution i created an event listener, how listen to all input elements. When something has changed it, saves the current cursor position (its import for ie support) and after this it trigger my "change" event. The "change" event check if it is valid or invalid. If it is invalid the kendo validator shows imidently the error-message (not as default by a blur event).
var ValidierungCheckClass = (function () {
return {
AllDOMElements: function () {
$('body').on('input', function () {
var myActiveElement = $(':focus');
if ((myActiveElement) && (myActiveElement.context.activeElement.nodeName.toLowerCase() !== "body")) {
var myActiveDOMElement = myActiveElement[0],
start = myActiveDOMElement.selectionStart, //just for IE Support
end = myActiveDOMElement.selectionEnd; //just for IE Support
myActiveElement.trigger("change");
myActiveDOMElement.setSelectionRange(start, end); //just for IE Support
}
})
}
}
});
The change event is allready created from kendo so you dont have to write your own.
At least you have to call the method when creating the website.
<script>
ValidierungCheckClass().AllDOMElements();
</script>
This is my Solution to my problem.
best regards.

Angular 4 Execute Function when html fully loaded

I have a problem with asynchronous HTTP calls in Angular 4 using typescript/components... I create an array of objects, and in the HTML I have checkboxes next to the objects. Now I want certain objects to be checked, by executing a function in angular. However when I do
(document.getElementById(id) as HTMLInputElement).checked = true;
In my component.ts.
It can't find the element however when I do the same code in a function that executes when you push a button it works. So the problem is that the HTML is not fully loaded when I execute the function. How can I make sure the HTML is fully loaded?
Yeah You shouldn't be manipulating the DOM.
Tag your HTML element in the html using hash.
<input ... #inputname />
Retrieved in the ts controller component.
#ViewChild('inputname') theinput;
Check after view init. ngAfterViewInit if it is checked
ngAfterViewInit() {
...
(this.form as HTMLInputElement).checked
...
}
Consider this as the last option since I wouldn't recommend direct DOM manipulation in Angular. But if you are still facing the issue, use can use my solution as a work around.
In constructor ,
let interval = setInterval(() => {
let flag = self.checkFunction();
if (flag)
clearInterval(interval);
}, 100)
Now create the function
checkFunction() {
if(document.getElementById(id)){
(document.getElementById(id) as HTMLInputElement).checked = true;
return true;
}
return false;
}

In a <form onSubmit={}>, is the event data automatically passed?

I'm following along with a React tutorial on Thinkster and noticed that the form has an onSubmit tag, which automatically passes on the event to be intercepted.
I did some quick research and couldn't seem to find any indication that this is normally what happens on an onSubmit. Am I missing something here? I just found it rather curious.
From CommentInput.js
...
this.createComment = ev => {
ev.preventDefault();
const payload = agent.Comments.create(this.props.slug, {body: this.state.body});
this.setState({body: ''});
this.props.onSubmit(payload);
};
}
render() {
return (
<form className="card comment-form" onSubmit={this.createComment}>
...
}
Thanks!
inside constructor() method declare
this.createComment= this.createComment.bind(this); to remove auto submiting if it is the case of your question. But if you are asking that, are the data passed when you click submit button, then yes. They should be sent.