1. परिचय
पिछला अपडेट: 11-09-2020
आप क्या बनाते हैं
इस कोडलैब में हम #39 हमारे फ़ाइनल ऐप्लिकेशन में तीन तरह के टास्क होंगे: बैकलॉग, काम जारी है, और पूरा हो गया है. हम खींचें और छोड़ें का इस्तेमाल करके, टास्क बना पाएंगे, उन्हें मिटा पाएंगे, और उन्हें एक कैटगरी से दूसरी कैटगरी में ट्रांसफ़र कर पाएंगे.
हम Angular का इस्तेमाल करके यूज़र इंटरफ़ेस बढ़ाएंगे और अपने स्थायी स्टोर के तौर पर Firestore का इस्तेमाल करेंगे. कोडलैब के आखिर में, हम Angular CLI का इस्तेमाल करके, ऐप्लिकेशन को Firebase होस्टिंग के लिए डिप्लॉय करेंगे.
आप क्या #39;जानेंगे
- ऐंगुलर सामग्री और सीडीके का इस्तेमाल करने का तरीका.
- अपने Angular ऐप्लिकेशन में Firebase एकीकरण को जोड़ने का तरीका.
- Firestore में लगातार डेटा बनाए रखने का तरीका.
- एक कमांड की मदद से Angular CLI का इस्तेमाल करके, अपने ऐप्लिकेशन को Firebase होस्टिंग के लिए डिप्लॉय करें.
आपको क्या चाहिए
इस कोडलैब से यह माना जाता है कि आपके पास Google खाता है और Angular और Angular CLI की बुनियादी जानकारी है.
शुरू करें!
2. नया प्रोजेक्ट बनाना
सबसे पहले, आइए एक नया Angular फ़ाइल फ़ोल्डर बनाएं:
ng new kanban-fire
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS
इस प्रक्रिया में कुछ मिनट लग सकते हैं. Angular CLI आपके प्रोजेक्ट का स्ट्रक्चर बनाता है और सभी डिपेंडेंसी इंस्टॉल करता है. इंस्टॉल करने की प्रक्रिया पूरी होने के बाद, kanban-fire
डायरेक्ट्री पर जाएं और Angular CLI's डेवलपमेंट सर्वर शुरू करें:
ng serve
http://localhost:4200 खोलें और आपको इससे मिलता-जुलता आउटपुट दिखेगा:
अपने एडिटर में src/app/app.component.html
खोलें और इसका पूरा कॉन्टेंट मिटाएं. http://localhost:4200 पर वापस जाने पर, आपको एक खाली पेज दिखेगा.
3. Material and the CDK जोड़ना
Angular, @angular/material
पैकेज के हिस्से के तौर पर, मटीरियल डिज़ाइन के साथ काम करने वाले यूज़र इंटरफ़ेस के कॉम्पोनेंट को लागू करने का तरीका है. @angular/material
की डिपेंडेंसी में से एक, कॉम्पोनेंट डेवलपमेंट किट या सीडीके है. सीडीके ने प्रिमिटिव, जैसे कि A11y यूटिलिटी, ड्रैग ऐंड ड्रॉप, और ओवरले की सुविधा दी है. हम सीडीके को @angular/cdk
पैकेज में बांटते हैं.
अपने ऐप्लिकेशन को चलाने के लिए सामग्री जोड़ने के लिए:
ng add @angular/material
इस निर्देश में आपसे कोई थीम चुनने के लिए कहा जाता है. अगर आप ग्लोबल मटीरियल टाइपोग्राफ़ी स्टाइल का इस्तेमाल करना चाहते हैं और आपको ऐंगुलर मटीरियल के लिए ब्राउज़र ऐनिमेशन सेट अप करना है, तो आपको यह विकल्प चुनना होगा. इस कोडलैब के समान नतीजा पाने के लिए, &Intgo/Ininkgo/Pink&kot; को चुनें और पिछले दो सवालों के जवाब &&कोटेशन की सुविधा से दें.
ng add
निर्देश, @angular/material
, उसकी डिपेंडेंसी इंस्टॉल करता है, और BrowserAnimationsModule
को AppModule
में इंपोर्ट करता है. अगले चरण में, हम इस मॉड्यूल के कॉम्पोनेंट का इस्तेमाल करना शुरू कर सकते हैं!
पहले, चलिए AppComponent
में एक टूलबार और एक आइकॉन जोड़ते हैं. app.component.html
खोलें और यह मार्कअप जोड़ें:
src/app/app.component.html
<mat-toolbar color="primary">
<mat-icon>local_fire_department</mat-icon>
<span>Kanban Fire</span>
</mat-toolbar>
यहां, हम अपनी मटीरियल डिज़ाइन थीम के मुख्य रंग का इस्तेमाल करके एक टूलबार जोड़ते हैं. साथ ही, हम लेबल &Kanban Fire.&के कोटेशन के आगे local_fire_depeartment
आइकॉन का इस्तेमाल करते हैं; अब अगर आप अपने कंसोल पर देखेंगे, तो आप देखेंगे कि Angular कुछ गड़बड़ियां देता है. उन्हें ठीक करने के लिए, पक्का करें कि आप AppModule
में ये इंपोर्ट जोड़ते हैं:
src/app/app.module.ts
...
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatIconModule } from '@angular/material/icon';
@NgModule({
declarations: [
AppComponent
],
imports: [
...
MatToolbarModule,
MatIconModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
हम ऐंगुलर सामग्री के टूलबार और आइकॉन का इस्तेमाल करते हैं, इसलिए हमें AppModule
में उससे जुड़े मॉड्यूल इंपोर्ट करने होंगे.
अब आपको स्क्रीन पर यह जानकारी दिखेगी:
एचटीएमएल की सिर्फ़ चार लाइन और दो इंपोर्ट का इस्तेमाल करना अच्छा नहीं है!
4. टास्क विज़ुअलाइज़ करना
अगले चरण में, आइए एक ऐसा कॉम्पोनेंट बनाएं जिसे हम कंबन बोर्ड में मौजूद टास्क को विज़ुअलाइज़ करने के लिए इस्तेमाल कर सकते हैं.
src/app
डायरेक्ट्री पर जाएं और यह सीएलआई कमांड चलाएं:
ng generate component task
यह निर्देश, TaskComponent
को जनरेट करता है और AppModule
में इसका एलान करता है. task
डायरेक्ट्री में, task.ts
नाम की एक फ़ाइल बनाएं. हम इस फ़ाइल का इस्तेमाल, कंबन बोर्ड के टास्क के इंटरफ़ेस को तय करने के लिए करेंगे. हर टास्क में एक वैकल्पिक id
, title
, और description
फ़ील्ड होंगे, जिनमें सभी टाइप का स्ट्रिंग होगा:
src/app/task/task.ts
export interface Task {
id?: string;
title: string;
description: string;
}
अब task.component.ts
को अपडेट करें. हम चाहते हैं कि TaskComponent
, Task
टाइप के ऑब्जेक्ट के इनपुट के तौर पर स्वीकार करे. साथ ही, हम चाहते हैं कि यह & &कोटेशनedit
&कोटेशन का आउटपुट दे:
src/app/task/task.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Task } from './task';
@Component({
selector: 'app-task',
templateUrl: './task.component.html',
styleUrls: ['./task.component.css']
})
export class TaskComponent {
@Input() task: Task | null = null;
@Output() edit = new EventEmitter<Task>();
}
TaskComponent
के टेंप्लेट में बदलाव करें! task.component.html
को खोलें और इसके कॉन्टेंट को नीचे दिए गए एचटीएमएल से बदलें:
src/app/task/task.component.html
<mat-card class="item" *ngIf="task" (dblclick)="edit.emit(task)">
<h2>{{ task.title }}</h2>
<p>
{{ task.description }}
</p>
</mat-card>
ध्यान दें कि हमें अब कंसोल में गड़बड़ियां मिल रही हैं:
'mat-card' is not a known element:
1. If 'mat-card' is an Angular component, then verify that it is part of this module.
2. If 'mat-card' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.ng
ऊपर दिए गए टेंप्लेट में हम '@angular/material
से mat-card
घटक का इस्तेमाल कर रहे हैं, लेकिन हमने ऐप्लिकेशन में उससे जुड़ा मॉड्यूल इंपोर्ट नहीं किया है. ऊपर से दी गई गड़बड़ी को ठीक करने के लिए, हमें AppModule
में MatCardModule
इंपोर्ट करना होगा:
src/app/app.module.ts
...
import { MatCardModule } from '@angular/material/card';
@NgModule({
declarations: [
AppComponent
],
imports: [
...
MatCardModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
इसके बाद, हम AppComponent
में कुछ टास्क बनाएंगे और उन्हें TaskComponent
का इस्तेमाल करके विज़ुअलाइज़ करेंगे!
AppComponent
में, todo
नाम की एक कैटगरी तय करें और इसमें दो टास्क जोड़ें:
src/app/app.component.ts
...
import { Task } from './task/task';
@Component(...)
export class AppComponent {
todo: Task[] = [
{
title: 'Buy milk',
description: 'Go to the store and buy milk'
},
{
title: 'Create a Kanban app',
description: 'Using Firebase and Angular create a Kanban app!'
}
];
}
अब, app.component.html
के नीचे यह *ngFor
निर्देश जोड़ें:
src/app/app.component.html
<app-task *ngFor="let task of todo" [task]="task"></app-task>
ब्राउज़र खोलने पर, आपको यह जानकारी दिखेगी:
5. टास्क के लिए, खींचें और छोड़ें की सुविधा को लागू करना
हम अब #39; मज़ेदार हिस्से के लिए तैयार हैं! आइए तीन अलग-अलग स्थितियों के लिए तीन तैराकी लेन-देन बनाते हैं. साथ ही, ऐंगुलर सीडीके का इस्तेमाल करके, खींचें और छोड़ें की सुविधा लागू करें.
app.component.html
में, app-task
कॉम्पोनेंट को सबसे ऊपर *ngFor
डायरेक्टिव से हटाएं और इसे इससे बदलें:
src/app/app.component.html
<div class="container-wrapper">
<div class="container">
<h2>Backlog</h2>
<mat-card
cdkDropList
id="todo"
#todoList="cdkDropList"
[cdkDropListData]="todo"
[cdkDropListConnectedTo]="[doneList, inProgressList]"
(cdkDropListDropped)="drop($event)"
class="list">
<p class="empty-label" *ngIf="todo.length === 0">Empty list</p>
<app-task (edit)="editTask('todo', $event)" *ngFor="let task of todo" cdkDrag [task]="task"></app-task>
</mat-card>
</div>
<div class="container">
<h2>In progress</h2>
<mat-card
cdkDropList
id="inProgress"
#inProgressList="cdkDropList"
[cdkDropListData]="inProgress"
[cdkDropListConnectedTo]="[todoList, doneList]"
(cdkDropListDropped)="drop($event)"
class="list">
<p class="empty-label" *ngIf="inProgress.length === 0">Empty list</p>
<app-task (edit)="editTask('inProgress', $event)" *ngFor="let task of inProgress" cdkDrag [task]="task"></app-task>
</mat-card>
</div>
<div class="container">
<h2>Done</h2>
<mat-card
cdkDropList
id="done"
#doneList="cdkDropList"
[cdkDropListData]="done"
[cdkDropListConnectedTo]="[todoList, inProgressList]"
(cdkDropListDropped)="drop($event)"
class="list">
<p class="empty-label" *ngIf="done.length === 0">Empty list</p>
<app-task (edit)="editTask('done', $event)" *ngFor="let task of done" cdkDrag [task]="task"></app-task>
</mat-card>
</div>
</div>
यहां बहुत कुछ #39 है. आइए, इस स्निपेट के अलग-अलग हिस्सों को सिलसिलेवार तरीके से देखते हैं. यह टेंप्लेट का टॉप-लेवल स्ट्रक्चर है:
src/app/app.component.html
...
<div class="container-wrapper">
<div class="container">
<h2>Backlog</h2>
...
</div>
<div class="container">
<h2>In progress</h2>
...
</div>
<div class="container">
<h2>Done</h2>
...
</div>
</div>
यहां हम div
बनाते हैं, जो तीनों तैराकी लेन्स को रैप करता है, जिसमें क्लास का नाम &कोटेशनcontainer-wrapper
होता है. हर कोट के पास एक क्लास का नाम &कोटेशन,container
&kot; और h2
टैग का एक शीर्षक होता है.
आइए, अब पहले तैराकी की संरचना पर नज़र डालें:
src/app/app.component.html
...
<div class="container">
<h2>Backlog</h2>
<mat-card
cdkDropList
id="todo"
#todoList="cdkDropList"
[cdkDropListData]="todo"
[cdkDropListConnectedTo]="[doneList, inProgressList]"
(cdkDropListDropped)="drop($event)"
class="list"
>
<p class="empty-label" *ngIf="todo.length === 0">Empty list</p>
<app-task (edit)="editTask('todo', $event)" *ngFor="let task of todo" cdkDrag [task]="task"></app-task>
</mat-card>
</div>
...
सबसे पहले, हम तैराकी के इलाके को mat-card
के तौर पर परिभाषित करते हैं, जो cdkDropList
डायरेक्टिव का इस्तेमाल करता है. इस कॉम्पोनेंट में मौजूद स्टाइल की वजह से, हम mat-card
का इस्तेमाल करते हैं. cdkDropList
में हम बाद में एलिमेंट के अंदर के टास्क छोड़ देंगे. हम यहां दिए गए दो इनपुट भी सेट करते हैं:
cdkDropListData
- ड्रॉप सूची का इनपुट, जो हमें डेटा अरे बताने की अनुमति देता हैcdkDropListConnectedTo
- मौजूदाcdkDropList
से जुड़े अन्यcdkDropList
के रेफ़रंस. इस इनपुट को सेट करके हम यह बताते हैं कि हम किन दूसरी सूचियों में आइटम छोड़ सकते हैं
इसके अलावा, हम cdkDropListDropped
आउटपुट का इस्तेमाल करके ड्रॉप इवेंट को मैनेज करना चाहते हैं. जब cdkDropList
यह आउटपुट देता है, तो हम AppComponent
में बताए गए drop
तरीके को चालू करते हैं और मौजूदा इवेंट को आर्ग्युमेंट के तौर पर पास करते हैं.
ध्यान दें कि हम इस कंटेनर के लिए, आइडेंटिफ़ायर के तौर पर इस्तेमाल करने के लिए id
, और class
का नाम भी तय करते हैं, ताकि हम इसे स्टाइल में ढाल सकें. अब mat-card
के बच्चों के कॉन्टेंट को देखते हैं. हमारे पास दो एलिमेंट हैं:
- एक पैराग्राफ़, जिसे हम
todo
सूची में कोई आइटम न होने पर &कोटेशन;खाली सूची&कोटेशन; टेक्स्ट दिखाने के लिए इस्तेमाल करते हैं app-task
कॉम्पोनेंट. ध्यान दें कि यहां हम':edit
आउटपुट को हैंडल कर रहे हैं, जिसका एलान हमने मूल रूप सेeditTask
तरीके को सूची और$event
ऑब्जेक्ट के नाम से कॉल करके किया था. इससे हमें बदलाव किए गए टास्क को सही सूची से बदलने में मदद मिलेगी. इसके बाद, हमने ऊपर बताई गईtodo
सूची को फिर से लागू किया है. साथ ही, हमtask
इनपुट को पास करते हैं. हालांकि, इस बार हमcdkDrag
डायरेक्टिव भी जोड़ते हैं. इससे हर टास्क को एक जगह से खींचकर दूसरी जगह ले जाया जा सकता है.
यह सभी काम करने के लिए, हमें app.module.ts
को अपडेट करना होगा और DragDropModule
में आयात शामिल करना होगा:
src/app/app.module.ts
...
import { DragDropModule } from '@angular/cdk/drag-drop';
@NgModule({
declarations: [
AppComponent
],
imports: [
...
DragDropModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
हमें editTask
और drop
के साथ-साथ, inProgress
और done
कैटगरी का भी एलान करना होगा:
src/app/app.component.ts
...
import { CdkDragDrop, transferArrayItem } from '@angular/cdk/drag-drop';
@Component(...)
export class AppComponent {
todo: Task[] = [...];
inProgress: Task[] = [];
done: Task[] = [];
editTask(list: string, task: Task): void {}
drop(event: CdkDragDrop<Task[]|null>): void {
if (event.previousContainer === event.container) {
return;
}
if (!event.container.data || !event.previousContainer.data) {
return;
}
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
ध्यान दें कि drop
तरीके में हम पहले यह जांचते हैं कि हम' उसी सूची में छोड़ रहे हैं या नहीं जिससे टास्क आ रहा है. अगर ऐसा है, तो हम तुरंत ही वापस लौट जाएंगे. ऐसा न करने पर, हम मौजूदा टास्क को डेस्टिनेशन स्विमिंग पूल में ट्रांसफ़र कर देते हैं.
नतीजा यह होना चाहिए:
इस समय आपको पहले से ही दोनों सूचियों के बीच आइटम स्थानांतरित करने में सक्षम होना चाहिए!
6. नए टास्क बनाना
अब, नए टास्क बनाने के लिए एक फ़ंक्शन का इस्तेमाल करें. इस उद्देश्य के लिए, AppComponent
का टेंप्लेट अपडेट करें:
src/app/app.component.html
<mat-toolbar color="primary">
...
</mat-toolbar>
<div class="content-wrapper">
<button (click)="newTask()" mat-button>
<mat-icon>add</mat-icon> Add Task
</button>
<div class="container-wrapper">
<div class="container">
...
</div>
</div>
हम container-wrapper
के आस-पास टॉप-लेवल का div
एलिमेंट बनाते हैं और &कोटेशनadd
और कोट; सामग्री वाले आइकॉन के साथ वाला बटन &कोटेशन जोड़ें.&कोटेशन का बटन जोड़ते हैं; बटन को तैराकी की सूची में सबसे ऊपर रखने के लिए हमें और रैपर चाहिए, जिसे हम फ़्लेक्सबॉक्स का इस्तेमाल करके एक-दूसरे के बगल में रखते हैं. यह बटन मटीरियल बटन कॉम्पोनेंट का इस्तेमाल करता है, इसलिए हमें AppModule
में इससे जुड़े मॉड्यूल को इंपोर्ट करना होगा:
src/app/app.module.ts
...
import { MatButtonModule } from '@angular/material/button';
@NgModule({
declarations: [
AppComponent
],
imports: [
...
MatButtonModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
अब, AppComponent
में काम जोड़ने के लिए, फ़ंक्शन की सुविधा लागू करें. हम कॉन्टेंट के डायलॉग का इस्तेमाल करेंगे. डायलॉग में हम'फ़ॉर्म में दो फ़ील्ड होंगे: शीर्षक और विवरण. जब उपयोगकर्ता &कोटेशन जोड़ें; कोटेशन दें बटन
आइए,AppComponent
में इस फ़ंक्शन को बेहतर तरीके से लागू करने के बारे में जानें:
src/app/app.component.ts
...
import { MatDialog } from '@angular/material/dialog';
@Component(...)
export class AppComponent {
...
constructor(private dialog: MatDialog) {}
newTask(): void {
const dialogRef = this.dialog.open(TaskDialogComponent, {
width: '270px',
data: {
task: {},
},
});
dialogRef
.afterClosed()
.subscribe((result: TaskDialogResult|undefined) => {
if (!result) {
return;
}
this.todo.push(result.task);
});
}
}
हम ऐसे कंस्ट्रक्टर का एलान करते हैं जिसमें MatDialog
क्लास इंजेक्ट करते हैं. newTask
में हम:
TaskDialogComponent
का इस्तेमाल करके एक नया डायलॉग खोलें, जिसे हम थोड़ी देर में तय करेंगे.- बताएं कि हम डायलॉग बॉक्स की चौड़ाई
270px.
रखना चाहते हैं - खाली टास्क को डायलॉग के तौर पर डेटा के तौर पर पास करें.
TaskDialogComponent
में हम #33 इस डेटा ऑब्जेक्ट का रेफ़रंस पा सकेंगे. - हम क्लोज़ इवेंट की सदस्यता लेते हैं और
result
ऑब्जेक्ट सेtodo
अरे में टास्क जोड़ते हैं.
यह पक्का करने के लिए, हमें पहले AppModule
में MatDialogModule
इंपोर्ट करना होगा:
src/app/app.module.ts
...
import { MatDialogModule } from '@angular/material/dialog';
@NgModule({
declarations: [
AppComponent
],
imports: [
...
MatDialogModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
अब TaskDialogComponent
को बनाएं. src/app
डायरेक्ट्री पर जाएं और चलाएं:
ng generate component task-dialog
इसके फ़ंक्शन को लागू करने के लिए: src/app/task-dialog/task-dialog.component.html
खोलें और इसकी सामग्री को इनमें से बदलें:
src/app/task-dialog/task-dialog.component.html
<mat-form-field>
<mat-label>Title</mat-label>
<input matInput cdkFocusInitial [(ngModel)]="data.task.title" />
</mat-form-field>
<mat-form-field>
<mat-label>Description</mat-label>
<textarea matInput [(ngModel)]="data.task.description"></textarea>
</mat-form-field>
<div mat-dialog-actions>
<button mat-button [mat-dialog-close]="{ task: data.task }">OK</button>
<button mat-button (click)="cancel()">Cancel</button>
</div>
ऊपर दिए गए टेंप्लेट में हम title
और description
के लिए दो फ़ील्ड वाला एक फ़ॉर्म बनाते हैं. जब उपयोगकर्ता डायलॉग खोलता है, तो हम cdkFocusInput
निर्देश का इस्तेमाल अपने-आप title
फ़ोकस में लाने के लिए करते हैं.
ध्यान दें कि हम टेंप्लेट के अंदर कॉम्पोनेंट की data
प्रॉपर्टी का रेफ़रंस कैसे देते हैं. यह वही data
होगा जिसे हम AppComponent
में dialog
के open
तरीके को पास करते हैं. जब उपयोगकर्ता, फ़ील्ड के साथ काम करने वाले फ़ील्ड का कॉन्टेंट बदलता है, तो हम ngModel
के साथ दो-तरफ़ा डेटा बाइंडिंग का इस्तेमाल करते हैं. इससे, शीर्षक और जानकारी में बदलाव किया जा सकता है.
जब उपयोगकर्ता 'ठीक है' बटन पर क्लिक करता है, तब हम अपने-आप { task: data.task }
नतीजे दिखाते हैं. यह वह टास्क है जिसे हमने ऊपर दिए गए टेंप्लेट के फ़ॉर्म फ़ील्ड का इस्तेमाल करके बदला है.
अब, आइए कॉम्पोनेंट का कंट्रोलर लागू करते हैं:
src/app/task-dialog/task-dialog.component.ts
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Task } from '../task/task';
@Component({
selector: 'app-task-dialog',
templateUrl: './task-dialog.component.html',
styleUrls: ['./task-dialog.component.css'],
})
export class TaskDialogComponent {
private backupTask: Partial<Task> = { ...this.data.task };
constructor(
public dialogRef: MatDialogRef<TaskDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: TaskDialogData
) {}
cancel(): void {
this.data.task.title = this.backupTask.title;
this.data.task.description = this.backupTask.description;
this.dialogRef.close(this.data);
}
}
TaskDialogComponent
में हम डायलॉग का रेफ़रंस इंजेक्ट करते हैं, ताकि हम उसे बंद कर सकें. साथ ही, हम MAT_DIALOG_DATA
टोकन से जुड़ी सेवा देने वाली कंपनी की वैल्यू भी इंजेक्ट कर सकते हैं. यह वह डेटा ऑब्जेक्ट है जिसे हमने ऊपर AppComponent
में ओपन मेथड में पास किया था. हम निजी प्रॉपर्टी backupTask
का भी एलान करते हैं, जो उस डेटा की कॉपी है जिसे हमने डेटा ऑब्जेक्ट के साथ पास किया था.
जब उपयोगकर्ता 'रद्द करें' बटन दबाता है, तो हम this.data.task
की उन प्रॉपर्टी को भी बदल देते हैं जो शायद बदल गई हैं. ऐसा करने पर, हम this.data
से नतीजे के तौर पर पास होने वाले डायलॉग को बंद कर देंगे.
हमने दो तरह के रेफ़रंस दिए हैं, लेकिन वे अभी तक ##39 नहीं बता पाए - TaskDialogData
और TaskDialogResult
. src/app/task-dialog/task-dialog.component.ts
के अंदर इन एलानों को फ़ाइल के नीचे जोड़ें:
src/app/task-dialog/task-dialog.component.ts
...
export interface TaskDialogData {
task: Partial<Task>;
enableDelete: boolean;
}
export interface TaskDialogResult {
task: Task;
delete?: boolean;
}
फ़ंक्शन तैयार होने से पहले, हमें AppModule
में कुछ मॉड्यूल इंपोर्ट करने होंगे!
src/app/app.module.ts
...
import { MatInputModule } from '@angular/material/input';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent
],
imports: [
...
MatInputModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
जब आप अभी &कोटेशन जोड़ें;कोटेशन जोड़ें बटन पर क्लिक करें, तो आपको यह यूज़र इंटरफ़ेस दिखेगा:
7. ऐप्लिकेशन के स्टाइल को बेहतर बनाना
हम ऐप्लिकेशन को और आकर्षक बनाने के लिए, इसके लेआउट में थोड़ा बदलाव करके, इसके लेआउट को बेहतर बना रहे हैं. हम स्विम लेन्स को एक-दूसरे के बगल में रखना चाहते हैं. हम &कीवर्ड का छोटा सा समायोजन भी करना चाहते हैं; &कार्य टैब जोड़ें बटन और खाली सूची लेबल.
src/app/app.component.css
खोलें और नीचे दिए गए स्टाइल को नीचे जोड़ें:
src/app/app.component.css
mat-toolbar {
margin-bottom: 20px;
}
mat-toolbar > span {
margin-left: 10px;
}
.content-wrapper {
max-width: 1400px;
margin: auto;
}
.container-wrapper {
display: flex;
justify-content: space-around;
}
.container {
width: 400px;
margin: 0 25px 25px 0;
}
.list {
border: solid 1px #ccc;
min-height: 60px;
border-radius: 4px;
}
app-new-task {
margin-bottom: 30px;
}
.empty-label {
font-size: 2em;
padding-top: 10px;
text-align: center;
opacity: 0.2;
}
ऊपर दिए गए स्निपेट में, हम टूलबार के लेआउट और उसके लेबल को एडजस्ट करते हैं. हम यह भी पक्का करते हैं कि कॉन्टेंट को चौड़ाई में 1400px
पर सेट किया गया हो और इसके मार्जिन को auto
पर सेट किया गया हो. इसके बाद, फ़्लेक्सबॉक्स का इस्तेमाल करके, हम एक-दूसरे के बगल में स्विम लेन डालते हैं. साथ ही, टास्क और खाली सूचियों को दिखाने के तरीके में कुछ बदलाव करते हैं.
ऐप्लिकेशन फिर से लोड होने के बाद, आपको यह यूज़र इंटरफ़ेस दिखेगा:
हालांकि, हमने अपने ऐप्लिकेशन के
जब हम &कोटेशन को खींचना शुरू करते हैं, तब हम एक ही टास्क के लिए दो कार्ड बनाते हैं - पहला, हम खींचें और छोड़ें. साथ ही, दूसरे को तैराकी के रास्ते पर छोड़ दें. Angular CDK हमें सीएसएस क्लास के नाम देता है, जिनका इस्तेमाल करके हम इस समस्या को ठीक कर सकते हैं.
नीचे दिए गए स्टाइल को src/app/app.component.css
के नीचे जोड़ें:
src/app/app.component.css
.cdk-drag-animating {
transition: transform 250ms;
}
.cdk-drag-placeholder {
opacity: 0;
}
जब हम किसी एलिमेंट को खींचते हैं, तो Angular CDK's क्लोन खींचें और छोड़ें और इसे उस जगह पर डाल दें जहां हम मूल इमेज को छोड़ना चाहते हैं. यह एलिमेंट नहीं दिख रहा है, यह पक्का करने के लिए हम cdk-drag-placeholder
क्लास में ओपैसिटी प्रॉपर्टी सेट करते हैं, जिसे सीडीके प्लेसहोल्डर में जोड़ने जा रहा है.
साथ ही, जब हम किसी एलिमेंट को छोड़ते हैं, तो सीडीके cdk-drag-animating
क्लास जोड़ता है. एलिमेंट को सीधे स्नैप करने के बजाय स्मूद ऐनिमेशन दिखाने के लिए, हम ट्रांज़िशन के लिए एक 250ms
तय करते हैं.
हम अपने टास्क के स्टाइल में भी कुछ छोटे-मोटे बदलाव करना चाहते हैं. task.component.css
में होस्ट होस्ट एलिमेंट's को block
पर सेट करें और कुछ मार्जिन सेट करें:
src/app/task/task.component.css
:host {
display: block;
}
.item {
margin-bottom: 10px;
cursor: pointer;
}
8. मौजूदा टास्क में बदलाव करना और उन्हें मिटाना
मौजूदा टास्क को हटाने और उनमें बदलाव करने के लिए, हम उनमें से ज़्यादातर फ़ंक्शन को दोबारा इस्तेमाल कर रहे हैं! जब उपयोगकर्ता किसी टास्क पर दो बार क्लिक करता है, तो हम TaskDialogComponent
को खोलते हैं और फ़ॉर्म में दो फ़ील्ड के टास्क और #39; title
और description
में अपने-आप जानकारी भर देते हैं.
TaskDialogComponent
में हम यूआरएल #39; हटाएं बटन भी जोड़ेंगे. जब उपयोगकर्ता इस पर क्लिक करेगा, तब हम'मिटाने के निर्देश को पास करेगा, जो AppComponent
पर खत्म होगा.
TaskDialogComponent
में हमें सिर्फ़ अपने टेंप्लेट में बदलाव करना होगा:
src/app/task-dialog/task-dialog.component.html
<mat-form-field>
...
</mat-form-field>
<div mat-dialog-actions>
...
<button
*ngIf="data.enableDelete"
mat-fab
color="primary"
aria-label="Delete"
[mat-dialog-close]="{ task: data.task, delete: true }">
<mat-icon>delete</mat-icon>
</button>
</div>
यह बटन मिटाएं सामग्री का आइकॉन दिखाता है. जब उपयोगकर्ता इस पर क्लिक करता है, तब हम डायलॉग बॉक्स को बंद कर देते हैं और नतीजे के तौर पर { task: data.task, delete: true }
लिटरल ऑब्जेक्ट को पास करते हैं. यह भी ध्यान रखें कि हम mat-fab
का इस्तेमाल करके बटन को गोलाकार बनाते हैं, इसका रंग प्राइमरी के तौर पर सेट करते हैं, और सिर्फ़ तब दिखाते हैं, जब डायलॉग डेटा को मिटाया जाता है.
बदलाव करने और मिटाने की सुविधाएं बाकी AppComponent
में लागू होती हैं. अपने editTask
तरीके को नीचे दिए गए तरीके से बदलें:
src/app/app.component.ts
@Component({ ... })
export class AppComponent {
...
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|undefined) => {
if (!result) {
return;
}
const dataList = this[list];
const taskIndex = dataList.indexOf(task);
if (result.delete) {
dataList.splice(taskIndex, 1);
} else {
dataList[taskIndex] = task;
}
});
}
...
}
editTask
मेथड के आर्ग्युमेंट देखें:
'done' | 'todo' | 'inProgress',
टाइप की सूची, जो अलग-अलग तैराकी के साथ जुड़ी प्रॉपर्टी से जुड़ी वैल्यू वाला स्ट्रिंग लिटरल टाइप है.- मौजूदा टास्क में हम बदलाव करना चाहते हैं.
मेथड' के मुख्य हिस्से में, हम पहले TaskDialogComponent
का एक इंस्टेंस खोलते हैं. data
जैसे ही हम एक ऑब्जेक्ट लिटरल पास करते हैं, जो उस टास्क के बारे में बताता है जिसमें हम बदलाव करना चाहते हैं. साथ ही, यह enableDelete
प्रॉपर्टी को true
पर सेट करके फ़ॉर्म में बदलाव करें बटन को भी चालू करता है.
जब हमें डायलॉग से नतीजा मिलता है, तो हम दो स्थितियों को हैंडल करते हैं:
- जब
delete
फ़्लैगtrue
पर सेट होता है (यानी, जब उपयोगकर्ता मिटाएं बटन दबाता है), तो हम टास्क को उससे जुड़ी सूची से हटा देते हैं. - इसके अलावा, हम दिए गए इंडेक्स के टास्क को सिर्फ़ उस टास्क से बदल देते हैं जो हमें डायलॉग नतीजे में मिला है.
9. नया Firebase प्रोजेक्ट बनाना
अब, एक नया Firebase प्रोजेक्ट बनाएं!
- Firebase कंसोल पर जाएं.
- "KanbanFire" नाम के साथ एक नया प्रोजेक्ट बनाएं.
10. प्रोजेक्ट में Firebase जोड़ना
इस सेक्शन में हम Firebase के साथ अपना प्रोजेक्ट इंटिग्रेट करेंगे! Firebase टीम @angular/fire
पैकेज ऑफ़र करती है, जो इन दो टेक्नोलॉजी के बीच इंटिग्रेशन की सुविधा देती है. अपने ऐप्लिकेशन में Firebase सहायता जोड़ने के लिए, अपने फ़ाइल फ़ोल्डर की रूट डायरेक्ट्री खोलें और चलाएं:
ng add @angular/fire
यह निर्देश, @angular/fire
पैकेज इंस्टॉल करता है और आपसे कुछ सवाल पूछता है. अपने टर्मिनल में, आपको कुछ ऐसा दिखेगा:
इस दौरान, इंस्टॉलेशन ब्राउज़र विंडो खोलता है, ताकि आप अपने Firebase खाते से पुष्टि कर सकें. आखिर में, आपको Firebase प्रोजेक्ट चुनने और आपकी डिस्क पर कुछ फ़ाइलें बनाने के लिए कहा जाता है.
इसके बाद, हमें Firestore डेटाबेस बनाना होगा! & तरह का &Cloud Firestore;कोटेशन करें; क्लिक करें;डेटाबेस बनाएं.&कोटेशन;
इसके बाद, टेस्ट मोड में डेटाबेस बनाएं:
आखिर में, कोई इलाका चुनें:
अब बस आपको Firebase को अपने एनवायरमेंट में जोड़ना है. आप अपने प्रोजेक्ट कॉन्फ़िगरेशन को Firebase कंसोल में देख सकते हैं.
- प्रोजेक्ट की खास जानकारी के आगे दिए गए गियर आइकॉन पर क्लिक करें.
- प्रोजेक्ट सेटिंग चुनें.
&अपने कोटेशन में जाकर, किसी &वेब ऐप्लिकेशन को चुनें;
इसके बाद, अपना ऐप्लिकेशन रजिस्टर करें और पक्का करें कि आपने &Firebase होस्टिंग&कोटेशन चालू किया हो:
&कोटेशन;ऐप्लिकेशन रजिस्टर करें&t> पर क्लिक करने के बाद, आप अपना कॉन्फ़िगरेशन src/environments/environment.ts
में कॉपी कर सकते हैं:
आखिर में, आपकी कॉन्फ़िगरेशन फ़ाइल कुछ ऐसी दिखनी चाहिए:
src/environments/environment.ts
export const environment = {
production: false,
firebase: {
apiKey: '<your-key>',
authDomain: '<your-project-authdomain>',
databaseURL: '<your-database-URL>',
projectId: '<your-project-id>',
storageBucket: '<your-storage-bucket>',
messagingSenderId: '<your-messaging-sender-id>'
}
};
11. डेटा को Firestore में ले जाना
अब जब हमने ##39;Firebase SDK टूल को सेट अप कर लिया है, तो हमें #39; @angular/fire
का इस्तेमाल करके, हमारे डेटा को Firestore में ले जाने दें! सबसे पहले, आइए AppModule
में उन मॉड्यूल को इंपोर्ट करें जिनकी हमें ज़रूरत है:
src/app/app.module.ts
...
import { environment } from 'src/environments/environment';
import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore';
@NgModule({
declarations: [AppComponent, TaskDialogComponent, TaskComponent],
imports: [
...
AngularFireModule.initializeApp(environment.firebase),
AngularFirestoreModule
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
हम Firestore का इस्तेमाल कर रहे हैं, इसलिए हमें AppComponent
's कंस्ट्रक्टर में AngularFirestore
इंजेक्ट करना होगा:
src/app/app.component.ts
...
import { AngularFirestore } from '@angular/fire/firestore';
@Component({...})
export class AppComponent {
...
constructor(private dialog: MatDialog, private store: AngularFirestore) {}
...
}
इसके बाद, हम स्विमलैन श्रेणियों को शुरू करने के तरीके को अपडेट करते हैं:
src/app/app.component.ts
...
@Component({...})
export class AppComponent {
todo = this.store.collection('todo').valueChanges({ idField: 'id' }) as Observable<Task[]>;
inProgress = this.store.collection('inProgress').valueChanges({ idField: 'id' }) as Observable<Task[]>;
done = this.store.collection('done').valueChanges({ idField: 'id' }) as Observable<Task[]>;
...
}
यहां सीधे AngularFirestore
संग्रह और#39; का कॉन्टेंट, डेटाबेस से पाने के लिए इस्तेमाल किया जाता है. ध्यान दें कि valueChanges
से कैटगरी की बजाय ऑब्ज़र्व किया जा सकने वाला मिलता है. साथ ही, हम यह भी बताते हैं कि इस कलेक्शन में दस्तावेज़ों के लिए आईडी फ़ील्ड को id
नाम दिया जाना चाहिए, ताकि उसका इस्तेमाल Task
इंटरफ़ेस में किया जा सके. valueChanges
के निगरानी में रखे गए ऑब्ज़र्व किए गए टास्क में, किसी भी समय बदलाव करने पर टास्क का कलेक्शन होता है.
हम श्रेणियों के बजाय ऑब्ज़र्व किए जा सकने वाले तरीके पर काम कर रहे हैं, इसलिए हमें टास्क जोड़ने, हटाने, और उनमें बदलाव करने के तरीके को अपडेट करना होगा. साथ ही, हमें स्विच के बीच टास्क को एक जगह से दूसरी जगह ले जाने के फ़ंक्शन को भी अपडेट करना होगा. अपनी इन-मेमोरी श्रेणियों में बदलाव करने के बजाय, हम डेटाबेस में डेटा को अपडेट करने के लिए Firebase SDK टूल का इस्तेमाल करेंगे.
सबसे पहले, आइए देखते हैं कि फिर से क्रम में लगाने का तरीका कैसा होता है. src/app/app.component.ts
में drop
वाला तरीका बदलें:
src/app/app.component.ts
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
);
}
ऊपर दिए गए स्निपेट में, नया कोड हाइलाइट कर दिया गया है. किसी टास्क को मौजूदा स्विम लेन से टारगेट में ले जाने के लिए, हम टास्क को पहले कलेक्शन से हटाकर, दूसरे कलेक्शन में जोड़ देते हैं. हम दो तरह के काम करते हैं जिन्हें हम एक जैसा देखना चाहते हैं (जैसे कि ऑपरेशन को परमाणु बनाना). इसलिए, हम उन्हें Firestore लेन-देन में चलाते हैं.
इसके बाद, चलिए editTask
Firestore का इस्तेमाल करने का तरीका अपडेट करते हैं! बंद डायलॉग हैंडलर के अंदर, हमें कोड की इन पंक्तियों को बदलना होगा:
src/app/app.component.ts
...
dialogRef.afterClosed().subscribe((result: TaskDialogResult|undefined) => {
if (!result) {
return;
}
if (result.delete) {
this.store.collection(list).doc(task.id).delete();
} else {
this.store.collection(list).doc(task.id).update(task);
}
});
...
हम उस टास्क से जुड़े टारगेट दस्तावेज़ को ऐक्सेस करते हैं, जिसे हम Firestore SDK का इस्तेमाल करके बदलते हैं. साथ ही, हम इसे मिटा देते हैं या इसे अपडेट कर देते हैं.
आखिर में, हमें नए टास्क बनाने के तरीके को अपडेट करना होगा. this.todo.push('task')
को this.store.collection('todo').add(result.task)
से बदलें.
ध्यान दें कि हमारे कलेक्शन अब कैटगरी नहीं हैं, बल्कि निगरानी किए जा सकते हैं. उन्हें विज़ुअलाइज़ करने के लिए हमें AppComponent
के टेम्प्लेट को अपडेट करना होगा. बस todo
, inProgress
, और done
प्रॉपर्टी के हर ऐक्सेस को todo | async
, inProgress | async
, और done | async
से बदलें.
एक साथ काम नहीं करने वाली पाइप, अपने-आप कलेक्शन से जुड़ी निगरानी में रखे गए डिवाइस की सदस्यता लेती है. जब ऑब्ज़र्व किया जा सकने वाला कोई नया मान बनाता है, तो Angular बदलाव की पहचान अपने-आप कर लेता है और दूसरी श्रेणी में ले जाता है.
उदाहरण के लिए, आइए देखते हैं कि todo
स्विम लेन-देन में हमें किस तरह के बदलाव करने होंगे:
src/app/app.component.html
<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>
जब हम cdkDropList
डायरेक्टिव को डेटा पास करते हैं, तो हम एसिंक पाइप लागू करते हैं. यह *ngIf
डायरेक्टिव में एक जैसा ही है. हालांकि, ध्यान रखें कि हम length
प्रॉपर्टी को ऐक्सेस करते समय, वैकल्पिक चेन (जिसे Angular में सुरक्षित नेविगेशन ऑपरेटर भी कहा जाता है) का भी इस्तेमाल करते हैं. ऐसा इसलिए, ताकि todo | async
या null
न होने पर, हमें रनटाइम की गड़बड़ी न मिले.
अब जब आप यूज़र इंटरफ़ेस में नया टास्क बनाएंगे और Firestore खोलें, तो आपको कुछ ऐसा दिखेगा:
12. सकारात्मक अपडेट में सुधार करना
ऐप्लिकेशन में फ़िलहाल हम अपडेट से जुड़े अपडेट कर रहे हैं. हमारे पास Firestore में सच्चाई का स्रोत है, लेकिन साथ ही, हमारे पास टास्क की स्थानीय कॉपी होती हैं; जब संग्रह से जुड़े किसी भी निगरानी वाले काम शुरू होते हैं, तो हमें कई तरह के टास्क मिलते हैं. जब कोई उपयोगकर्ता कार्रवाई, स्थिति में बदलाव करती है, तब हम पहले स्थानीय मानों को अपडेट करते हैं. इसके बाद, बदलावों को Firestore में लागू करते हैं.
जब हम किसी एक स्विम लेन-देन को दूसरे में ले जाते हैं, तो हम हर तैराकी समूह में काम को दिखाने वाली श्रेणियों के स्थानीय इंस्टेंस पर काम करने वाले transferArrayItem,
को शुरू करते हैं. Firebase SDK टूल इन श्रेणियों को बदला नहीं जा सकता. इसका मतलब है कि अगली बार जब Angular बदलाव का पता लगाएगा, तब हम #{0/}
साथ ही, हम Firestore अपडेट को ट्रिगर करते हैं और Firebase SDK टूल सही वैल्यू वाले अपडेट को ट्रिगर करता है, इसलिए कुछ मिलीसेकंड में यूज़र इंटरफ़ेस अपनी सही स्थिति पर पहुंच जाएगा. इससे, वह टास्क ट्रांसफ़र हो जाता है जिसे हमने पहली सूची से अगली सूची पर भेजा. आप नीचे दिए गए GIF पर इसे अच्छी तरह से देख सकते हैं:
इस समस्या को हल करने का सही तरीका हर ऐप्लिकेशन के लिए अलग-अलग होता है, लेकिन सभी मामलों में हमें यह पक्का करना होगा कि जब तक हमारा डेटा अपडेट नहीं हो जाता, तब तक हम एक ही स्थिति बनाए रखते हैं.
हम BehaviorSubject
का फ़ायदा ले सकते हैं, जो हमें valueChanges
से मिलने वाले मूल ऑब्ज़र्वर को रैप कर देता है. हुड के तहत, BehaviorSubject
एक बदली जा सकने वाली श्रेणी रखता है जो transferArrayItem
से अपडेट रहता है.
समाधान लागू करने के लिए, हमें बस AppComponent
को अपडेट करना होगा:
src/app/app.component.ts
...
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { BehaviorSubject } from 'rxjs';
const getObservable = (collection: AngularFirestoreCollection<Task>) => {
const subject = new BehaviorSubject<Task[]>([]);
collection.valueChanges({ idField: 'id' }).subscribe((val: Task[]) => {
subject.next(val);
});
return subject;
};
@Component(...)
export class AppComponent {
todo = getObservable(this.store.collection('todo')) as Observable<Task[]>;
inProgress = getObservable(this.store.collection('inProgress')) as Observable<Task[]>;
done = getObservable(this.store.collection('done')) as Observable<Task[]>;
...
}
ऊपर दिए गए स्निपेट में हम सिर्फ़ BehaviorSubject
बनाते हैं. ऐसा करने से, कलेक्शन में होने वाले हर बदलाव की निगरानी करने से, एक वैल्यू बनती है.
सब कुछ उम्मीद के मुताबिक है, क्योंकि BehaviorSubject
बदलाव का पता लगाने वाले शुरू होने पर श्रेणी को दोबारा इस्तेमाल करता है और सिर्फ़ तब अपडेट होता है, जब हमें Firestore से नया मान मिलता है.
13. ऐप्लिकेशन को डिप्लॉय किया जा रहा है
अपने ऐप्लिकेशन को डिप्लॉय करने के लिए, हमें बस इतना करना है:
ng deploy
यह निर्देश:
- अपने ऐप्लिकेशन को प्रोडक्शन कॉन्फ़िगरेशन के साथ बनाएं, कंपाइल-टाइम ऑप्टिमाइज़ेशन लागू करें.
- अपने ऐप्लिकेशन को Firebase होस्टिंग के लिए डिप्लॉय करें.
- यूआरएल का आउटपुट पाएं, ताकि आप नतीजे की झलक देख सकें.
14. बधाई हो
बधाई हो, आपने Angular और Firebase के साथ एक कंबान बोर्ड बनाया है!
आपने तीन कॉलम की मदद से एक यूज़र इंटरफ़ेस बनाया है, जिसमें अलग-अलग टास्क की स्थिति दिखाई गई है. Angular CDK का इस्तेमाल करके, आपने पूरे कॉलम में टास्क को खींचकर छोड़ा है. फिर, ऐंगुलर सामग्री का इस्तेमाल करके आपने नए टास्क बनाने और मौजूदा टास्क में बदलाव करने के लिए एक फ़ॉर्म बनाया. इसके बाद, आपने @angular/fire
का इस्तेमाल करने और सभी ऐप्लिकेशन स्टेट को Firestore में ले जाने का तरीका सीखा. आखिर में, आपने अपने ऐप्लिकेशन को Firebase होस्टिंग के लिए डिप्लॉय किया.
आगे क्या होगा?
याद रखें कि हमने टेस्ट कॉन्फ़िगरेशन का इस्तेमाल करके ऐप्लिकेशन डिप्लॉय किया है. अपने ऐप्लिकेशन को प्रोडक्शन में डिप्लॉय करने से पहले पक्का करें कि आपने सही अनुमतियां सेट की हैं. ऐसा करने का तरीका यहां जानें.
फ़िलहाल, हम किसी खास स्विम लेन में अलग-अलग टास्क का क्रम सुरक्षित नहीं रखते हैं. इसे लागू करने के लिए, आप टास्क के दस्तावेज़ में ऑर्डर फ़ील्ड का इस्तेमाल कर सकते हैं और उसके हिसाब से क्रम तय कर सकते हैं.
इसके अलावा, हमने सिर्फ़ एक उपयोगकर्ता के लिए कंबान बोर्ड बनाया है. इसका मतलब है कि ऐप्लिकेशन खोलने वाले किसी भी व्यक्ति के लिए एक कंबन बोर्ड है. अपने ऐप्लिकेशन के अलग-अलग उपयोगकर्ताओं के लिए अलग-अलग बोर्ड लागू करने के लिए, आपको अपने डेटाबेस की संरचना बदलनी होगी. Firestore के #सबसे सही तरीकों के बारे में यहां जानें.