Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,258 changes: 14,258 additions & 0 deletions code-snapshots/06-cmp-deep-dive/18-two-way-binding-repetition/package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@


<app-header />

<main>
<div id="dashboard">
<app-dashboard-item
[image]="{ src: 'status.png', alt: 'A signal symbol' }"
title="Server Status"
>
>
<app-server-status />
</app-dashboard-item>

Expand All @@ -24,3 +26,4 @@
</app-dashboard-item>
</div>
</main>

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { DashboardItemComponent } from './dashboard/dashboard-item/dashboard-ite
selector: 'app-root',
standalone: true,
imports: [
HeaderComponent,
HeaderComponent, // komponenti header eshte standalone: true, mjafton vetem ta inportosh, por edhe nese do kishim @NgModule dhe komponenti do ishte standalone: true, thjesht na duhesh ta inportonim.
ServerStatusComponent,
TrafficComponent,
TicketsComponent,
Expand All @@ -19,3 +19,4 @@ import { DashboardItemComponent } from './dashboard/dashboard-item/dashboard-ite
templateUrl: './app.component.html',
})
export class AppComponent {}

Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
:host {

/* :host { } -> perfaqeson gjith komponenin ne teresi */

:host { /* The styles inside this block apply to the host element of the DashboardItemComponent. */
display: block;
padding: 1rem;
border: 1px solid #ccc;
Expand All @@ -7,14 +10,15 @@
box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.2);
}

/* This targets the header element inside your component, aligning its content (image and title) horizontally using flexbox */
:host header {
display: flex;
padding: 0;
gap: 0.75rem;
align-items: center;
margin-bottom: 1rem;
}

:host header img {
width: 1.5rem;
height: 1.5rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<img [src]="image().src" [alt]="image().alt" />
<h2>{{ title() }}</h2>
</header>
<!-- shtojme ng-content sepse brenda <app-dashboard-item > .... </app-dashboard-item> ne app.component.html permbajme vlera si: <app-server-status />, <app-traffic />, <app-tickets /> -->
<ng-content />
</article>
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ import { Component, Input, input } from '@angular/core';
// }
})
export class DashboardItemComponent {

// marim input nga app.compoent.html

// @Input({required: true}) image!: { src: string; alt: string };
// @Input({required: true}) title!: string;
image = input.required<{ src: string; alt: string }>();
title = input.required<string>();
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,25 @@
'status-offline': currentStatus() === 'offline',
'status-unknown': currentStatus() === 'unknown'
}" >

<!-- status-online , status-offline dhe status-unknown jan klasa ne css, ku ndryshojme gjyrat sipas kushtin random
qe na vjen nga ts, e njetja gje eshte edhe me @if, @else if, @else -->

@if (currentStatus() === 'online') {

<p>Servers are online</p>
<p>All systems are operational.</p>

} @else if (currentStatus() === 'offline') {

<p>Servers are offline</p>
<p>Functionality should be restored soon.</p>

} @else {

<p>Server status is unknown</p>
<p>Fetching server status failed.</p>

}
</div>

Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,31 @@ import {
styleUrl: './server-status.component.css',
})
export class ServerStatusComponent implements OnInit {
currentStatus = signal<'online' | 'offline' | 'unknown'>('offline');
private destroyRef = inject(DestroyRef);
// krijojme ne string signal me 3 kushte ku gjendja e tij fillestare eshte 'offline'
currentStatus = signal<'online' | 'offline' | 'unknown'>('offline'); // signal eshte i ngjashem si subjet ne librarin rxjs

// pra therasim nje funkson si cili theret funksonet brenda ketit komponentet edhe kur angulari eshte i fokusuar ne
// komponentet te tjere, pershembull jemi te komponenti app-tickets duke krijuar nje ticket, DestroyRef te ky komponent
// vazhdon i mundeson angularit te therasi funksonet brenda komponetit ServerStatusComponent edhe pa qen user
// prezen ne te.

private destroyRef = inject(DestroyRef);
// What "Destroyed" Means:
// For example, if your component is used in a certain route, and the user navigates to another route, Angular will destroy
// the component. This means your interval will be cleared, thanks to the clearInterval call inside onDestroy. Without this,
// the interval would continue running even though the component is no longer visible, potentially causing memory leaks or
// unwanted behavior.

constructor() {
effect(() => {
console.log(this.currentStatus());
// console.log(this.currentStatus());
});
}
}

