How to Validate Angular 2 FormArray for length and Regex - angular2-forms

app.component.ts
import { Component,OnInit } from '#angular/core';
import {FormControl,FormGroup,FormArray,FormBuilder} from '#angular/forms'
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular 6';
form=new FormGroup({
topics:new FormArray([])
})
addTopic(topic:HTMLInputElement){
(this.form.get('topics') as FormArray).push(new FormControl(topic.value));
topic.value='';
}
}
app.component.html
<form>
<input type="text" class="form-control" (keyup.enter)="this.addTopic(topic)" #topic />
<ul class="list-group">
<li class="list-group-item" *ngFor="let topic of form.get('topics').controls">
{{topic.value}}
</li>
</ul>
</form>
I have created a Multi Input Control using Angular FormArray but how can i Validate the same for Minimum 2 Items(Length=2) and only accept integer values.
How to Add Validators.minlength like Reactive Form / Model Driven Form Approach.
How can i get those items using ngModel?

I hope this helps.
import {
Component,
OnInit
} from '#angular/core';
import {
FormControl,
FormGroup,
FormArray,
FormBuilder
} from '#angular/forms'
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = 'Angular 6';
form = new FormGroup({
topics: new FormArray(this.formBuilder.control(''), [Validators.reqired, Valiadtors.minlength(2)], Validators.Paterrn("^[0-9]*$"))
])
addTopic(topic: HTMLInputElement) {
(this.form.get('topics') as FormArray).push(new FormControl(topic.value));
topic.value = '';
}
}

Related

what is parent stand in selector in angular 2

import { Component, Input } from "#angular/core";
import "./loadingSpinner.component.css!";
#Component({
selector: "loading-spinner-Parent",
template: `
<div *ngIf="showSpinner" class="loader-directive-wrapper">
<div class="loader"></div>
</div>`
})
export class LoadingSpinnerComponent {
#Input() public showSpinner: boolean = false;
}

Programmatically open an N level self nested mat-menu component with matMenuTrigger openMenu

I am trying to make a self nested component that uses Angular Material mat-menu. I have a flyoutcomponent that is a wrapper for flyout-menu-item component, that will have a button as a matMenuTrigger for the nested component that will appear as many levels as the FeatureInput.FeatureChoices dictates. FeatureInput is an object that has FeatureChoices that may or may not contain other featurechoices etc N levels deep. Below code does not compile but it should demonstrate what I am doing. Basically I have flyout menu component as a input to a form and I am trying to load a stored answer on a form rather than select new, which I can do easily using the nested component. The desired behavior is that if the user clicks top matMenuTrigger button to open the top menu that it would expand all child menus to the menu item that matches with the FeatureInput.FeatureValue and sets the menu item _highlighted to true. I am using the menuOpen input parameter and ngChanges successfully to find the match(with I a setTimeout which cannot be right). Basically when I console.log this.trigger it is undefined. Ideally in the ngOnChange to the openMenu I would go through all menus and call openMenu on all the triggers but I cannot get access to the matMenuTrigger with ViewChild as the docs say. I get undefined. *-( All help welcome please and thanks.
Here is flyout template component.
<div>
<buttonmat-button [matMenuTriggerFor]="menu.childMenu"
(onMenuOpen)="onMenuOpen()"
(onMenuClose)="onMenuClose()">
<span [innerHTML]="featureInput.Text"></span>
</button>
<app-flyout-menu-item #menu
[featureChoicesObject]="featureInput.FeatureChoices"></app-flyout-menu-item>
</div>
And here is its .ts
import { Component, OnInit, Input, ViewChild } from '#angular/core';
import { MatMenuTrigger } from '#angular/material';
#Component({
selector: 'app-flyout',
templateUrl: './flyout.component.html',
styleUrls: ['./flyout.component.scss']
})
export class FlyoutComponent implements OnInit {
#Input() featureInput: FeatureInput
constructor() { }
ngOnInit() {
}
onMenuOpen() {
this.menuOpen = true;
}
onMenuClose() {
this.menuOpen = false;
}
}
And here is flyout-menu-item template
<mat-menu #childMenu="matMenu" [overlapTrigger]="false">
<span *ngFor="let featureChoice of featureChoices">
<span>
<button mat-menu-item [matMenuTriggerFor]="menu.childMenu">
<span [innerHTML]="featureChoice.Text"></span>
</button>
<app-flyout-menu-item #menu
[menuOpen]="menuOpen"
[featureInput]="featureInput"
[featureChoicesObject]="featureChoice.FeatureChoices"
(onOptionSelected)="someService.SomeMethod($event)"></app-flyout-menu-item>
</span>
<span *ngIf="!featureChoice.FeatureChoices">
<button mat-menu-item (click)="selectOption(featureChoice.ID)" [innerHTML]="featureChoice.Text" value="{{featureChoice.ID}}"></button>
</span>
</span>
</mat-menu>
And here is its .ts
import { Component, OnInit, Input, Output, ViewChild, EventEmitter, OnChanges, SimpleChanges } from '#angular/core';
import { MatMenuTrigger } from '#angular/material';
import { FeatureChoice } from 'app/model/feature-choice';
import { FeatureInput } from 'app/model/feature-input';
#Component({
selector: 'app-flyout-menu-item',
templateUrl: './flyout-menu-item.component.html',
styleUrls: ['./flyout-menu-item.component.scss']
})
export class FlyoutMenuItemComponent implements OnInit{
#ViewChild('menu') public menu;
#ViewChild('childMenu') public childMenu;
#ViewChild(MatMenuTrigger) public trigger: MatMenuTrigger;
#Input() featureInput: FeatureInput;
#Input() featureChoicesObject: FeatureChoice;
#Output() onOptionSelected: EventEmitter<FeatureInput> = new EventEmitter<FeatureInput>();
constructor(public solutionDataService: SolutionDataService) { }
ngOnInit() {
console.log(this.trigger);
}
ngOnChanges(simpleChanges: SimpleChanges) {
if (simpleChanges.menuOpen && simpleChanges.menuOpen.currentValue) {
setTimeout(() => {
// console.log(this.menu);
const itemsArray = this.childMenu.items.toArray();
for (let x = 0; x < itemsArray.length; x++) {
const menuItem = itemsArray[x];
if (this.featureInput.FeatureValue !== '' && menuItem._elementRef.nativeElement.value === this.featureInput.FeatureValue) {
menuItem._highlighted = true;
}
}
}, 1);
}
}
}
this.menuOpen = true;
Perhaps add menuOpen: boolean = false as an attribute at the top of your FlyoutComponent. I don't know where the value of menuOpen is saved.
the menuOpen property relates to the matMenuTrigger.
here's an example:
<button [ngClass]="{'active-icon': trigger.menuOpen}" type="button" mat-
icon-button #trigger="matMenuTrigger" [matMenuTriggerFor]="help">
<mat-icon></mat-icon>
</button>
<mat-menu #help="matMenu">
<div> textId </div>
</mat-menu>

