angular 5 form with form builder - forms

I am trying to implement a form in Angular5. But there occurs a error in the console which states 'formGroup needs to have an instance of FormGroup'
This is the HTML code:
<form [formGroup]="userInfo" (ngSubmit)="onSubmit()" novalidate>
<div class="input-section">
<div class="form-group filled-form">
<label for="businessName">What positions are you hiring for?</label>
<input class="form-control myInputStyle" type="text" id="enterEmail"
formControlName="businessname" required>
<div [hidden]="userInfo.controls['businessname'].valid ||
userInfo.controls['businessname'].pristine" class="inline-error">
Please enter a Business name!
</div>
</div>
</div>
</form>
Here is the ts code :
export class HwaPreviewComponent implements OnInit {
public userInfo:FormGroup;
constructor(private router: Router) { }
ngOnInit() {
}
onSubmit() {
if (this.userInfo.valid) {
console.log("Form Submitted!");
}
}

public userInfo:FormGroup; - adding this in the .ts file helped

Related

How to implement validation rules for elements from a partial view

We are developing a .net core 3.1 MVC application (actual with MVVMC).
We have implemented custom validation attributes. And want them to be checked on server and on client side.
The view is a standard view, however the user has the possibility to add multiple partial views to the standard view (via a button).
In the partial view we were not able to use the 'asp-for' tag helper within the input fields, because one can have several times the same item added, and we need to be able to create a list in the ViewModel out of those additional partial views selected. That's why we tried to build the tags by ourselfes.
Once a partial view has been requested via ajax we are calling the validator again. Server validation works, client validation only works for those inputs, which are on the main view, not for the inputs on the partial views. However, after refreshing or when the server sends the user back after a validation error, client validation starts working (because site is completely refreshed and jquery validation takes input fields of partial views into account).
Please find the code below:
Implementation of validation attribute
public class AllowedExtensionsAttribute: ValidationAttribute, IClientModelValidator
{
private readonly List<string> _extensions = new List<string>();
public AllowedExtensionsAttribute(string extensions)
{
_extensions.Add(extensions);
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (value is IFormFile file)
{
var extension = Path.GetExtension(file.FileName);
if (!_extensions.Contains(extension.ToLower()))
{
return new ValidationResult(ErrorMessage);
}
}
return ValidationResult.Success;
}
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-extension", ErrorMessage);
}
}
MainViewModel
[AllowedExtensions(".pdf", ErrorMessage = "This data type is not allowed!")]
public IFormFile PdfDocumentOne { get; set; }
PartialViewModel
[AllowedExtensions(".pdf", ErrorMessage = "This data type is not allowed!")]
public IFormFile PdfDocumentTwo { get; set; }
Main View
<form method="post" asp-controller="Home" asp-action="MainView" enctype="multipart/form-data">
<div class="form-group top-buffer">
<div class="row">
<div class="col-2">
<label asp-for="PdfDocumentOne" class="control-label"></label>
</div>
<div class="col-3">
<input asp-for="PdfDocumentOne" class="form-control-file" accept="application/pdf" />
<span asp-validation-for="PdfDocumentOne" class="text-danger"></span>
</div>
</div>
</div>
<div id="container">
<div id="containerFull" class="form-group">
<div class="row">
<div class="col-2">
<label class="control-label">...</label>
</div>
<div class="col-10">
<div id="containerPartialView">
</div>
</div>
</div>
<div class="row">
<div class="col-2">
</div>
<div class="col-3">
<button id="AddPartialView" type="button" class="form-control">...</button>
</div>
</div>
</div>
</div>
...
<div class="form-group top-buffer">
<div class="row">
<div class="col-2">
<input type="submit" value="Submit" class="form-control" id="checkBtn" />
</div>
</div>
</div>
</form>
Partial View
<input id="Lists[#Model.ViewId].ViewId" name="Lists[#Model.ViewId].ViewId" class="partialViewModel" type="hidden" value="#Model.ViewId" />
<div id="Lists[#Model.ViewId].MainContainer" class="partialView">
<div class="form-group">
<div>
<div class="col-2">
<label asp-for="PdfDocumentTwo" class="control-label"></label>
</div>
<div class="col-3">
<input name="Lists[#Model.ViewId].PdfDocumentTwo" id="Lists[#Model.ViewId].PdfDocumentTwo " type="file" class="form-control-file" accept="application/pdf"
data-val="true" data-val-extension="This data type is not allowed!"/>
<span class="text-danger field-validation-valid" data-valmsg-for="Lists[#Model.ViewId].PdfDocumentTwo" data-valmsg-replace="true"></span>
</div>
</div>
</div>
...
</div>
Javascript
function AddPartialView() {
var i = $(".partialView").length;
$.ajax({
url: '/Home/AddPartialView?index=' + i,
success: function (data) {
$('#containerPartialView').append(data);
$().rules('remove','extension');
jQuery.validator.unobtrusive.adapters.addBool("extension");
},
error: function (a, b, c) {
console.log(a, b, c);
}
});
}
$('#AddPartialView').click(function () {
AddPartialView();
});
jQuery.validator.addMethod("extension",
function (value, element, param) {
var extension = value.split('.').pop().toLowerCase();
if ($.inArray(extension, ['pdf']) == -1) {
return false;
}
return true;
});
jQuery.validator.unobtrusive.adapters.addBool("extension");
HomeController
[HttpPost]
public IActionResult MainView(MainViewModel vm)
{
if (vm == null)
{
return RedirectToAction("Index");
}
DatabaseHelper.GetMainViewModel(vm);
if (!ModelState.IsValid)
{
#ViewData["StatusMessageNegative"] = "The entered data is not valid. Please scroll down to correct your data.";
return View(vm);
}
return RedirectToAction("UploadDocument", new { Id = vm.Id});
}
[HttpGet]
public ActionResult AddPartialView(int index)
{
PartialViewModel pvm = DatabaseHelper.GetPartialViewModel(index);
return PartialView("Partial", pvm);
}
After searching in the internet we found the following argument (data-ajax="true"). However, we don't know where to place it or how to use it correctly.
Have you tried re-apply validation after loading your partial view?
$.ajax({
url: '/Home/AddPartialView?index=' + i,
success: function (data) {
$('#containerPartialView').append(data);
$().rules('remove','extension');
jQuery.validator.unobtrusive.adapters.addBool("extension");
},
error: function (a, b, c) {
console.log(a, b, c);
}
}).then(function () {
$("form").each(function () { $.data($(this)[0], 'validator', false); });
$.validator.unobtrusive.parse("form");
});