ngOnInit() {
console.log('ON INIT');
const interval = setInterval(() => {

const interval = setInterval(() => { // funksoni e lejon kodin te lexoj mbas 5 sekondash

const rnd = Math.random(); // 0 - 0.99999999999999

if (rnd < 0.5) {
Expand All @@ -39,7 +52,7 @@ export class ServerStatusComponent implements OnInit {
}
}, 5000);

this.destroyRef.onDestroy(() => {
this.destroyRef.onDestroy(() => { // therasim funksjonin ne pafundesi cdo 5 sekonda te cilat permbajne vlera random, pasi mbaron ciklin
clearInterval(interval);
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
<form (ngSubmit)="onSubmit()" #form>

<app-control label="Title">
<input
name="title"
id="title"
#input
[(ngModel)]="enteredTitle"

/>
</app-control>

<app-control label="Request">
<textarea
name="request"
id="request"
id="request"
rows="3"
#input
#textarea
[(ngModel)]="enteredText"
></textarea>
</app-control>

<!-- <p> {{ textarea.value }} </p> -->
<p>
<button appButton>

<button app-Button-in-new-ticket type="submit">
Submit
<span ngProjectAs="icon">⌲</span>
<!-- ngProjectAs="icon" perfaqeson <ng-content select="icon" /> ne button.component.html e cila lecon klasen icon ne css. -->
<span ngProjectAs="icon">⌲</span>
</button>
</p>
</form>

Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,54 @@ import { ButtonComponent } from '../../../shared/button/button.component';
import { ControlComponent } from '../../../shared/control/control.component';

@Component({
selector: 'app-new-ticket',
selector: 'app-new-ticket',
standalone: true,
templateUrl: './new-ticket.component.html',
styleUrl: './new-ticket.component.css',
imports: [ButtonComponent, ControlComponent, FormsModule],
})
export class NewTicketComponent implements OnInit, AfterViewInit {
@ViewChild('form') private form?: ElementRef<HTMLFormElement>;

// private form = viewChild.required<ElementRef<HTMLFormElement>>('form');
// @Output() add = new EventEmitter<{title: string; text: string}>();
@ViewChild('form') private form?: ElementRef<HTMLFormElement>;
@ViewChild('input') private input?: ElementRef<HTMLInputElement>;
@ViewChild('textarea') private textarea?: ElementRef<HTMLTextAreaElement>;

enteredTitle = '';
enteredText = '';
enteredText = '';

// @Output() add = new EventEmitter<{title: string; text: string}>();
add = output<{ title: string; text: string }>();

ngOnInit() {
console.log('ONINIT');
console.log(this.form?.nativeElement);
console.log('ONINIT --> this.form?.nativeElement', this.form?.nativeElement);
}

ngAfterViewInit() {
console.log('AFTER VIEW INIT');
console.log(this.form?.nativeElement);
console.log( 'AFTER VIEW INIT --> this.form?.nativeElement', this.form?.nativeElement);

if (this.input) { // marim vlera nga input title
console.log('Title input value:', this.input.nativeElement.value);
}

if (this.textarea) { // marim vlerat nga textaare request
console.log('Request textarea value:', this.textarea.nativeElement.value);
}
}

onSubmit() {
this.add.emit({ title: this.enteredTitle, text: this.enteredText });
// this.form?.nativeElement.reset();
if (this.form?.nativeElement.checkValidity()) {
this.add.emit({ title: this.enteredTitle, text: this.enteredText });
this.resetForm();
} else {
console.log('Form is not valid');
}
}

private resetForm() {
this.enteredTitle = '';
this.enteredText = '';
this.form?.nativeElement.reset(); // Reset the form programmatically
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ <h3>
stroke="currentColor"
class="w-6 h-6"
>
<path
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m19.5 8.25-7.5 7.5-7.5-7.5"
Expand All @@ -40,7 +40,7 @@ <h3>
</svg>
}
</span>
</button>
</button>
</h3>

@if (detailsVisible()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,24 @@ import { Ticket } from '../ticket.model';
})
export class TicketComponent {
// @Input({}) ...
data = input.required<Ticket>();
data = input.required<Ticket>(); // marim te dhenat nga tickets.component.html

// @Output('closeTicket')
close = output();
detailsVisible = signal(false);
close = output<void>(); // krijojme nje output void i cili do prejcelli metem sinjalin ne tickets.component.html

detailsVisible = signal(false); // krijojme nje signal boolean me vler fillestare false

onToggleDetails() {

// per cdo shtypje te butonit signal boolean false e kthejme ne true, dhe nga true ne false
// if true kodi lexon: @if (detailsVisible()) { , if false kodi lexon: } @else {

onToggleDetails() {
// this.detailsVisible.set(!this.detailsVisible());
this.detailsVisible.update((wasVisible) => !wasVisible);
this.detailsVisible.update((wasVisible) => !wasVisible);
}

onMarkAsCompleted() {
this.close.emit();
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div>
<ul>
@for (ticket of tickets; track ticket.id) {
<li>
<li> <!-- close = output<void>(); eshte nje ouptu void, is cili mer vetem sinjalin e shtypjes se butonit, perte mbyllur ticket qe krijuam -->
<app-ticket [data]="ticket" (close)="onCloseTicket(ticket.id)" />
</li>
} @empty {
Expand All @@ -11,5 +11,6 @@
</div>

<div id="new-ticket">
<app-new-ticket (add)="onAdd($event)" />
<app-new-ticket (add)="onAdd($event)" /> <!-- marim vlerat input title dhe text, per ti shtuar ne array tickets: Ticket[] = []; -->
</div>

Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,26 @@ import { TicketComponent } from "./ticket/ticket.component";
imports: [NewTicketComponent, TicketComponent]
})
export class TicketsComponent {
tickets: Ticket[] = [];

onAdd(ticketData: { title: string; text: string }) {
tickets: Ticket[] = []; // krijojme nje array emtity

onAdd(ticketData: { title: string; text: string }) { // marim objet data me output nga app-new-ticket
const ticket: Ticket = {
title: ticketData.title,
request: ticketData.text,
id: Math.random().toString(),
status: 'open'
id: Math.random().toString(),
status: 'open'
}

this.tickets.push(ticket);
this.tickets.push(ticket); // ne e shtojme ne array
}

onCloseTicket(id: string) {
onCloseTicket(id: string) { // pe cdo clikim mbi object me ndimen e id, updetojme objektin nga status open ne status closed.
this.tickets = this.tickets.map((ticket) => {
if (ticket.id === id) {
return { ...ticket, status: 'closed' }
}
return ticket;
});
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<p>Last 7 days</p>

<div id="chart">
@for (dataPoint of dummyTrafficData; track dataPoint.id) {
@for (dataPoint of dummyTrafficData; track dataPoint.id) { <!-- track dataPoint.id -> perdoret per te indentifikur te dhenat - reshtat ne baz te id -->
<!-- In Angular, <div [style.height]> is a way to bind a dynamic value to the height CSS style property of a div element. -->
<div [style.height]="(dataPoint.value / maxTraffic) * 100 + '%'"></div>
}
</div>

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class TrafficComponent {
{
id: 'd3',
value: 290,
},
},
{
id: 'd4',
value: 410,
Expand All @@ -38,5 +38,8 @@ export class TrafficComponent {
value: 589,
},
];

// nga dummyTrafficData gjejme objektin qe vleren me te madhe, ne kete raste vlera me e madhe eshte 589
maxTraffic = Math.max(...this.dummyTrafficData.map((data) => data.value));

}
Loading