Skip to content

Commit 795496a

Browse files
committed
create core/delegates component
1 parent c224b4f commit 795496a

File tree

7 files changed

+258
-2
lines changed

7 files changed

+258
-2
lines changed

src/app/core/core-routing.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ExtensionComponent } from './extension/extension.component';
66
import { LinqComponent } from './linq/linq.component';
77
import { GenericsComponent } from './generics/generics.component';
88
import { AsynchronousComponent } from './asynchronous/asynchronous.component';
9+
import { DelegatesComponent } from './delegates/delegates.component';
910

1011
const routes: Routes = [
1112
{ path: 'docs/core/overview', component: OverviewComponent },
@@ -14,6 +15,7 @@ const routes: Routes = [
1415
{ path: 'docs/core/linq', component: LinqComponent },
1516
{ path: 'docs/core/generics', component: GenericsComponent },
1617
{ path: 'docs/core/asynchronous', component: AsynchronousComponent },
18+
{ path: 'docs/core/delegates', component: DelegatesComponent },
1719
{ path: 'docs/core', redirectTo: 'docs/core/overview', pathMatch: 'full' }
1820
];
1921

src/app/core/core.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ExtensionComponent } from './extension/extension.component';
88
import { LinqComponent } from './linq/linq.component';
99
import { GenericsComponent } from './generics/generics.component';
1010
import { AsynchronousComponent } from './asynchronous/asynchronous.component';
11+
import { DelegatesComponent } from './delegates/delegates.component';
1112

