Angular 2 Material Design Autocomplete search box - javascript

I got some issues on autocomplete on Angular2 Material Design which these are the things happened:
*When I type a character that is associated with the one I search it won't display on the autocomplete the specific character that I entered on the search textbox as shown in the picture below:
When before typing on the search box.
When after typing on the search box
The second one is that when I select a specific list on the list of users it seems that it will display the [object Object] thingy and I don't know why it happens. See the picture below:
When before selecting a employee on the list
When after selecting a employee on the list
Here is my code below see if there's something that I missed or what.
Angular Code: new-useraccount-components.ts
import { Component } from '#angular/core';
import { WebServiceComponents } from '../WebService/web.service';
import { FormControl } from '#angular/forms';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/map';
#Component({
selector: 'new-user-account',
template: `
<md-card class="card-margin">
<md-card-content>
<md-input-container>
<input mdInput placeholder="Select Employee" [mdAutocomplete]="auto" [formControl]="UserAccountCtrl" /><br />
</md-input-container>
<md-autocomplete #auto="mdAutocomplete">
<md-option *ngFor="let userAccount of filterUserAccount | async" [value]="userAccount">
{{userAccount.username}}
</md-option>
</md-autocomplete>
<md-input-container>
<input mdInput placeholder="Username" /><br />
</md-input-container>
</md-card-content>
</md-card>
`
})
export class NewUserAccountComponent{
UserAccountCtrl: FormControl;
filterUserAccount: any;
async ngOnInit(){
var response = await this.webService.getUserAccounts();
this.userAccounts = response.json();
}
userAccounts = [];
constructor(private webService : WebServiceComponents){
this.UserAccountCtrl = new FormControl();
this.filterUserAccount = this.UserAccountCtrl.valueChanges
.startWith(null)
.map(name => this.filteredUserAccount(name));
}
filteredUserAccount(val: string) {
return val ? this.userAccounts.filter(s => new RegExp(`^${val}`, 'gi').test(s))
: this.userAccounts;
}
}
AppModule: app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { MaterialModule } from '#angular/material';
import { AppComponent } from './app.component';
import { WebServiceComponents } from './WebService/web.service';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { UserAccountComponent } from './UserAccount/useraccount-components';
import { NewUserAccountComponent } from './UserAccount/new-useraccount-component';
#NgModule({
imports: [ BrowserModule, MaterialModule, ReactiveFormsModule, FormsModule ],
declarations: [ AppComponent, UserAccountComponent, NewUserAccountComponent ],
bootstrap: [ AppComponent ],
providers: [ WebServiceComponents ]
})
export class AppModule { }
Sorry I'm just a newbie trying to play with this new framework. Hopefully someone will guide me on how to fix this issue. Thank you and Have a wonderful day ahead!

The docs are quite clear if you read them closely enough:
https://material.angular.io/components/autocomplete/overview
You'll be especially interested in what it has to say under the title "Setting separate control and display values". It is not displaying your search result because you want to display something different than the [value] you've specified.
The other problem you are having is that when selecting an item in the list the actual value of that item is inserted into the search box. Since this is a userAccount and not the username, [object Object] is displayed.
Simply changing to [value]="userAccount.username" could solve both your problems. If this does not give you the desired effect, you'll have to use the [displayWith] attribute as explained in the docs.

Related

Angular formControl fails to load