typescript in ASPNET core 2 with angular - acces html document

I've searched a while for this but I feel like this is one of the basics so no one bothers to explain it anymore...
Here's my problem.
I'm writing a component in TypeScript, which is part of an ASPNET core 2 and angular project.
TS file :
import { Component } from '#angular/core';
#Component({
selector: 'clients',
templateUrl: './clients.component.html',
styleUrls: ['./clients.component.css']
})
export class ClientsComponent{
rows: Array<any>;
constructor() {
let btn = document.getElementById("coolbutton");
if (btn === null) return;
btn.addEventListener("click", (e: Event) => this.ClickMeButton());
}
ClickMeButton() {
alert("toto");
}
}
HTML file :
<input type="button" value="Click" id="coolbutton"/>
But an error is raised when the page loads :
An unhandled exception occurred while processing the request.
NodeInvocationException: Uncaught (in promise): ReferenceError: document is
not defined
I am unable to find any explanations on how to import document in my TS componenet...
just put the (click) on the element and call your function:
import { Component } from '#angular/core';
#Component({
selector: 'clients',
templateUrl: './clients.component.html',
styleUrls: ['./clients.component.css']
})
export class ClientsComponent{
constructor() {}
public clickMeButton(): void {
alert("toto");
}
}
<input type="button" value="Click" (click)="clickMeButton()"/>

Angular2-Dart PathLocationStrategy