Why validation is not working?

corporate.html
<form #f="ngForm" name="corporateProfileForm" ng-submit="corporateFrmSave(objDS, objDSCurrency)" novalidate="">
<div class="row form-group">
<div class="col-md-12" >
<input type="text" *ngIf="formData" [(ngModel)]="formData.Corporate_Id" id="corpid" title="Corporate ID" tab-index="1" name="corpid" maxlength="20" #corpid="ngModel" required/>
<label for="corp"><b>Corporate ID</b></label>
<div *ngIf="corpid.invalid && (corpid.dirty || corpid.touched)" class="alert alert-danger">
<div *ngIf="corpid.errors.required">
Name is required.
</div>
<div *ngIf="ncorpidame.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="corpid.errors.forbiddenName">
Name cannot be Bob.
</div>
</div>
</div>
</div>
</form>
Iam getting error message as
ERROR TypeError: Cannot read property 'invalid' of undefined
Make sure you define your variable with this structure:
TS file
export class ContactComponent implements OnInit {
myform: any;
corpid: FormControl;
constructor() {
}
ngOnInit() {
this.createFormControls();
this.createForm();
}
createFormControls() {
this.corpid= new FormControl('', Validators.required);
}
createForm() {
this.myform = new FormGroup({
corpid: this.corpid,
});
}
HTML file
<div class="md-form form-sm form-group"
[ngClass]="{
'invalid': corpid.invalid && (corpid.dirty || corpid.touched),
'valid': corpid.valid && (corpid.dirty || corpid.touched)
}">
<i class="fa fa-user prefix"></i>
<input
type="text" id="corpid" class="form-control"
required
[formControlName]="'corpid'">
<label for="corpid" class="">Your corpid</label>
</div>
<div class="form-control-feedback"
*ngIf="corpid.errors && (corpid.dirty || corpid.touched)">
<p *ngIf="corpid.errors.required">corpid is required</p>
</div>
It's hard to tell because issue is not in your HTML snipped but in .ts file.
I hope my Code will be helpfull
The issue is with the *ngIf, so when that condition is checked, Angular renders the rest of the template, and while the small fraction of time while *ngIf is being evaluated, your template reference variable corpid does not exist, so it will throw an error when trying to check the validation intially.
Wrap the input field with the validation div's inside the *ngIf instead of applying it only on the input field.
<div class="row form-group" *ngIf="formData">
<input [(ngModel)]="formData.Corporate_Id" id="corpid" ... >
<!-- more code here... -->
</div>
DEMO

