Topic: TypeError: Cannot read properties of undefined (reading 'input')
pzimmer
priority
asked 11 months ago
Expected behavior
Doesn't throw errors in console
Actual behavior
This may be the same issue discussed here. https://mdbootstrap.com/support/angular/cannot-read-properties-of-undefined-reading-input/
Resources (screenshots, code snippets etc.)
gamer.component.html
<div class="d-flex align-items-center" *ngIf="isLoading">
<strong>Loading...</strong>
<div class="spinner-border text-success" role="status" aria-hidden="true" style="margin-left: 15px;"></div>
</div>
<div class="d-flex">
<!-- Image -->
<div class="flex-shrink-0">
<app-image [code]="model.gamerCode"
[isSmallCard]="false"
[isClanMemberPhoto]="false"
folder="gamerphotos"
(save)="saveFilename($event)">
</app-image>
</div>
<!-- Body -->
<div class="flex-grow-1 ms-3" style="margin-left:20px;">
<div class="row">
<div class="col-md-4"><h4>{{model.name}}</h4></div>
<div class="col-md-3 offset-md-5" style="text-align:right">
<button type="button" class="btn btn-primary btn-sm" (click)="save()">
<span class="spinner-border spinner-border-sm" role="status" *ngIf="isSaving" aria-hidden="true"></span>
<i class="fas fa-save" style="margin-left:5px;"></i> Save
</button>
<button type="button"
class="btn btn-primary btn-sm"
style="margin-left: 10px"
(click)="!onCancelCheck() ? openCancelModal() : cancelUpdate()">
<i class="fas fa-undo"></i> Cancel
</button>
</div>
</div>
<div class="clearfix"></div>
<form>
<mdb-form-control class="col-8" style="margin-top: 10px; margin-bottom: 15px;">
<input mdbInput type="text" id="name" name="name" class="form-control" [(ngModel)]="model.name" />
<label mdbLabel class="form-label" for="name">Name</label>
</mdb-form-control>
<mdb-form-control class="col-8" style="margin-top: 10px; margin-bottom: 15px;">
<input mdbCheckbox class="form-check-input" type="checkbox" value="" id="active" [(ngModel)]="model.isActive" [ngModelOptions]="{standalone: true}" />
<label class="form-check-label" for="active"> Active? </label>
</mdb-form-control>
<div class="col-8">
<label for="gamerClanLeaders">Clan Leaders</label><br/>
<ng-select [items]="(gamerClanLeaders$ | async)!"
bindLabel="displayName"
[trackByFn]="trackByFn"
[minTermLength]="2"
[loading]="gamerClanLeadersLoading"
typeToSearchText="Please enter 2 or more characters"
[typeahead]="gamerClanLeadersInput$"
[(ngModel)]="gamerClanLeadersModel"
labelForId="gamerClanLeaders"
mdbInput
name="gamerClanLeaders"
[multiple]="true"
[maxSelectedItems]="2">
</ng-select>
</div>
<div class="col-8">
<label for="clanOfficers">Clan Officers</label><br/>
<ng-select [items]="(clanOfficers$ | async)!"
bindLabel="displayName"
[trackByFn]="trackByFn"
[minTermLength]="2"
[loading]="clanOfficersLoading"
typeToSearchText="Please enter 2 or more characters"
[typeahead]="clanOfficersInput$"
[(ngModel)]="clanOfficersModel"
labelForId="clanOfficers"
mdbInput
name="clanOfficers"
[multiple]="true"
[maxSelectedItems]="2">
</ng-select>
</div>
<div class="col-8">
<label for="clanMembers">Clan Members</label><br/>
<ng-select [items]="(clanMembers$ | async)!"
bindLabel="displayName"
[trackByFn]="trackByFn"
[minTermLength]="2"
[loading]="clanMembersLoading"
typeToSearchText="Please enter 2 or more characters"
[typeahead]="clanMembersInput$"
[(ngModel)]="clanMembersModel"
labelForId="clanMembers"
mdbInput
name="clanMembers"
[multiple]="true">
</ng-select>
<br />
<br />
</div>
</form>
</div>
</div>
gamer.component.ts
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { HttpClient } from '@angular/common/http';
import { GamerService } from '../../services/gamer.service';
import { IGamer } from '../../models/gamer.model';
import { PhotoService } from "../../services/photo.service";
import { IPhoto } from "../../models/photo.model";
import { ClanMemberService } from "../../services/clanMember.service";
import { IClanMember } from "../../models/clanMember.model";
import { IGamerClanLeader } from "../../models/gamer-clanLeader.model";
import { IClanOfficer } from "../../models/managing-director.model";
import { concat, Observable, of, Subject } from 'rxjs';
import { catchError, distinctUntilChanged, switchMap, tap } from 'rxjs/operators';
import { select, Store } from '@ngrx/store';
import { accessToken, AppState, azureStorageKey } from 'src/app/store/app.state';
import { azureStorageURL } from 'src/app/utils/app-config';
import { setImagefolder, setImageUniqueId, setPhotoName } from 'src/app/store/auth.actions';
import { ToastSuccessComponent } from '../helpers/toast-success/toast-success.component';
import { ToastErrorComponent } from '../helpers/toast-error/toast-error.component';
import { MdbNotificationRef, MdbNotificationService } from 'mdb-angular-ui-kit/notification';
import { ModalCancelComponent } from '../helpers/modal-cancel/modal-cancel.component';
import { MdbModalRef, MdbModalService } from 'mdb-angular-ui-kit/modal';
// import { ToastService } from 'mdb-angular-ui-kit';
@Component({
selector: 'app-gamer',
templateUrl: './gamer.component.html',
styleUrls: ['./gamer.component.scss']
})
export class GamerComponent implements OnInit {
notificationSuccessRef: MdbNotificationRef<ToastSuccessComponent> | null = null;
notificationErrorRef: MdbNotificationRef<ToastErrorComponent> | null = null;
modalRef: MdbModalRef<ModalCancelComponent> | null = null;
id: string | null = null;
gamer: IGamer = { isActive: true, gamerClanLeaders: [], clanOfficers: [], clanMembers: [] }
model: IGamer = { isActive: true, gamerClanLeaders: [], clanOfficers: [], clanMembers: [] }
gamerClanLeadersModel: IClanMember[] = [];
clanOfficersModel: IClanMember[] = [];
clanMembersModel: IClanMember[] = [];
mode = 'read'; // CRUD
defaultPhoto: string = '';
searchText2?= '';
data: IClanMember[] = [];
isLoading: boolean = false;
isLoaded:boolean = false;
isSaving:boolean = false;
constructor(private readonly gamerService: GamerService
, private readonly store: Store<{user: AppState}>
, private notificationService: MdbNotificationService
, private modalService: MdbModalService
, private readonly clanMemberService: ClanMemberService
, private readonly activatedRoute: ActivatedRoute
, private readonly title: Title
, private readonly router:Router) { }
ngOnInit(): void {
const id = this.activatedRoute.snapshot.paramMap.get('id');
this.store.pipe(select(accessToken)).subscribe(async (accessToken: string | null) => {
if(accessToken && id !== null)
{
this.isLoading = true;
await this.getGamer(id);
this.loadClanLeaders();
this.loadClanOfficers();
this.loadClanMembers();
}
})
}
gamerClanLeaders$: Observable<IClanMember[]> = new Observable<IClanMember[]>();
gamerClanLeadersLoading = false;
gamerClanLeadersInput$ = new Subject<string>();
private loadClanLeaders() {
this.gamerClanLeaders$ = concat(
of([]), // default items
this.gamerClanLeadersInput$.pipe(
distinctUntilChanged(),
tap(() => this.gamerClanLeadersLoading = true),
switchMap(term => this.clanMemberService.getAll({ isActive: true, name: term }).pipe(
catchError(() => of([])), // empty list on error
tap(() => this.gamerClanLeadersLoading = false)
))
)
);
}
clanOfficers$: Observable<IClanMember[]> = new Observable<IClanMember[]>();
clanOfficersLoading = false;
clanOfficersInput$ = new Subject<string>();
private loadClanOfficers() {
this.clanOfficers$ = concat(
of([]), // default items
this.clanOfficersInput$.pipe(
distinctUntilChanged(),
tap(() => this.clanOfficersLoading = true),
switchMap(term => this.clanMemberService.getAll({ isActive: true, name: term }).pipe(
catchError(() => of([])), // empty list on error
tap(() => this.clanOfficersLoading = false)
))
)
);
}
clanMembers$: Observable<IClanMember[]> = new Observable<IClanMember[]>();
clanMembersLoading = false;
clanMembersInput$ = new Subject<string>();
private loadClanMembers() {
this.clanMembers$ = concat(
of([]), // default items
this.clanMembersInput$.pipe(
distinctUntilChanged(),
tap(() => this.clanMembersLoading = true),
switchMap(term => this.clanMemberService.getAll({ isActive: true, name: term }).pipe(
catchError(() => of([])), // empty list on error
tap(() => this.clanMembersLoading = false)
))
)
);
}
trackByFn(item: IClanMember) {
return item.clanMemberId;
}
getGamer(id: string) {
//console.log('getGamer');
this.gamerService.get(id, { includeClanMembers: true, includeClanLeaders: true, includeClanOfficers: true }).subscribe(gamer => {
this.gamer = gamer;
this.model = { ...gamer };
this.setTitle();
// Put the PSC ClanMembers into an array.
this.clanOfficersModel = (gamer.clanOfficers) ? gamer.clanOfficers.filter(pe => pe.clanMember).map(pe => pe.clanMember!) : [];
this.gamerClanLeadersModel = (gamer.gamerClanLeaders) ? gamer.gamerClanLeaders.filter(pl => pl.clanMember).map(pl => pl.clanMember!) : [];
this.clanMembersModel = (gamer.clanMembers) ? [...gamer.clanMembers] : [];
this.store.dispatch(setPhotoName({photoName: this.model.photoName ? this.model.photoName : 'No_Image_Available.jpg'}));
this.store.dispatch(setImagefolder({folderLocation: 'gamerphotos'}));
this.store.dispatch(setImageUniqueId({imageUniqueId: new Date().getTime()}));
this.isLoaded = true;
this.isLoading = false;
},
err => {
console.error(err);
});
}
setTitle() {
this.title.setTitle(`Gamer - ${this.gamer.name}`);
}
updateGamer() {
this.isSaving = true;
//console.log('updateGamer');
//console.log(this.model);
this.gamerService.update(this.model, this.model.gamerId, true, {includeClanLeaders: true, includeClanOfficers: true, includeClanMembers: true}).subscribe(() => {
//console.log('Gamer updated.');
this.gamer = { ...this.model };
this.setTitle();
this.mode = 'read';
this.isSaving = false;
this.showSuccess();
},
err => {
this.isSaving = false;
console.error(err);
this.showError();
});
}
edit() {
this.mode = 'update';
}
save() {
//console.log('save');
if (this.model.clanMembers) {
// Remove any that are no longer selected.
const clanMembers = this.model.clanMembers.filter(pe => this.clanMembersModel.find(pem => pem.clanMemberId === pe.clanMemberId));
// Add any new ones.
const newClanMembers = this.clanMembersModel.filter(pe => !(this.model.clanMembers!.find(pem => pem.clanMemberId === pe.clanMemberId)));
this.model.clanMembers = [...clanMembers, ...newClanMembers];
}
if (this.model.gamerClanLeaders) {
// Remove any that are no longer selected.
const gamerClanLeaders = this.model.gamerClanLeaders.filter(pe => this.gamerClanLeadersModel.find(pem => pem.clanMemberId === pe.clanMemberId));
// Add any new ones.
const newGamerClanLeaderModels = this.gamerClanLeadersModel.filter(pe => !(this.model.gamerClanLeaders!.find(pem => pem.clanMemberId === pe.clanMemberId)));
const newGamerClanLeaders = newGamerClanLeaderModels.map<IGamerClanLeader>(pe => ({clanMemberId: pe.clanMemberId!, gamerId: this.model.gamerId!}));
this.model.gamerClanLeaders = [...gamerClanLeaders, ...newGamerClanLeaders];
}
if (this.model.clanOfficers) {
// Remove any that are no longer selected.
const clanOfficers = this.model.clanOfficers.filter(pe => this.clanOfficersModel.find(pem => pem.clanMemberId === pe.clanMemberId));
// Add any new ones.
const newClanOfficerModels = this.clanOfficersModel.filter(pe => !(this.model.clanOfficers!.find(pem => pem.clanMemberId === pe.clanMemberId)));
const newClanOfficers = newClanOfficerModels.map<IClanOfficer>(pe => ({clanMemberId: pe.clanMemberId!, gamerId: this.model.gamerId!}));
this.model.clanOfficers = [...clanOfficers, ...newClanOfficers];
}
this.updateGamer();
}
onCancelCheck(){
return JSON.stringify(this.gamer) === JSON.stringify(this.model);
}
cancelUpdate() {
//console.log('cancelUpdate');
// TODO: Prompt if there were changes before reverting.
// Revert
this.model = { ...this.gamer };
this.clanOfficersModel = (this.gamer.clanOfficers) ? this.gamer.clanOfficers.filter(pe => pe.clanMember).map(pe => pe.clanMember!) : [];
this.gamerClanLeadersModel = (this.gamer.gamerClanLeaders) ? this.gamer.gamerClanLeaders.filter(pl => pl.clanMember).map(pl => pl.clanMember!) : [];
this.clanMembersModel = (this.gamer.clanMembers) ? [...this.gamer.clanMembers] : [];
this.router.navigate(['/gamers']);
}
openCancelModal() {
this.modalRef = this.modalService.open(ModalCancelComponent, {
data: { title: 'Gamer'},
});
}
saveFilename(filename?: string) {
this.gamer.photoName = filename;
this.model.photoName = filename;
this.gamerService.update(this.gamer, this.gamer.gamerId, false).subscribe(() => {
//console.log("Updated photo filename.");
},
err => {
console.error(err);
});
}
showSuccess() {
this.notificationSuccessRef = this.notificationService.open(ToastSuccessComponent
, { data: { text: 'Gamer updated!'}
, position: 'bottom-center'
, autohide: true });
}
showError() {
this.notificationSuccessRef = this.notificationService.open(ToastErrorComponent
, { data: { text: 'Something went wrong. Gamer could not be updated!'}
, position: 'bottom-center'
, autohide: true });
}
}
package.json
{
"name": "gamer",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^14.2.8",
"@angular/cdk": "^14.2.6",
"@angular/common": "^14.2.8",
"@angular/compiler": "^14.2.8",
"@angular/core": "^14.2.8",
"@angular/forms": "^14.2.8",
"@angular/platform-browser": "^14.2.8",
"@angular/platform-browser-dynamic": "^14.2.8",
"@angular/router": "^14.2.8",
"@azure/msal-angular": "^2.0.0-beta.1",
"@azure/msal-browser": "^2.12.1",
"@fortawesome/fontawesome-free": "^5.15.2",
"@ng-select/ng-select": "^9.0.2",
"@ngrx/data": "^14.3.2",
"@ngrx/effects": "^14.3.2",
"@ngrx/entity": "^14.3.2",
"@ngrx/router-store": "^14.3.2",
"@ngrx/store": "^14.3.2",
"@ngrx/store-devtools": "^14.3.2",
"@types/chart.js": "^2.9.30",
"animate.css": "^4.1.1",
"bn-ng-idle": "^1.0.1",
"chart.js": "^2.5.0",
"easy-pie-chart": "^2.1.7",
"hammerjs": "^2.0.8",
"mdb-angular-file-upload": "mdbootstrap.com/mdb/angular/mdb5/plugins/prd/file-upload",
"mdb-angular-ui-kit": "mdbootstrap.com/mdb/angular/mdb5/prd/mdb5-angular-ui-kit-pro-essential",
"mdb-angular-wysiwyg": "mdbootstrap.com/mdb/angular/mdb5/plugins/prd/wysiwyg",
"rxjs": "~6.6.0",
"screenfull": "^3.3.0",
"tslib": "^2.0.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^14.2.7",
"@angular/cli": "^14.2.7",
"@angular/compiler-cli": "^14.2.8",
"@types/jasmine": "~3.6.0",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^12.11.1",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~6.3.4",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"protractor": "~7.0.0",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "^4.6.4"
}
}
Grzegorz Bujański
staff
answered 11 months ago
The error showed up because you used a checkbox inside the mdb-form-control
component. The form control component is for other components that have a floating label, eg input type="text"
input type="number"
and select
FREE CONSULTATION
Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.
Answered
- User: Priority
- Premium support: Yes
- Technology: MDB Angular
- MDB Version: MDB5 3.0.0
- Device: Desktop
- Browser: Chrome
- OS: Windows
- Provided sample code: No
- Provided link: Yes