Refreshing angular2 dart page using HashLocationStrategy works fine as it opens the exact same view.
Refreshing the page using PathLocationStrategy - with tomcat server configured to serve index.html - works for the url without parameter but does not work for the url with parameter.
localhost:8090/menu1 // refresh works
localhost:8090/menu2/paramVal // does not refresh
tomcat web.xml has
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
main.dart
main() {
bootstrap(AppComponent, [
ROUTER_PROVIDERS,
provide(APP_BASE_HREF, useValue: '/')]);
}
app_component.dart
import 'package:angular2/core.dart';
import 'package:angular2/router.dart';
import 'package:angular2/angular2.dart';
import 'package:mboxes/menu1.dart';
import 'package:mboxes/menu2.dart';
#Component(
selector: 'my-app',
templateUrl: 'app_component.html',
directives: const [ROUTER_DIRECTIVES],
providers: const[ROUTER_PROVIDERS, ])
#RouteConfig(const [
const Route(
path: '/menu1',
name: 'Menu1',
component: Menu1Component,
useAsDefault: true),
const Route(
path: '/menu2/:param', name: 'Menu2', component: Menu2Component)
])
class AppComponent {}
app_component.html
<div class="container">
<nav>
<ul>
<li>
<a [routerLink]="['Menu1']">Menu1</a>
</li>
<li> <a [routerLink]="['Menu2', {'param':'paramVal'}]">Menu2</a> </li>
</ul>
</nav>
<div style="padding-left: 200px; padding-top: 200px; padding-bottom: 50px">
<router-outlet></router-outlet>
</div>
</div>
menu1.dart
import 'package:angular2/core.dart';
import 'package:angular2/router.dart';
#Component(
selector: 'menu1',
template: ''' menu 1 was clicked '''
)
class Menu1Component {}
menu2.dart
import 'package:angular2/core.dart';
import 'package:angular2/router.dart';
#Component(
selector: 'menu2',
template: ''' menu 2 was clicked'''
)
class Menu2Component implements OnInit {
final RouteParams _routeParams;
Menu2Component(this._routeParams);
ngOnInit() {
var val = _routeParams.get('param');
print ("passed param is " + val);
}
}
Instead of using 404 to serve index.html I think you want to set up a servlet-mapping with something like <url-pattern>*</url-pattern>
See also Tomcat servlet, redirect all urls to a single webpage

How to use routing of angular2 and .net mvc Routing

I am doing authentication and authorization of pages on the server side. on index pages of each controller. But inside each index page I want to use angular 2 hence I want to use angular 2 routing.
I have tried like
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template:''
})
export class AppComponent {
}
app.module.ts
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { RouterModule } from '#angular/router'
import { TestSuiteComponent } from './testsuite/testsuite.component'
//import {InputTextModule, CalendarModule, DataTable} from 'primeng/primeng';
import { DataTableModule, SharedModule } from 'primeng/primeng';
#NgModule({
imports: [BrowserModule, DataTableModule, SharedModule, RouterModule.forRoot([
{
path: 'TestSuiteEditor/Index',
component: TestSuiteComponent
},
{
path: 'Home/Index',
component: TestSuiteComponent
}
])],
declarations: [AppComponent,TestSuiteComponent],
bootstrap: [ AppComponent]
})
export class AppModule { }
on testsuite.component.ts page
import { Directive, Component, OnInit } from '#angular/core';
import {DataTableModule, SharedModule} from 'primeng/primeng';
import { TestSuite } from './testsuite';
#Component({
// moduleId: module.id,
selector: 'testsuite-header',
template: `
<div class="ui-widget-header ui-helper-clearfix" style="padding:4px 10px;border-bottom: 0 none">
<i class="fa fa-search" style="float:left;margin:4px 4px 0 0"></i>
<input #gb type="text" pInputText size="50" style="float:left" placeholder="Global Filter">
</div>
<div class="ui-datatable ui-widget">
<div class="ui-datatable-tablewrapper">
<p-dataTable [value]="testSuites" [rows]="5" [paginator]="true" [globalFilter]="gb" [editable]="true">
<p-column field="testSuiteId" header="TestSuites (startsWith)" [style]="{'width':'10%'}" [filter]="true" [editable]="true"></p-column>
<p-column field="projectId" header="ProjectId (contains)" [style]="{'width':'10%'}" [filter]="true" filterMatchMode="contains" [editable]="true"></p-column>
<p-column field="name" header="Name (startsWith)" [style]="{'width':'30%'}" [filter]="true" [editable]="true"></p-column>
<p-column field="description" header="Description (endsWith)" [style]="{'width':'40%'}" [filter]="true" filterMatchMode="endsWith" [editable]="true"></p-column>
<p-column field="isActive" header="IsActive (endsWith)" [style]="{'width':'10%'}" [filter]="true" filterMatchMode="endsWith" [editable]="true"></p-column>
</p-dataTable>
</div>
</div> `,
// providers: [TestSuiteService]
})
export class TestSuiteComponent{}
Home/Index.cshtml
<testsuite-header>Loading....</testsuite-header>
but it throwing an error of
Cannot find primary outlet to load 'TestSuiteComponent'
You have forgotten to add router-outlet in your application. You can define router-outlet in AppComponent like this-
<router-outlet></router-outlet>
So your AppComponent will looks like this-
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template:`
<!-- Routed views go here -->
<router-outlet></router-outlet>
`
})
export class AppComponent {
}
I have found the solution, thanks for your help
I have created the path similar to my MVC routing and added in routing.ts.
Since angular 2routing have feature of loading the active url so it automatically loads the component which is assign to that URL.

Resources