I'm following Angular tutorial on forms here:
https://angular.io/guide/reactive-forms
I have this code in 'datasources.component.html':
<form [formGroup]="queryForm">
<label>Query:
<input type="text" formControlName="query">
</label>
And this in 'datasources.component.ts':
import { Component } from '#angular/core';
import { FormGroup, FormControl } from '#angular/forms';
#Component({
selector: 'sql-editor',
templateUrl: './datasources.component.html',
styleUrls: ['./datasources.component.scss']
})
export class DatasourcesComponent {
queryForm = new FormGroup({
query: new FormControl(''),
});
}
I see its stuck at 'websocket : pending'
Also, my original intent is to make it work for 'textarea'. Is the solution going to work for that too?
<textarea class="form-control" rows="5" id="sql-query" [formControl]="query"></textarea>-
I'm using Angular version 7.2:
EDIT:
I see this error in console 'Can't bind to 'formGroup' since it isn't a known property of 'form'
Import ReactiveFormsModule in your AppModule
import { ReactiveFormsModule } from '#angular/forms';
#NgModule({
imports: [
// other imports ...
ReactiveFormsModule
],
})
export class AppModule { }
formGroup, formControl, etc are all directives that are exposed as a part of the ReactiveFormsModule.
If you want to use these directives in a Component, you'll have to either import the ReactiveFormsModule in the Module that this Component is registered in. Or you'll have to export the ReactiveFormsModule from some other module(SharedModule for instance) and then import that module in the module that you have this Component registered in.
import { ReactiveFormsModule } from '#angular/forms';
#NgModule({
imports: [
// other imports ...
ReactiveFormsModule
],
})
export class YourComponentModule { }
Also use the formcontrols like shown below:
<textarea class="form-control" rows="5" id="sql-query" formControlName="query"></textarea>

Angular 2 bind HTML inputs to component variables like in Vue?

So I've been struggling with this for a long time...I've been looking into the docs, but there are so many different directives and ways to communicate between components and the DOM, but only a few good examples...
So I'm actually not even sure what I need. Let's say I have a user input in my tables.component.html file like this:
<label>Name</label>
<input id="customerName" class="form-control" required>
Then there is my tables.component.ts file which looks like this:
import { Component, OnInit } from '#angular/core';
import { isLoggedIn } from '../../assets/js/auth.js';
import { Router } from '#angular/router';
#Component({
selector: 'app-tables',
templateUrl: './tables.component.html',
styleUrls: ['./tables.component.css']
})
export class TablesComponent implements OnInit {
customers = [];
id = ""; // keep outside of object to prevent user changes
customer_form = {
name: "",
job: "",
address: "",
birthdate: "",
email: "",
}
constructor(private router: Router) { }
...
}
To make it simple: I want to bind the user input above to the customer_form.name variable in my component. I'm looking for the equivalent of Vue 2.0 models, so that if the user changes the input value, the component value changes aswell. I don't neccessarily have to push the data within a form since we've got the task not to set up any backend...
Anyway, I'm kinda confused. I read the docs, but that made it just worse. One page says I'm supposed to add a controller to the form and add a script to the bottom of the HTML, another one said I have to make a template of the form that should be stored in the component...And then there are so many different directives to bind things. I was assuming you'd want to use ngModel for that, but I couldn't seem to get that working like in the examples I found.
Thanks for any help in advance..
I have created a simple example of binding in a template-driven form: https://stackblitz.com/edit/angular-m2tkrf
Note that FormsModule is imported in app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms'; //<---- IMPORTED
import { AppComponent } from './app.component';
import { HeroFormComponent } from './hero-form/hero-form.component';
#NgModule({
imports: [
BrowserModule,
FormsModule //<---- IMPORTED IN MODULE
],
declarations: [
AppComponent,
HeroFormComponent
],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule { }
I think what you're looking for is [(ngModel)] which is used for two-way data binding.
<input
id="customerName"
class="form-control"
required
[(ngModel)]="customer_form.name"
name="name">
PS: To use the [(ngModel)], you'll have to import FormsModule and then add it the the imports array of your AppModule or whatever module you're using it in.
...
import { FormsModule } from '#angular/forms';
...
#NgModule({
imports: [
...,
FormsModule,
...
],
...
})
export class AppModule { }
Use ngModel for two-way data binding
put [(ngModel)] on the input to pass the data from & to your property like this:
//app.module code
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms'; //<---- IMPORTED
import { AppComponent } from './app.component';
import { TablesComponent } from './tables.component'; //<---- IMPORTED
#NgModule({
imports: [
BrowserModule,
FormsModule //<---- IMPORTED IN MODULE
],
declarations: [
AppComponent,
TablesComponent //<---- IMPORTED
],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule { }
//--------------------------tables.component.html
<input id="customerName" class="form-control" [(ngModel)]="customer_form.name" required>

Angular2, toggle a checked checkbox list

