Angular FormControl on <input> displays [object Object] - html

Using Angular 7.
Have an <input> tag like the following:
<input id="foo" type="text" class="bar" [formControlName]="'product'"
autocomplete="off [ngModel]="formGroup.controls.product.value" [readOnly]="true"/>
Eventually, myControl.setValue('some string'); is called.
The result is the <input> element displays [object Object].
I am trying to display the string from the setValue() call.
What am I doing incorrectly?

try like this you don't need to use [ngModel] you set product control directly
<div [formGroup]="form">
<input id="foo" type="text" class="bar" formControlName="product"
autocomplete="off" [readOnly]="true"/>
<button (click)="update()">Update</button>
</div>
component
form:FormGroup;
constructor(fb:FormBuilder) {
this.form = fb.group({
product:'init data'
});
}
update(){
this.form.get('product').setValue('Updated...')
}
demo 🚀
incase you just have single form control you have to use [formControl] directive
<input id="foo" type="text" class="bar" [formControl]="myControl"
autocomplete="off" [readOnly]="true"/>
<button (click)="update()">Update</button>
component
myControl:FormControl
constructor() {
this.myControl = new FormControl('init data')
}
update(){
this.myControl.setValue('Updated...')
}
demo 🌟

Remove the [ngModel] section of the input, that isn't needed if you're using formControlName as well.
When setting the value, we can't see how you're specifying myControl but the equivalent code would be:
this.formGroup.controls['product'].setValue('my string');

Related

Is there a way to enable the autocomplete for angular reactive form?