1213
@NgModule({
1314
declarations: [
@@ -16,7 +17,8 @@ import { AsynchronousComponent } from './asynchronous/asynchronous.component';
1617
ExtensionComponent,
1718
LinqComponent,
1819
GenericsComponent,
19-
AsynchronousComponent
20+
AsynchronousComponent,
21+
DelegatesComponent
2022
],
2123
imports: [
2224
CommonModule,

src/app/core/delegates/delegates.component.css

Whitespace-only changes.
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
<div class="container pt-3">
2+
<div class="row">
3+
<div id="sidebar" style="width: 260px;">
4+
<app-sidebar></app-sidebar>
5+
</div>
6+
<div id="content" class="flex-grow-1" style="width: 400px;">
7+
<article>
8+
<h1>Delegates & Events</h1>
9+
<hr>
10+
<p>
11+
A delegate is a type that holds references to methods or functions with a particular signature of parameters and return type, and any method or function compatible with the delegate signature can be associated with the instance of that delegate and can be called by invoking the delegate instance.
12+
</p>
13+
<h3>Defining the delegate</h3>
14+
<p>
15+
A delegate is constructed by extending the abstract class Delegate, defining the method signature with an empty body, and having the same name as the name of the defined delegate class, as shown in the code example below.
16+
</p>
17+
<pre><code class="language-php">&lt;?php
18+
19+
namespace Application;
20+
21+
use DevNet\System\Delegate;
22+
23+
class MyDelegate extends Delegate
24+
&lcub;
25+
// Define the delegate signature.
26+
public function myDelegate(array $args): string
27+
&lcub;
28+
// The body is left empty.
29+
}
30+
}
31+
</code></pre>
32+
<br>
33+
<h3>Defining the handler</h3>
34+
<p>
35+
The following code example represents a handler class with two methods that will be associated with the delegate introduced in the previous example, and they must have the same signature of that delegate.
36+
</p>
37+
<pre><code class="language-php">&lt;?php
38+
39+
namespace Application;
40+
41+
class MyHandler
42+
&lcub;
43+
// Define a method with the same signature as the delegate.
44+
public function handle(array $args): string
45+
&lcub;
46+
return serialize($args);
47+
}
48+
}
49+
</code></pre>
50+
<br>
51+
<h3>Using the delegate</h3>
52+
<p>
53+
When the delegate is instantiated, it can encapsulate any function or method with a compatible signature, and when the call is made to the delegate instance, it will be passed to the associated function, passing along the same arguments and returning the same value.
54+
</p>
55+
<pre><code class="language-php">&lt;?php
56+
57+
// Register the method 'handle' of the Handler class
58+
$myAction = new MyDelegate([new MyHandler(), 'handle']);
59+
60+
// Or register in-line closure function of the same signature
61+
$myAction = new MyDelegate(function(array $args): string &lcub;
62+
return serialize($args);
63+
});
64+
65+
$args = ['value1', 'value2'];
66+
67+
// Invoke the delegate instance.
68+
$result = $myAction($args);
69+
</code></pre>
70+
<br>
71+
<h4>Multicast Delegate</h4>
72+
<p>
73+
A multicast delegate is a delegate that holds references to multiple methods or functions, and when the delegate instance is called, it invokes all of the associated functions, and the return value is that of the last function executed, unless you invoke each function through iteration to deal with each returned value.
74+
</p>
75+
<pre><code class="language-php">&lt;?php
76+
77+
$myAction = new MyDelegate();
78+
79+
// register Handlers
80+
$myAction[] = [new MyHandler(), 'handle'];
81+
$myAction[] = function(array $args): string &lcub;
82+
return json_encode($args);
83+
};
84+
85+
$args = ['value1', 'value2'];
86+
87+
// Invoke the multicast delegate and store the last returned value
88+
$result = $myAction($args);
89+
90+
// Invoke each function of the multicast delegate through iteration to store all the returned values
91+
$results = [];
92+
foreach($myAction as $action) &lcub;
93+
$results[] = $action->invoke($args);
94+
}
95+
</code></pre>
96+
<br>
97+
<h3>Event</h3>
98+
<p>
99+
An event is a special type of delegate that enables an object to notify other objects when something of interest occurs, where the class that sends or raises the event is called the publisher (other names: sender, subject), and the classes that receive or handle the event are called subscribers (other names: receivers, observers, listeners, handlers).
100+
</p>
101+
<h5>Event Handler</h5>
102+
<p>
103+
DevNet provides an easy way to subscribe to the event by using <code>DevNet\System\Event\EventHandler</code>, which has the following delegate signature <code>function(object $sender, EventArgs $args): void</code>
104+
</p>
105+
<ul>
106+
<li><b>$sender:</b> (<code>object</code>) represents the publisher that raises the event, and the reason for passing the sender as a parameter to the handler, is because the handler can be subscribed to multiple publishers, and sometimes we need to know which publisher raises the event.</li>
107+
<li><b>$args:</b> (<code>DevNet\System\Event\EventArgs</code>) represents the event arguments to be handled by the handler.</li>
108+
</ul>
109+
<p>
110+
The example below represents a <code>Button</code> class as a publisher with two events: The <code>click</code> and <code>keypress</code> events, which can be associated with event listners.
111+
</p>
112+
<pre><code class="language-php">&lt;?php
113+
114+
namespace Application\Components;
115+
116+
use DevNet\System\Event\EventArgs;
117+
use DevNet\System\Event\EventHandler;
118+
119+
class Button
120+
&lcub;
121+
public string $Title;
122+
private EventHandler $click;
123+
private EventHandler $keypress;
124+
125+
public function __construct(string $title)
126+
&lcub;
127+
$this->Title = $title;
128+
$this->click = new EventHandler();
129+
$this->keypress = new EventHandler();
130+
}
131+
132+
public function addListner(string $event, callable $handler): void
133+
&lcub;
134+
switch($event) &lcub;
135+
case 'click':
136+
$this->click[] = $handler;
137+
break;
138+
case 'keypress':
139+
$this->keypress[] = $handler;
140+
break;
141+
default:
142+
throw \Exception("The event &lcub;$event} does not exist!");
143+
}
144+
}
145+
146+
public function click(): void
147+
&lcub;
148+
$this->click->invoke($this, new EventArgs);
149+
}
150+
151+
public function keypress(): void
152+
&lcub;
153+
$this->keypress->invoke($this, new EventArgs);
154+
}
155+
}
156+
</code></pre>
157+
<p>
158+
And the following example represents a <code>Window</code> class as a subscriber that can subscribe handlers to the <code>Button</code> events.
159+
</p>
160+
<pre><code class="language-php">&lt;?php
161+
162+
namespace Application\Components;
163+
164+
use DevNet\System\Event\EventArgs;
165+
166+
class Window
167+
&lcub;
168+
public string $Title;
169+
public Button $MyButton;
170+
171+
public function __construct(string $title)
172+
&lcub;
173+
$this->Title = $title;
174+
$this->MyButton = new Button("My button");
175+
// Subscribe to the click event.
176+
$this->MyButton->addListner('click', [$this, 'onMyButtonClick']);
177+
}
178+
179+
public function onMyButtonClick(object $sender, EventArgs $event): void
180+
&lcub;
181+
print("&lcub;$sender->Title} was clicked");
182+
}
183+
}
184+
</code></pre>
185+
<p>
186+
And here is a working example of triggering the click event of the Window's button.
187+
</p>
188+
<pre><code class="language-php">&lt;?php
189+
190+
use Application\Components\Window;
191+
192+
$myWindow = new Window("My Window");
193+
$myWindow->MyButton->click();
194+
</code></pre>
195+
</article>
196+
<nav class="no-print" aria-label="Page navigation">
197+
<ul class="nav-page">
198+
<li class="nav-page-item">
199+
<a class="nav-page-link" routerLink="/docs/core/asynchronous">
200+
<i class="chevron left"></i> Previous
201+
</a>
202+
</li>
203+
<li class="nav-page-item">
204+
<a class="nav-page-link" routerLink="/docs/core/diagnostics">
205+
Next <i class="chevron right"></i>
206+
</a>
207+
</li>
208+
</ul>
209+
</nav>
210+
</div>
211+
</div>
212+
</div>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { DelegatesComponent } from './delegates.component';
4+
5+
describe('DelegatesComponent', () => {
6+
let component: DelegatesComponent;
7+
let fixture: ComponentFixture<DelegatesComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [ DelegatesComponent ]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(DelegatesComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import hljs from 'highlight.js/lib/common';
3+
4+
@Component({
5+
selector: 'core-delegates',
6+
templateUrl: './delegates.component.html',
7+
styleUrls: ['./delegates.component.css']
8+
})
9+
export class DelegatesComponent implements OnInit {
10+
11+
constructor() { }
12+
13+
ngOnInit(): void {
14+
hljs.highlightAll();
15+
}
16+
17+
}

src/app/shared/sidebar/sidebar.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<li><a class="link-dark d-inline-flex text-decoration-none rounded" routerLink="/docs/core/linq" routerLinkActive="fw-bold">LINQ Methods</a></li>
3838
<li><a class="link-dark d-inline-flex text-decoration-none rounded" routerLink="/docs/core/generics" routerLinkActive="fw-bold">Generic Types</a></li>
3939
<li><a class="link-dark d-inline-flex text-decoration-none rounded" routerLink="/docs/core/asynchronous" routerLinkActive="fw-bold">Async Operations</a></li>
40-
<li><a class="link-dark d-inline-flex text-decoration-none rounded" routerLink="/docs/core/delegate" routerLinkActive="fw-bold">Event Delegate</a></li>
40+
<li><a class="link-dark d-inline-flex text-decoration-none rounded" routerLink="/docs/core/delegates" routerLinkActive="fw-bold">Delegates & Events</a></li>
4141
<li><a class="link-dark d-inline-flex text-decoration-none rounded" routerLink="/docs/core/diagnostics" routerLinkActive="fw-bold">Diagnostics</a></li>
4242
</ul>
4343
</div>

0 commit comments

Comments
 (0)