Is there a way to toggle a checked checkbox list in Angular2?
I have a button that when pressed and the full list is in view, it will show only the checked items in the list. When the button is pressed again, it will show the entire list.
Plunkr: http://plnkr.co/edit/jZz4XoHjYJ40bjt2eOU5?p=preview
//our root app component
import {Component, NgModule} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
</div>
<li *ngFor="let col of data" class="form-group">
<input type="checkbox" name="col" value="{{col.value}}" [(ngModel)]="col.value" (change)="addColumns(col)" />{{col.name}}
</li>
`,
})
export class App {
name:string;
data:any[]=[{"id":"13","name":"AAA"},{"id":"15","name":"BBB"},{"id":"20","name":"CCC"}]
constructor() {
this.name = 'Angular2'
}
get selectedcheckboxes() {
return this.data
.filter(opt => opt.value)
}
addColumns(col){
this.selectedcheckboxes;
console.log(this.selectedcheckboxes)
}
}
#NgModule({
imports: [ BrowserModule,FormsModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
HTML:
<body>
<my-app>
loading...
</my-app>
<button class="check">Collapse/Expand</button>
</body>
In Angular1, it looks like this: http://jsfiddle.net/jzhang172/of4yy8k9/ I'm looking to do the same thing in Angular2, but can't understand the syntax.
You can put the main array in other variable and then just change the data variable according your clicked button (to expand or to collapse), you may need one variable to define if it's full list or the selected list
something like:
isFullList: boolean;
mainData: Array<any> = [your main data here];
data: Array<any> = [data to use in list]; //should initied by mandata
toggle() {
//this.isFullList: boolean
if (!this.isFullList) {
this.data = [...this.mainData];
} else {
this.data = [...this.selectedcheckboxes];
}
console.log(this.data)
this.isFullList = ! this.isFullList
}
plunker: http://plnkr.co/edit/V1iiX87gYVMUtIkmpMfT?p=preview
You can implement an filter at your component, and invoke the filter at your template.
In the filter, just add a flag to control to filter or show original list, and toggle the flag by click the button.
Invoke filter at template
*ngFor="let col of getData()"
Filter data in component
getData() {
return this.filter ? this.data.filter(item => item.value === true) : this.data;
}
Plunker Demo

ng-select not updating in Angular 2

hello i am new in angular 2
i can make formGroup in add in ng-select controll and predefine value added.
that is perfectly.
but when button click then new value push in ng-select but ng-select not updating .
here my plunker
https://plnkr.co/edit/Hwfk1T2stkiRcLTxuFmz
//our root app component
import {Component, OnInit, NgModule, ViewChild} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {FormControl, FormGroup, ReactiveFormsModule} from '#angular/forms';
import {SelectModule} from 'ng-select';
#Component({
selector: 'my-app',
template: `
<h1>ng-select demo app</h1>
<form style="padding:18px;max-width:800px;"
[formGroup]="form">
<div style="margin:5px 0;font-weight:600;">Single select example</div>
<ng-select
[options]="options0"
[multiple]="false"
placeholder="Select one"
formControlName="selectSingle"
>
</ng-select>
<button (click)="pushValue()">Click</button>
<div>Events:</div>
<pre #preSingle>{{logSingleString}}</pre>
</form>`
})
export class App implements OnInit {
form: FormGroup;
multiple0: boolean = false;
options0: any[] = [];
selection: Array<string>;
#ViewChild('preSingle') preSingle;
logSingleString: string = '';
constructor() {
this.options0.push({"label":'test',"value":'Test'});
console.log("Object:::"+JSON.stringify(this.options0));
}
ngOnInit() {
this.form = new FormGroup({});
this.form.addControl('selectSingle', new FormControl(''));
console.log("Object:::"+JSON.stringify(this.options0));
}
pushValue()
{
console.log("pushValue call.");
this.options0.push({"label":"test","value":"Test"});
console.log("Object:::"+JSON.stringify(this.options0));
}
}
#NgModule({
imports: [
BrowserModule,
ReactiveFormsModule,
SelectModule
],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
where is wrong ???
you can use Array.slice() to update to array instance in order to let angular detect the change of array.
this.options0 = this.options0.slice();
Looking at ng-select source code i noticed
ngOnChanges(changes: any) {
if (changes.hasOwnProperty('options')) {
this.updateOptionsList(changes['options'].isFirstChange());
}
so in order to update options list you should fire ngOnChanges. It can be done by creating new reference to options0
this.options0 = this.options0.concat({"label":"test","value":"Test"});
or
this.options0 = [...this.options0, {"label":"test","value":"Test"}];
Modified Plunker
Change Detection
Ng-select component implements OnPush change detection which means the dirty checking checks for immutable data types. That means if you do object mutations like:
this.items.push({id: 1, name: 'New item'})
Component will not detect a change. Instead you need to do:
this.items = [...this.items, {id: 1, name: 'New item'}];
This will cause the component to detect the change and update. Some might have concerns that this is a pricey operation, however, it is much more performant than running ngDoCheck and constantly diffing the array.

TypeError: this.form._updateTreeValidity is not a function

I'm currently using Angular Forms version 2.0.0 and trying to make a contact us modal with a contact form inside.
Immediately after the ContactComponent loads, I get:
EXCEPTION: this.form._updateTreeValidity is not a function
I've already seen some other stack posts suggesting that using FormGroup instead of FormBuilder to init the form object in the component constructor is now standard with the new API so I've updated that.
I import ReactiveFormsModule and FormsModule along with all the form related components and the error doesn't seem to be module related.
My TypeScript isn't throwing errors in compile time and Visual Studio Intellisense seems to be able to find all FormGroup functions just fine so why is this happening at runtime?...
My code:
contact.component.ts:
import { Component, Input, ViewChild } from '#angular/core';
import { ApiService } from '../../../services/api.service';
import { ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { FormsModule, ReactiveFormsModule, FormGroup, FormControl, Validators } from '#angular/forms';
import 'rxjs/Rx';
declare var jQuery: any;
#Component({
selector: 'my-contact',
templateUrl: 'app/modules/footer/contact/contact.html'
})
export class ContactComponent {
private contactForm: FormGroup;
private invalidEmail: boolean;
private invalidSubject: boolean;
private invalidMessage: boolean;
constructor(private apiService: ApiService, private router: Router, private route: ActivatedRoute) {
this.contactForm = new FormGroup({
emailControl: new FormControl('', <any>Validators.required),
subjectControl: new FormControl('', <any>Validators.required),
messageControl: new FormControl('', <any>Validators.required)
});
}
submit() {
if (this.contactForm.valid) {
this.apiService.sendMessage(this.contactForm.controls['emailControl'].value, this.contactForm.controls['subjectControl'].value, this.contactForm.controls['messageControl'].value);
}
if (!this.contactForm.controls['emailControl'].valid) {
this.invalidEmail = true;
}
if (!this.contactForm.controls['subjectControl'].valid) {
this.invalidSubject = true;
}
if (!this.contactForm.controls['messageControl'].valid) {
this.invalidMessage = true;
}
}
ngOnInit() {
this.invalidEmail = false;
this.invalidSubject = false;
this.invalidMessage = false;
}
}
contact.html:
<modal-header class="c-no-border" [show-close]="true">
<h4 class="modal-title text-uppercase">Send us a message</h4>
</modal-header>
<form novalidate #contactForm [formGroup]="contactForm" (ngSubmit)="submit()">
<div class="modal-body">
<div class="form-group">
<label for="email" class="control-label">Email</label>
<input name="email" formControlName="emailControl" placeholder="" type="text" class="c-square form-control c-margin-b-20" id="email">
<div class="c-font-red-1" *ngIf="invalidEmail" style="position: absolute;">*Required</div>
<label for="subject" class="control-label">Subject</label>
<input name="subject" formControlName="subjectControl" placeholder="" type="text" class="c-square form-control c-margin-b-20" id="subject">
<div class="c-font-red-1" *ngIf="invalidSubject" style="position: absolute;">*Required</div>
<textarea formControlName="messageControl" style="resize: vertical;" class="c-square form-control c-margin-b-20" id="content" (keyup.enter)="submit()"></textarea>
<div class="c-font-red-1" *ngIf="invalidMessage" style="position: absolute;">*Required</div>
</div>
</div>
<modal-footer class="c-no-padding">
<button type="button" class="btn c-btn-square c-btn-bold c-btn-uppercase pull-right">Cancel</button>
<button type="submit" class="btn c-theme-btn c-btn-square c-btn-bold c-btn-uppercase pull-right" style="margin-right: 10px;">Send</button>
</modal-footer>
</form>
app.module.ts:
import { NgModule, enableProdMode } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { Ng2Bs3ModalModule } from 'ng2-bs3-modal/ng2-bs3-modal';
import { QueuesModule } from './modules/queues/queues.module';
import { OrderModule } from './modules/order/order.module';
import { AccountModule } from './modules/account/account.module';
import { AdminModule } from './modules/admin/admin.module';
import { routing } from './app.routing';
import { GridModule } from '#progress/kendo-angular-grid';
import { SplashComponent } from './modules/splash/splash.component';
import { ContactComponent } from './modules/footer/contact/contact.component';
import { SharedModule } from './shared/shared.module';
import { EmailValidator } from './shared/utilities/custom-validators'
import { CookieService } from 'angular2-cookie/services/cookies.service';
import { HttpModule, Response } from '#angular/http';
import { StringService } from './services/string.service';
import { ApiService } from './services/api.service';
import { UserService } from './services/user.service';
import { OrderService } from './services/order.service';
import { OrderGuard } from './services/order-guard.service';
import { FooterComponent } from './modules/footer/footer.component';
import { ErrorComponent } from './modules/error/error.component';
import { CustomFormsModule } from "ng2-validation";
#NgModule({
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
HttpModule,
QueuesModule,
OrderModule,
AccountModule,
AdminModule,
routing,
GridModule,
SharedModule,
Ng2Bs3ModalModule,
CustomFormsModule
],
declarations: [
AppComponent,
SplashComponent,
FooterComponent,
ErrorComponent,
ContactComponent
],
providers: [
StringService,
ApiService,
UserService,
CookieService,
OrderService,
OrderGuard
],
bootstrap: [AppComponent],
exports: [
]
})
export class AppModule {
}
Binding the template variable #contactForm appears to cause a name conflict and blow up the template processor as it tries to turn the attached template variable into an NgForm on the backend. Everywhere I have seen model driven forms used there is no template variable binding on the form, whereas there is a #tv="ngForm" utilized in template driven forms. It appears there was a miss on the mixing of the two forms approaches which resulted in the error.
Simply removing it will resolve the issue.
When you incorrectly add to your template formGroup="..." instead of [formGroup]="..." you'll also get this error message.
It's been a while, but for me the problem was passing the formGroup to the template instead of referencing it directly.
E.g. this is not working
<ng-template #selectField
let-field
let-group
let-frmName="frmName">
<ng-container [formGroup]="group">
<mat-form-field fxFlex="32"
floatLabel="always">
<mat-label>{{field.label}}</mat-label>
<mat-select [formControlName]="frmName"
[required]="field.required">
<mat-option *ngFor="let option of field.options"
[value]="option.value">
{{option.description}}
</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
</ng-template>
If I use directly my formGroup instance it works just fine.
Hope this helps.
I had a dynamic form. I got above error since I didn't init it inside the ngOnInit()
Solution:
checkInForm: FormGroup;
ngOnInit(){
this.checkInForm = this.formBuilder.group({});
}
Sometime this error is caused when you use a [formGroup] to pass the string of the formGroup name. Use formGroupName instead.
This can happen when you're using the input name formControl or formGroup on a custom component which isn't a form control.
Change your custom component to accept a different input name:
Change this
#Input()
formGroup: string
// ^ Causes issues
To this
#Input()
group: string
I forgot to pass my form to the reusable input <app-input [form]="myForm"></app-input>
app-input.component.html
<form [formGroup]="form">
<input [type]="type" [placeholder]="placeholder [formControlName]="formControlName" />
</form>
app-input.component.ts
#Input() type: string = '';
#Input() placeholder: string = '';
#Input() formControlName: string = ''
#Input() form: FormGroup = {} as FormGroup;

Categories

Resources