Angular 4 form validation

How to validate a form in angular 4 by clicking on external link (ie out side from tag). If the form is valid do some actions with form data else show validation messages. If form is valid I don't want to submit the form just need to get the form field values.
This is my answer post to another question:
The easy way is to use reactive forms, like this:
Code:
import {ReactiveForm, FormBuilder, Validators} from '#angular/form';
export class SignupFormComponent implements OnInit {
userForm: FormGroup;
firstName: string;
constructor(private _formBuilder:FormBuilder){}
ngOnInit() {
this.userForm = this._formBuilder.group({
'firstName': ['',[Validators.required,Validators.minLength(5)]]
});
}
onSubmit() {
console.log(this.firstName);
}
}
HTML:
<form [formGroup]="userForm" (ngSubmit)="onSubmit()" name="userForm">
<div class="form-group">
<label>First Name</label>
<input type="text" [(ngModel)]="firstName" class="form-control" formControlName="firstName">
<p *ngIf="userForm.controls.firstName.invalid && (userForm.controls.firstName.dirty || userForm.controls.firstName.touched)"> Error message </p>
</div>
<button type="submit" class="btn btn-primary" [disabled]="userForm.invalid">Submit </button>
</form>

Angular 2 Template Driven Forms - Array Input Elements

I have been struggling for 1 and half day and still couldn't find any solution to the problem. I am working on simple form which has select and checkboxes element.When I try submitting the form I do not get the values of select and checkboxes but rather I just get true in the console.
I am working on template driven form.
<form (ngSubmit)="addSubcontractor(subcontractorForm)" #subcontractorForm="ngForm">
<h5>Type :</h5>
<div class="form-group">
<div *ngFor="let contractor_type of contractor_types;let i = index;" class="pull-left margin-right">
<label htmlFor="{{ contractor_type | lowercase }}">
{{ contractor_type }} :
</label>
<input type="checkbox" name="_contractor_type[{{i}}]" [value]="contractor_type" ngModel>
</div>
<div class="form-group">
<select class="form-control costcodelist" name="_cc_id[]" multiple="true" ngModel>
//When I put ngModel on select I just keep getting error
//TypeError: values.map is not a function
<option *ngFor="let costcode of costcodes" [selected]="costcode.id == -1" [value]="costcode.id">{{ costcode.costcode_description }}</option>
</select>
</div>
</form>
Component Section
export class SubcontractorComponent implements OnInit, OnDestroy {
private contractor_types = ['Subcontractor', 'Supplier', 'Bank', 'Utility'];
constructor(private costcodeService: CostcodeService,
private subcontractorService: SubcontractorService) {
this.subcontractorService.initializeServices();
}
ngOnInit() {
this.costcode_subscription = this.costcodeService.getAll()
.subscribe(
(costcodes) => {
this.costcodes = costcodes;
});
}
addSubcontractor(form: NgForm) {
console.log(form.value);
}
}
When I remove ngModel from select element the code runs fine and When I submit the form I get the following output.
_contractor_type[0]:true
_contractor_type[1]:true
_contractor_type[2]:true
_contractor_type[3]:""
I do not get the checkboxes values as well the selected options from select element.
Your comments and answer will appreciated a lot.
Thanks
Here is a simple selection that i use with my Template driven form.
<form #f="ngForm" (submit)="addOperator(f.valid)" novalidate>
<label>Name</label>
<input [(ngModel)]="operator.name" name="name">
<label >Service</label>
<select #service="ngModel" name="service" [(ngModel)]="operator.service">
<option *ngFor='let service of services' [ngValue]='service'>{{service.name}}</option>
</select>
<label >Enabled</label>
<label>
<input type="checkbox" name="enabled" [(ngModel)]="operator.enabled">
</label>
<button type="submit">Create Operator</button>
</form>
.ts
operator: Operator;
ngOnInit() {
this.operator = <Operator>{}; // // Initialize empty object, type assertion, with this we loose type safety
}
addOperator(isValid: boolean) {
if (isValid) {
this.operatorsService.addOperator(this.operator).then(operator => {
this.goBack();
});
}
}
Also im importing this
import { FormsModule, ReactiveFormsModule } from '#angular/forms';