I want to set on the autocomplete attribute for an angular form but it doesn't work as expected. It remembers only the values that I submitted only the first time and I would like to remember and suggest all the values no matter how many times I click on submit button.
Here is the stackblitz with the code that I tried.
<form
autocomplete="on"
(ngSubmit)="onSubmit()"
name="filtersForm"
[formGroup]="formGroup1"
>
<div>
<label>First Name</label>
<input
id="firstName"
name="firstName"
autocomplete="on"
formControlName="firstName"
/>
</div>
<div>
<label>Last Name</label>
<input
id="firstName"
name="lastName"
autocomplete="on"
formControlName="lastName"
/>
</div>
<button type="submit">Submit</button>
</form>
Here are the details about the autocomplete attribute that I used.
In Firefox, the autocomplete is working after several clicks on Submit button, the problem is in Chrome and Edge.
Is there a way to make the autocomplete to work for inputs inside the angular form?
I think, I have found a workaround, that only works with Template Driven Form.
TLDR;
What I have discovered while looking after this issue.
On first form submit autofill remember only first time submission values
form submit POST method can remember all values.
Yes, by looking at above, it clearly seems like 2nd way is suitable for us. But why would anybody do form POST for submitting form to BE. There should be better way to tackle this. Otherwise we would have to think of handling PostBack 😃😃 (FW like .Net does it by keeping hidden input's).
Don't worry we can do some workaround here to avoid form POST. I found an answer for handling POST call without page refresh.
Working JSBin with plain HTML and JS
AutoCompleteSaveForm = function(form){
var iframe = document.createElement('iframe');
iframe.name = 'uniqu_asdfaf';
iframe.style.cssText = 'position:absolute; height:1px; top:-100px; left:-100px';
document.body.appendChild(iframe);
var oldTarget = form.target;
var oldAction = form.action;
form.target = 'uniqu_asdfaf';
form.action = '/favicon.ico';
form.submit();
setTimeout(function(){
form.target = oldTarget;
form.action = oldAction;
document.body.removeChild(iframe);
});
}
Basically we change set few things on form attribute.
target="iframe_name" - Connects to iFrame to avoid page refresh.
method="POST" - POST call
url="/favicon" - API url to favicon (lightweight call)
In angular you can create an directive for the same.
import {
Directive, ElementRef, EventEmitter,
HostBinding, HostListener, Input, Output,
} from '#angular/core';
#Directive({
selector: '[postForm]',
})
export class PostFormDirective {
#HostBinding('method') method = 'POST';
#HostListener('submit', ['$event'])
submit($event) {
$event.preventDefault();
this.autoCompleteSaveForm(this.el.nativeElement);
}
constructor(private el: ElementRef) {}
autoCompleteSaveForm(form) {
let iframe = document.querySelector('iframe');
if (!iframe) {
iframe = document.createElement('iframe');
iframe.style.display = 'none';
}
iframe.name = 'uniqu_asdfaf';
document.body.appendChild(iframe);
var oldTarget = form.target;
var oldAction = form.action;
form.target = 'uniqu_asdfaf';
form.action = '/favicon.ico'; // dummy action
form.submit();
setTimeout(() => {
// set back the oldTarget and oldAction
form.target = oldTarget;
form.action = oldAction;
// after form submit
this.onSubmit.emit();
});
}
#Output() onSubmit = new EventEmitter();
ngOnDestroy() {
let iframe = document.querySelector('iframe');
if (iframe) {
document.body.removeChild(iframe);
}
}
}
Okay, so far everything went well. Then I started integrating this in formGroup(Model Driven Form), somehow it didn't worked. It does not store value next time these fields.
<form (ngSubmit)="onSubmit()" [formGroup]="formGroup1" autocomplete="on">
<div>
<label>First Name</label>
<input id="firstName" name="firstName" formControlName="firstName" />
</div>
<div>
<label>Last Name</label>
<input id="lastName" name="lastName" formControlName="lastName" />
</div>
<button>Submit</button>
</form>
Later I tried the same with Template Driven Form. It just worked like a charm! I did not went into the depth why it didn't work for Model Driven Form (perhaps that investigation could eat more time).
<form #form1="ngForm" ngForm postForm (onSubmit)="onSubmit(form1)">
<ng-container [ngModelGroup]="userForm">
<div>
<label>First Name</label>
<input name="firstName" [(ngModel)]="userForm.firstName" />
</div>
<div>
<label>Last Name</label>
<input name="lastName" [(ngModel)]="userForm.lastName" />
</div>
</ng-container>
<button>Submit</button>
</form>
Yeah, I just said in the begining it works only with Template Driven Form. So you would have to switch to Template. And one more important thing to note, you may think of creating dummy POST api call, that can be lightweight rather than hitting favicon.
Stackblitz
autocomplete attribute works only with submitted values. It has nothing to do with Angular.
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
If you need some custom behavior then you are better off creating your own component to autocomplete user's input, this way you can use some default values, add more of them on blur etc.
You just need to remove autocomplete="on" in input tag. With chrome, we only add attribute autocomplete="on" in form element and it will be cached all value that user input into input text. Result will be like this:
<form
autocomplete="on"
(ngSubmit)="onSubmit()"
name="filtersForm"
[formGroup]="formGroup1"
>
<div>
<label>First Name</label>
<input
id="firstName"
name="firstName"
formControlName="firstName"
/>
</div>
<div>
<label>Last Name</label>
<input
id="firstName"
name="lastName"
formControlName="lastName"
/>
</div>
<button type="submit">Submit</button>
</form>
You have to create an array with your desired options which should be displayed as autocomplete. You can have a look here https://material.angular.io/components/autocomplete/examples, there are multiple examples which should help you. Even if you're not using Angular Material, the logic would be the same

Passing interpolation value through ngModel

<input [(ngModel)]="newVariablesAttribute.Steps"
class="form-control"
type="text" readonly
name="{{newVariablesAttribute.Steps}}">
{{stepname}}
I want to pass stepname (which I am able to show in the frontend using interpolation) using ngModel.
But It is not working.
Didn't find any issue with your code. Steps might be undefined
Component
export class SomeComponent {
newVariablesAttribute = {
Steps: 'step'
};
stepname = 'abc';
}
html:
<input [(ngModel)]="newVariablesAttribute.Steps" class="form-control" type="text" readonly name="{{newVariablesAttribute.Steps}}">{{stepname}}
O/P
Since stepname is getting rendered in the UI, you can pass it to the ngModel directly like this right -
<input [(ngModel)]="stepname"
class="form-control"
type="text" readonly
name="{{newVariablesAttribute.Steps}}">
{{stepname}}
(I guess newVariablesAttribute.Steps are some array of objects. )

