I have a very basic form consisting of a input field and a button. I am trying to use angular2 validators to show an error message when anything other than numbers are entered into the input field and also to disable the submit button when the input field is invalid or empty. For some reason the error message shows regardless of what gets entered... Any idea what i'm doing wrong?
my code:
app.component.html:
<div class="row">
<div class="col-md-4 col-md-push-4">
<form [formGroup]="barcodeForm" role="form" (ngSubmit)="submitBarcode(barcode)" >
<div class="form-group">
<input type="number" class="form-control" id="barcode" placeholder="Enter Barcode" [formControl]="barcodeForm.controls['barcode']" [(ngModel)]="barcode" name="barcode" #focusInput>
<div [hidden]="barcode.valid || barcode.pristine" class="alert alert-danger">A barcode can only consist of numbers (0-9)...</div>
</div>
<button class="btn btn-submit btn-block" [disabled]="!(barcode.valid) || barcode.pristine">Submit</button>
</form>
</div>
</div>
part of app.component.ts:
import { Component, ViewChild, ElementRef, AfterViewInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { RestService } from "./services/rest.service";
import { ProductModel } from "./models/product.model";
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
#ViewChild('focusInput') focusInput: ElementRef;
barcode: string;
barcodeForm: FormGroup;
product: ProductModel;
constructor(fb: FormBuilder, private restService: RestService){
this.barcodeForm = fb.group({
'barcode':['', [Validators.required, Validators.pattern("[0-9]+")]]
});
}
In angular2 there are two types of forms: template driven and model driven.
Model driven is defining the form's structure in code and binding inputs to its controls (via formControl and formGroup).
And template driven is using ngModel and defining validators on the template.
I can see most of your code is targeted for model driven which in my opinion is better anyway, but you still have ngModel on your input, do you need it for something?
I dont see you using it anywhere other than barcode.valid which shouldn't work since barcode is merely a string. You want to bind the disabled property to barcodeForms.controls['barcode'].valid instead and then remove the use of ngModel. It might conflict with formControl since both of them initialize a FormControl instance for that element.
Related
I'm working on a little login project, and there is one thing that doesn't work for me. I want to do two way binding for my userID and password, and it just doesn't work. (I'm working in the login component, so not in the app component).
HTML:
<div class="loginstuff">
<label>Log in a.u.b.</label><br>
<input type="text" [(ngModel)]="userID" /><br>
<div>user: {{ userID }}</div>
<input type="text" [(ngModel)]="password" /><br>
<div>pw: {{ password }}</div>
<button (click)="Login();">Login</button><br>
<input type="radio" name="radiobutton"
[(ngModel)]="selectedRole" (focus)="RoleSelection('User')" checked/>User
<input type="radio" name="radiobutton"
[(ngModel)]="selectedRole" (focus)="RoleSelection('Admin')"/>Admin<br>
<div>your selected role is {{selectedRole}}</div>
<a [routerLink]="['/registration']" (click)="GoToRegistration()">Registreren</a>
</div>
<router-outlet></router-outlet>
TS
import { Component, ElementRef, Input, OnInit, ViewChild, NgModule } from '#angular/core';
import {NgForm} from '#angular/forms';
import { FormsModule } from '#angular/forms';
import { Router } from '#angular/router';
import {MatRadioModule} from '#angular/material/radio';
import { stringify } from 'querystring';
import {BrowserModule} from '#angular/platform-browser';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit(): void {
}
selectedRole='User';
userID = '';
password = '';
registration = '';
RoleSelection(role){
this.selectedRole = role;
}
Login(){
if(this.selectedRole === 'User'){
console.log(this.userID, this.password);
}
else{
this.router.navigate(['/adminpage'])
}
}
}
And this is what it looks like:
Login project
I added the user: and pw: to check if the two way binding is working. Whatever I type in the userID and password fields is supposed to show behind the user: and pw:, but it doesn't. As you can see, I did the two way binding with my radio buttons and it works (on the image you can see it shows "you selected role is User, User comes from a variable. PS: I know the variable is already bound to the value "User" but that's just the default value. When I click on the admin radio button it changes to "Admin" so I know it works). I have no idea what I'm doing wrong, since I do the exact same thing with the radio buttons and they work. Any ideas?
Use FormGroup, it supports the two way binding for forms and much more, like validation. Pass a FormGroup to your <div class="loginstuff" [formGroup]="yourFormGroup">. And for your inputs:
<input type="text" formControlName="login"/>.
And in your .ts class:
const form = new FormGroup({
login: new FormControl(),
password: new FormControl()
});
I want to affect the value of this input to a variable 'numToAdd' which is in my component and then add 1 to the variable 'numToAdd', but I can't pass the value of the html input to my component variable 'numToAdd'. How to bind my html input to a variable in the component ?
my html code
<input type="number" id=num class=num>
my component
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-afficher-projets',
templateUrl: './afficher-projets.component.html',
styleUrls: ['./afficher-projets.component.css']
})
export class AfficherProjetsComponent implements OnInit {
ngOnInit(): void {}
numToAdd: number;
constructor() { }
add: void {
this.numToAdd++;
}
}
Two-way binding a primary functionality of angular. Use the ngModel directive to bind input to variables.
<input type="number" id="num" class="num" [(ngModel)]="numToAdd">
The above code binds the variable numToAdd with the input. Find more details here
I need to create a button for uploading a file in my form. I am using tag in my html but it is throwing an error : Can't bind to 'control' since it isn't a known property of 'app-contorl-message'.
Here is my html code -
<div class="col-lg-6">
<div class="form-group">
<div class="custom-file">
<input *ngIf="mode == 'CREATE'" type="file" (change)="onFileSelect($event)"
accept=".jpg,.jpeg,.png"/>
<app-contorl-message [control]="form.get('file')"></app-contorl-message>
</div>
</div>
</div>
here is def of onSelect($event) :
onFileSelect(event) {
this.form.get('file').setValue(event.srcElement.files);
this.fileData = event.srcElement.files;
console.log(event);
}
Thanks in advnace!
In your AppControlMessageComponent you need to create an #Input() named control. To learn more about inputs and output, visit: https://angular.io/guide/inputs-outputs
app-control-message.component.ts
import { Component, OnInit, Input } from "#angular/core";
#Component({
selector: "app-app-control-message",
templateUrl: "./app-control-message.component.html",
styleUrls: ["./app-control-message.component.css"]
})
export class AppControlMessageComponent implements OnInit {
#Input() control; // Input whose value parent component will provide
constructor() {}
ngOnInit() {}
}
I want to prevent users to enter html injection to textbox. I have researched some example but they are generally about allowing html tags through pipes and saying angular automatically sanitizes html tags. But in my example when I enter <script>alert('blabla')</script> to text box, it is accepted and registered to db like this..
How can I prevent it ?
My template code is:
<div fxLayout="row">
<mat-form-field fxFlex="20">
<input matInput name="label" [(ngModel)]="product.label" placeholder="Label"
required>
</mat-form-field>
</div>
and my ts file is:
import { Product } from '../../../';
#Component({
selector: '....',
templateUrl: '....',
styleUrls: ['....']
})
export class ProductEditComponent implements OnInit {
product: Product = <Product>{};
constructor(some services etc.) {
}
ngOnInit() {
//some code
}
Note again: I want to prevent entering html script injection, not allowing it with bypass or pipe...
you could use DomSanitizer for that
import { DomSanitizer } from "#angular/platform-browser"
import { SecurityContext } from "#angular/core";
constructor(private sanit:DomSanitizer){
var dom = this.sanitizer.sanitize(SecurityContext.HTML, "<script> alert('HELLO'); </script>");
console.log(dom);
}
if it returns null, then it was an issue with html,else it returns passed html
I have created a custom control directive as "my-text-box", inside this directive I am using html control <input>, I need to pass values from my custom control to html input control. In angular1 simply I am using like <my-text-box id="1" name="Box 1"> using my custom attributes of scope variables in directive, i assigned the values to html control like <input type="text" id="{{id}}" name={{name}} > how can i use this scenario in angular 2.
Here is my sample code:
AppComponent.ts
import {Component} from '#angular/core';
import {TextBoxComponent} from './TextBoxComponentDirective';
#Component({
selector: 'my-app',
template: '<h1>{{title}}</h1> <my-text-box id="66" name="MyText1"></my-text-box>',
directives:[TextBoxComponent]
})
export class AppComponent {
title="Sample TextBox";
}
TextBoxComponentDirective.ts
import {Component,Input,Directive} from '#angular/core';
#Component({
selector:'my-text-box',
templateUrl: './TextBoxTemplate.html',
})
export class TextBoxComponent {
#Input() id;
}
TextBoxTemplate.html
<input type="text" [name]="name" [id]="id"/>
You can use #Input() for this:
#Component({
selector: 'my-text-box',
template: `
<input type="text" [id]="id" [name]="name" >
`
})
export class MyTextBoxComponent {
#Input() id;
#Input() name;
}
In your parent component you now can use it like so:
<my-text-box id="1" name="Box 1">
Or if you need to bind to variables:
<my-text-box [id]="someId" [name]="theBoxName">
Working Plunker for example usage