angular2: how to use input fields in sub components of forms

Look at my plunkr:
http://plnkr.co/edit/hB34VjxP98uz1iAYS7Dw?p=preview
Name is included in myform.form, but Name1 of component inner is not. How do I include Name1 in myform?
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form</h1>
<form #heroForm="ngForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" required
[(ngModel)]="modelname"
name="name" #name="ngModel" >
<div [hidden]="name.valid || name.pristine" class="alert alert-danger">
Name is required
</div>
<inner></inner>
</div>
</form>
{{heroForm.form.value | json}}
</div>
Template of inner.component:
<label for="name">Name1</label>
<input type="text" class="form-control" required
[(ngModel)]="modelname1"
name="name1" #name1="ngModel" >
<div [hidden]="name1.valid || name1.pristine" class="alert alert-danger">
Name1 is required
</div>
See this issue:
https://github.com/angular/angular/issues/9600
I have fixed your code to accomplish your end goal. Now both Name and Name1 are included in the form and values are coming up on the display for you
I have created a fork from your plnkr and fixed your code to support your use case. Please take a look : http://plnkr.co/edit/UHkwJ9?p=preview
inner.component.html is changed as :
<label for="name">Name1</label>
<input type="text" class="form-control" required
[(ngModel)]="modelname1" [formModel]="form" [registerModel]="name2"
name="name2" #name2="ngModel" >
<div [hidden]="name2.valid || name2.pristine" class="alert alert-danger">
Name1 is required
</div>
hero-form.component.ts is changed as :
<inner [form]="heroForm"></inner>
New Directive is added which will register a new control in the existing form reference :
import { Directive, ElementRef, Input, OnInit } from '#angular/core';
import { NgModel, NgForm } from '#angular/forms';
#Directive({
selector: '[formModel]'
})
export class FormModelDirective implements OnInit {
private el: HTMLInputElement;
#Input('formModel') public form: NgForm;
#Input('registerModel') public model: NgModel;
constructor(el: ElementRef) {
this.el = el.nativeElement;
}
ngOnInit() {
if (this.form && this.model) {
this.form.form.addControl(this.model.name, this.model.control);
}
}
}
Output Image :
Output of the plnkr code
Reference : plnkr.co/edit/GG2TVHHHGbAzoOP5mIRr?p=preview