HTML "placeholder" attribute successfully fills form input, but "value" attribute doesn't (using Angular 2+)

I have an Angular UI where clicking an edit button transforms the member name heading into a form where you can edit and update the name. I want the form to be pre-filled with the existing name.
However, the problem occurs with the value="{{member.name}}" line in the code snippet below. The form simply appears blank. Why?
Using placeholder="{{member.name}}"sets the value correctly, but placeholder isn't the behavior I want.
<h4 *ngIf="!editMode">{{member.name}}</h4>
<form *ngIf="editMode" #f="ngForm" (ngSubmit)="onEdit(f)">
<input type="text" value="{{member.name}}" ngModel name="name">
<button type="submit">Update</button>
</form>
To set the value of an input field use [ngModel] directive and put the variable as parameter. Usually one wants a "two way binding", that's why the [] and () are mixed.
<form *ngIf="editMode" #f="ngForm" (ngSubmit)="onEdit(f)">
<input type="text" [(ngModel)]="member.name" name="name">
<button type="submit">Update</button>
</form>
It's possible to only use [] to only "set" the value of the input. See the following SO-question for details:
Difference between [(ngModel)] and [ngModel] for binding state to property?
Source: https://angular.io/api/forms/NgModel
I came up to this answer looking for set the placeholder with a variable but didn't work with the solution above.
I solved with property binding, using [placeholder]="myVar" with this helpfull link
<form *ngIf="editMode" #f="ngForm" (ngSubmit)="onEdit(f)">
<input type="text" [(ngModel)]="member.name" name="name" [placeholder]="myVar">
<button type="submit">Update</button>
</form>
And the Angular component to set placeholder text:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-input-placeholder',
templateUrl: './input-placeholder.component.html',
styleUrls: ['./input-placeholder.component.scss']
})
export class PlaceholderComponent {
myVar = 'Please enter your name here';
}

how populate a input hidden with vuejs 2?

i want to know how pass the value that return this function to the input hidden i try with the directive v-input but doesn't work, how can i found the solution to this?.
here is the computed function:
computed:{
currentDate: function (){
this.date = moment().format("D-MM-YYYY");
return this.date;
}
thats the view:
<input type="hidden" name="customfield" class="form-control" v-model="fillProfile.customfield">
If you expect currentDate to be the value of your hidden field, you should bind it like so:
<input type="hidden" name="customfield" class="form-control" :value="currentDate">
v-model is a two-way binding, and hidden inputs are not interactive, so there is no point in using it.

how to access element in directive?

I have a html page in which there is a directive(child html) inside as below. I want to do input validation of input1 and input2 in directive(child html) for the button in parent html, but I don't know how I can access the input1 and input2 in child (directive). I would like to know what is the right way to access input1 and input2? Thanks in advance!!
Parent html:
<div>
<child></child>
<button name="myButton" ng-disabled="????.myForm.input1.$invalid"><button>
</div>
Directive: child
<form name="myForm">
<input name="input1" required/>
<input name="input2" required/>
</form>
Try this:
Parent controller:
vm.myForm = {};
Parent Html:
<child my-form="vm.myForm"></child>
<button name="myButton" ng-disabled="vm.myForm.input1.$invalid"><button>
Child directive:
scope: {
myForm: "="
}
Child HTML:
<form name="myForm">
<input name="input1" required/>
<input name="input2" required/>
</form>
You can $emit event to your parent controller and pass needed data.
Directive:
$scope.$emit('yourCustomEvent', 'Data to send');
And catch the event in you parent controller.
Parent controller:
$scope.$on('yourCustomEvent', function (event, data) {
console.log(data); // will print "Data to send"
});
And in your case I advice you to include the button in your directive, it will be much easier to work with it.