Reputation: 21
I am making the Kanban-fire app by following the tutorial on Google Codelabs. This is the link of the part where I'm facing issues. https://developers.google.com/codelabs/building-a-web-app-with-angular-and-firebase#10
I'm using Angular CLI 11.0.7, Node 12.18.2, Ubuntu 20.10 64bit, TypeScript 4.1.2.
As explained in the tutorial, I followed along and made all the necessary changes. Here's the issue that I'm facing.
At first, I was getting this error
Property 'task' has no initializer and is not definitely assigned in the constructor. 19 task: Task;
and this is my corresponding code
@Input() task: Task;
It uses the following Task interface
export interface Task {
id?: string;
title: string;
description: string;
}
I tried to solve this error by initializing the task property in @Input as
@Input() task: Task = {title: 'def title', description: 'def desc'};
and it was all good until these errors arose.
As you'll be able to see in the link that I've shared, that we have to make changes to app.component.html
as well as some methods in app.component.ts
file.
I made the changes and now I'm getting these errors.
Error: src/app/app.component.html:21:34 - error TS2345: Argument of type 'CdkDragDrop<{ id: string; }[] | null, any>' is not assignable to parameter of type 'CdkDragDrop<Task[], Task[]>'.
Type '{ id: string; }[] | null' is not assignable to type 'Task[]'.
Type 'null' is not assignable to type 'Task[]'.
21 (cdkDropListDropped)="drop($event)"
and
Error occurs in the template of component AppComponent.
src/app/app.component.html:27:17 - error TS2739: Type '{ id: string; }' is missing the following properties from type 'Task': title, description
27 cdkDrag [task]="task"></app-task>
For complete reference, I am providing app.component.html
as well as app.component.ts
code here
<mat-toolbar color="primary">
<mat-icon>local_fire_department</mat-icon>
<span>Kanban Fire</span>
</mat-toolbar>
<div class="content-wrapper">
<button (click)="newTask()" mat-button>
<mat-icon>add</mat-icon> Add Task
</button>
</div>
<div class="container-wrapper">
<div class="container">
<h2>Backlog</h2>
<mat-card
cdkDropList
id="todo"
#todoList="cdkDropList"
[cdkDropListData]="todo | async"
[cdkDropListConnectedTo]="[doneList, inProgressList]"
(cdkDropListDropped)="drop($event)"
class="list">
<p class="empty-label" *ngIf="(todo | async)?.length === 0">Empty List</p>
<app-task
(edit)="editTask('todo', $event)"
*ngFor="let task of todo | async"
cdkDrag [task]="task"></app-task>
</mat-card>
</div>
<div class="container">
<h2>In Progress</h2>
<mat-card
cdkDropList
id="inProgress"
#inProgressList="cdkDropList"
[cdkDropListData]="inProgress | async"
[cdkDropListConnectedTo]="[todoList, doneList]"
(cdkDropListDropped)="drop($event)"
class="list">
<p class="empty-label" *ngIf="(inProgress | async)?.length === 0">Empty List</p>
<app-task
(edit)="editTask('inProgress', $event)"
*ngFor="let task of inProgress | async"
cdkDrag [task]="task"></app-task>
</mat-card>
</div>
<div class="container">
<h2>Done</h2>
<mat-card
cdkDropList
id="done"
#doneList="cdkDropList"
[cdkDropListData]="done | async"
[cdkDropListConnectedTo]="[todoList, inProgressList]"
(cdkDropListDropped)="drop($event)"
class="list">
<p class="empty-label" *ngIf="(done | async)?.length === 0">Empty List</p>
<app-task
(edit)="editTask('done', $event)"
*ngFor="let task of done | async"
cdkDrag [task]=""></app-task>
</mat-card>
</div>
</div>
app.component.ts
import { Component } from '@angular/core';
import { Task } from '../app/task/task';
import { CdkDragDrop, transferArrayItem } from '@angular/cdk/drag-drop';
import { MatDialog } from '@angular/material/dialog';
import { TaskDialogComponent } from '../app/task-dialog/task-dialog.component';
import { TaskDialogResult } from '../app/task-dialog/task-dialog.component';
import { AngularFirestore } from '@angular/fire/firestore';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
todo = this.store.collection('todo').valueChanges({ idField: 'id' });
inProgress = this.store.collection('inProgress').valueChanges({ idField: 'id' });
done = this.store.collection('done').valueChanges({ idField: 'id' });
constructor(private dialog: MatDialog, private store: AngularFirestore) {}
editTask(list: 'done' | 'todo' | 'inProgress', task: Task): void {
const dialogRef = this.dialog.open(TaskDialogComponent, {
width: '270px',
data: {
task,
enableDelete: true,
}
});
dialogRef.afterClosed().subscribe((result: TaskDialogResult) => {
if (result.delete) {
this.store.collection(list).doc(task.id).delete();
} else {
this.store.collection(list).doc(task.id).update(task);
}
});
}
drop(event: CdkDragDrop<Task[]>): void {
if (event.previousContainer === event.container) {
return;
}
const item = event.previousContainer.data[event.previousIndex];
this.store.firestore.runTransaction(() => {
const promise = Promise.all([
this.store.collection(event.previousContainer.id).doc(item.id).delete(),
this.store.collection(event.container.id).add(item),
]);
return promise;
});
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
newTask(): void {
const dialogRef = this.dialog.open(TaskDialogComponent, {
width: '270px',
data: {
task: {}
}
});
dialogRef.afterClosed().subscribe((result: TaskDialogResult) => {
this.store.collection('todo').add(result.task)
});
}
}
Any help will be appreciated.
Upvotes: 0
Views: 1638
Reputation: 349
I had a similar problem in an application I was working on. I eventually paid close attention to my error message similar to yours ... your error message was --> "Property 'task' has no initializer and is not definitely assigned in the constructor. 19 task: Task;
In my case my error was -->"Property 'election' has no initializer and is not definitely assigned in the constructor.ts(2564)"
my input statement was
@Input() election: Election
and I added this line in my constructor which was formerly not populated with this initialization.
this.election =ELECTIONS[0]
this solved my problem
I guess you have to initialize in the constructor whatever it is you are trying to import.
In summary source Component -->
elections-main-list.component.html
<app-election-item
*ngFor="let election of elections"
[election]="election" >
</app-election-item>
Import component
election-item-component.ts
export class ElectionItemComponent implements OnInit{
@Input() election: Election
constructor() {
this.election =ELECTIONS[0]
}
As I have only been using Angular for a short period of time the lesson I learned was to pay close attention to the error message. anyway this solution worked perfectly and on the next step....
Upvotes: 0
Reputation: 21
Thanks to @Eliseo for pointing this out. The strict mode being turned on caused all this to happen.
Just set strict
and strictTemplates
flags to false in tsconfig.json
file.
Upvotes: 1