<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Angular Archives - Nerd Corner</title>
	<atom:link href="https://nerd-corner.com/category/angular/feed/" rel="self" type="application/rss+xml" />
	<link>https://nerd-corner.com/category/angular/</link>
	<description>Craft your dreams!</description>
	<lastBuildDate>Sun, 16 Mar 2025 18:49:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.2</generator>

<image>
	<url>https://nerd-corner.com/wp-content/uploads/2019/10/cropped-LogoNerdCorner-2-32x32.png</url>
	<title>Angular Archives - Nerd Corner</title>
	<link>https://nerd-corner.com/category/angular/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Deployment of a WebApp with Kubernetes and Caddy</title>
		<link>https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/</link>
					<comments>https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Sun, 16 Feb 2025 18:31:48 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<category><![CDATA[App development]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Caddy]]></category>
		<category><![CDATA[Caddy Server]]></category>
		<category><![CDATA[Cluster]]></category>
		<category><![CDATA[ClusterIP]]></category>
		<category><![CDATA[ConfigMap]]></category>
		<category><![CDATA[Container]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[Domain Registration]]></category>
		<category><![CDATA[Hetzner]]></category>
		<category><![CDATA[Images]]></category>
		<category><![CDATA[Ingress]]></category>
		<category><![CDATA[Ingress Controller]]></category>
		<category><![CDATA[ip addres]]></category>
		<category><![CDATA[K3s]]></category>
		<category><![CDATA[Kubectl]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[LoadBalancer]]></category>
		<category><![CDATA[mySql]]></category>
		<category><![CDATA[Nest.js]]></category>
		<category><![CDATA[Node Port]]></category>
		<category><![CDATA[Pods]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[Service]]></category>
		<category><![CDATA[Step by step guide]]></category>
		<category><![CDATA[Traefik]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/de/?p=1695</guid>

					<description><![CDATA[<p>After describing how to create production-ready Docker images and upload them to Docker Hub in the last article, it is now time to make these &#8230; </p>
<p>The post <a href="https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/">Deployment of a WebApp with Kubernetes and Caddy</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>After describing how to create production-ready Docker images and upload them to Docker Hub in the last article, it is now time to make these images available on a server. The aim is to make the web application accessible to everyone via a dedicated domain. To do this, we use a virtual private server (VPS) from Hetzner and deploy Kubernetes (k3s) with Caddy as a reverse proxy.</p>
<p><strong><em>You might also be interested in this: </em></strong><a href="https://nerd-corner.com/create-docker-images-and-upload-them-to-docker-hub/"><em>Create Docker images and upload them to Dockerhub</em></a></p>
<h2>Set up a VPS with Hetzner</h2>
<p>Hetzner often offers referral links with credit benefits for new customers. Of course, you can also use other providers, but Hetzner is attractively priced and offers solid services.</p>
<h3>What is a VPS?</h3>
<p>A Virtual Private Server (VPS) is a virtual server that is operated on a physical machine and acts as an independent server. It offers more control than classic shared hosting and is a cost-effective alternative to dedicated servers. Access is usually via SSH (Secure Shell), which allows us to control the server via the command line.</p>
<h3>SSH access to the VPS</h3>
<p>Once a VPS has been created, it is usually managed via a secure shell (SSH). SSH is a protocol that enables encrypted connections to remote servers. The following command is used to connect to the server:</p>
<p data-start="1137" data-end="1384"><span style="background-color: #e9ebec; color: #222222; font-family: Monaco, Consolas, 'Andale Mono', 'DejaVu Sans Mono', monospace; font-size: 15px;">ssh root@&lt;IP-Server&gt;</span></p>
<p>If an SSH key has been stored, authentication can be carried out using public key authentication, which is more secure than a password.</p>
<h3>Create a server at Hetzner</h3>
<ol>
<li>After logging into the Hetzner Cloud, we navigate to “Projects” and create a new project.</li>
<li>Select “Add server” and can configure an instance.</li>
<li>The cheapest model is often sufficient to start with. However, I recommend activating the option for an IPv4 address, as purely IPv6-based setups often cause compatibility problems.</li>
</ol>
<h3>Setting up a domain</h3>
<p>To access the application later under your own domain, you must register a domain and link it to the server.</p>
<h3>Apply for a domain at Hetzner</h3>
<ol>
<li>Register a new domain or add an existing domain in the Hetzner ConsoleH.</li>
<li>To manage DNS entries, we need to activate DNS access.</li>
</ol>
<h3>Set name servers</h3>
<p>The following name servers should be used:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">helium.ns.hetzner.de. 
hydrogen.ns.hetzner.com. 
oxygen.ns.hetzner.com.</pre>
<p>These new name servers offer better performance and flexibility compared to the old Hetzner name servers:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">ns1.first-ns.de.
robotns2.second-ns.de.
robotns3.second-ns.com.</pre>
<p>However, both nameserver variants are possible! The DNS changes take some time. However, we can use tools such as MXToolbox to check whether the changes have already taken place.</p>
<h3>Connect the domain to the server</h3>
<p>Now the IP address of the server must be linked to the domain:</p>
<ol>
<li>Switch to DNS zones in the Hetzner Cloud.</li>
<li>Select the registered domain.</li>
<li>Create a new A-Record and enter the IPv4 address of the server.</li>
<li>If available, remove the IPv6 record (AAAA) to avoid compatibility problems.</li>
</ol>
<p>You can also use <a href="http://mxtoolbox.com">MXToolbox</a> to check whether the DNS changes have already been applied.</p>
<h2>Set up Kubernetes</h2>
<p>Kubernetes is a powerful orchestration tool for containers. I use k3s, a lean Kubernetes variant that is particularly suitable for smaller environments.</p>
<h3>Install K3s on the server</h3>
<p>Connect to the server via SSH and install k3s with the following command:</p>
<pre><code class="language-sh">curl -sfL https://get.k3s.io | sh - </code></pre>
<p>The script installs k3s and starts the Kubernetes service. After installation, k3s can be checked with the following command:</p>
<pre><code class="language-sh">kubectl get nodes
</code></pre>
<p>k3s comes with its own kubectl version, so that no separate installation is necessary.</p>
<h3>Create YAML files for FE, BE, MySQL and Redis</h3>
<p>To deploy our application, we need YAML files for:</p>
<ul>
<li>Frontend (Angular)</li>
<li>Backend (NestJS)</li>
<li>Database (MySQL)</li>
<li>Session-Management (Redis)</li>
</ul>
<p>A deployment file for the backend could look like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
        - name: backend
          image: dockerhub-user/backend:latest
          ports:
            - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: ClusterIP
</pre>
<h3>What are deployments and services?</h3>
<ul>
<li>Deployments manage the provision and scaling of containers.</li>
<li>Services ensure a stable network connection between containers.</li>
<li>ClusterIP means that the service is only accessible within the Kubernetes cluster.</li>
</ul>
<h3>Set up Caddy as a reverse proxy</h3>
<p>A reverse proxy is required to ensure that incoming traffic is distributed correctly. K3s comes with Traefik by default, but I opted for a simpler solution: Caddy. I was really surprised how little guidance or documentation there is on Caddy in combination with Kubernetes.</p>
<h3>Why Kubernetes with Caddy?</h3>
<ul>
<li>Automatic Let&#8217;s Encrypt SSL certificates</li>
<li>Simple configuration via Caddyfile</li>
<li>Built-in load balancer</li>
</ul>
<h3>Remove Traefik</h3>
<pre><code class="language-sh">kubectl delete helmrelease traefik -n kube-system
</code></pre>
<h3>Create Caddy Deployment</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">apiVersion: apps/v1
kind: Deployment
metadata:
  name: caddy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: caddy
  template:
    metadata:
      labels:
        app: caddy
    spec:
      containers:
        - name: caddy
          image: caddy
          volumeMounts:
            - name: caddy-config
              mountPath: /etc/caddy/Caddyfile
      volumes:
        - name: caddy-config
          configMap:
            name: caddy-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: caddy-config
data:
  Caddyfile: |

    example.com {
        reverse_proxy backend-service:3000
    }

---
apiVersion: v1
kind: Service
metadata:
  name: caddy-service
spec:
  type: LoadBalancer
  selector:
    app: caddy
  ports:
    - port: 80
      targetPort: 80
    - port: 443
      targetPort: 443</pre>
<p>Important: Since Let&#8217;s Encrypt has a rate limit, tests should first be carried out with staging certificates!</p>
<h2>Conclusion</h2>
<p>After these steps, the application is now running in a Kubernetes cluster on a Hetzner VPS and can be accessed via its own domain. The next step would be to set up an automatic CI/CD pipeline to deploy new versions without manual effort.</p>
<p>The post <a href="https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/">Deployment of a WebApp with Kubernetes and Caddy</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/deployment-of-a-webapp-with-kubernetes-and-caddy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to build a Custom Angular Reactive SVG Form with clickable elements</title>
		<link>https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/</link>
					<comments>https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/#comments</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Thu, 30 Dec 2021 17:20:52 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Angular reactive forms]]></category>
		<category><![CDATA[create SVG]]></category>
		<category><![CDATA[custom angular form]]></category>
		<category><![CDATA[custom form]]></category>
		<category><![CDATA[custom reactive angular form]]></category>
		<category><![CDATA[custom reactive form]]></category>
		<category><![CDATA[ng]]></category>
		<category><![CDATA[reactive]]></category>
		<category><![CDATA[reactive form with SVG]]></category>
		<category><![CDATA[reactive forms]]></category>
		<category><![CDATA[SVG]]></category>
		<category><![CDATA[SVG binding]]></category>
		<category><![CDATA[SVG plan]]></category>
		<category><![CDATA[TDD]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/de/?p=1149</guid>

					<description><![CDATA[<p>During the Corona pandemic, many companies and employees discovered home office. As a result, it became apparent that not every employee required his own workstation. &#8230; </p>
<p>The post <a href="https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/">How to build a Custom Angular Reactive SVG Form with clickable elements</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>During the Corona pandemic, many companies and employees discovered home office. As a result, it became apparent that not every employee required his own workstation. Instead, companies now offer a shared desk model. This means that employees flexibly share workstations. Often, you can reserve your desired workstation in advance. This workplace booking function has attracted me for some time. I find the possibility to create a Custom Reactive Form in Angular, which also includes an office plan, particularly interesting. In the Custom Angular Reactive SVG Form there is the possibility to select a workstation from the office plan and to mark it with a color. As soon as a workstation has been chosen, the form will be validated and the desk will be bookable. In the following the implementation is explained step by step.</p>
<p><em><strong>This might also be interesting for you:</strong> <a href="https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/">How to build an Angular PUSH architecture.</a></em></p>
<h2>List of components</h2>
<ul>
<li>Development environment (e.g. VS Code)</li>
<li>Angular CLI</li>
<li><a  data-e-Disable-Page-Transition="true" class="download-link" title="" href="https://nerd-corner.com/download/1134/?tmstv=1756512555" rel="nofollow" id="download-link-1134" data-redirect="false" >
	SVG File</a>
</li>
</ul>
<p><iframe id="angularFrame" title="Angular Seat Booker App" src="https://nerd-corner.com/angular/SVG-form/" width="600" height="380" frameborder="0"><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><br />
</iframe></p>
<h2>Creation of an office plan</h2>
<p><img fetchpriority="high" decoding="async" class="zoooom aligncenter wp-image-1138" src="https://nerd-corner.com/wp-content/uploads/2021/12/Office-plan.jpg" alt="SVG office plan with clickable elements Angular Form SVG" width="720" height="497" srcset="https://nerd-corner.com/wp-content/uploads/2021/12/Office-plan.jpg 726w, https://nerd-corner.com/wp-content/uploads/2021/12/Office-plan-300x207.jpg 300w" sizes="(max-width: 720px) 100vw, 720px" /></p>
<p>I would almost say that creating the office plan was the hardest part of the task. The office plan can be created in different ways. The important thing is it has to be an SVG file. I used Adobe Xd and worked with lines, rectangles and circles. The result could be prettier, but it is enough to demonstrate the functionality. You can use my plan or create your own.</p>
<p>After the SVG image is created, the areas that represent a workspace need to be grouped together. I assigned the class &#8220;seat&#8221; to the group. It looks like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;g class="seat" &gt;
    &lt;g id="table-0" transform="translate(19 59)"&gt;
      &lt;rect width="66" height="35" stroke="none" /&gt;
      &lt;rect x="2.5" y="2.5" width="61" height="30" fill="none" /&gt;
    &lt;/g&gt;
    &lt;g id="screen-0" transform="translate(31 84)"&gt;
      &lt;rect id="fill" width="42" height="4" stroke="none" /&gt;
      &lt;path
        d="M0,1.5h42M39.5,0v4M42,2.5h-42M2.5,4v-4"
        fill="none"
        clip-path="url(#clip)"
      /&gt;
    &lt;/g&gt;
    &lt;g id="chair-0" transform="translate(40 30)"&gt;
      &lt;ellipse cx="12.5" cy="11" rx="12.5" ry="11" stroke="none" /&gt;
      &lt;ellipse cx="12.5" cy="11" rx="10" ry="8.5" fill="none" /&gt;
    &lt;/g&gt;
  &lt;/g&gt;</pre>
<p>The code snippet shown corresponds to a workstation, such as the one in the red circle here:</p>
<p><img decoding="async" class="zoooom aligncenter wp-image-1140" src="https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1.png" alt="SVG office plan place selected Angular Form SVG" width="1140" height="625" srcset="https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1.png 1151w, https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1-300x164.png 300w, https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1-1024x561.png 1024w, https://nerd-corner.com/wp-content/uploads/2021/12/one-seat-1-768x421.png 768w" sizes="(max-width: 1140px) 100vw, 1140px" /></p>
<h2>Creation of the Angular Reactive Form</h2>
<p>To include the office plan in a reactive form, we create a new Angular project. I took inspiration for the project from the German YouTuber Unleashed Design: https://www.youtube.com/watch?v=NOuVxP7FxBc. In general, I can highly recommend his videos! You always learn new tips and tricks, especially when dealing with Angular.</p>
<p>We need the ReactiveFormsModule for the Reactive Angular Form SVG. Then we create a FormGroup and FormControl fields. I have named the FormGroup reservationForm. It contains a field for the name, a field for the weekday and a field for the place you want to book.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">public reservationForm: FormGroup = new FormGroup({
    name: new FormControl('', [Validators.required], []),

    weekday: new FormControl('', [Validators.required], []),

    seat: new FormControl('', [Validators.required], []),
  });</pre>
<p>To be able to display the form some html code is necessary:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;form [formGroup]="reservationForm"&gt;
  &lt;label for="name"&gt; Your name:&lt;/label&gt;
  &lt;input id="name" type="text" formControlName="name" placeholder="Name" /&gt;

  &lt;label for="weekday"&gt; Enter the reservation day:&lt;/label&gt;
  &lt;input
    id="weekday"
    type="text"
    formControlName="weekday"
    placeholder="Monday"
  /&gt;
&lt;/form&gt;</pre>
<p>For a better demonstration, it makes sense to also display the value of the form:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;p&gt;Values: {{ reservationForm.value | json }}&lt;/p&gt;
&lt;p&gt;Form valid: {{ reservationForm.valid }}&lt;/p&gt;</pre>
<h2>Making Seats Component for the Custom Angular Reactive SVG Form</h2>
<p>To build a custom form field, the first thing we need is a new component. Here we can directly use a tip from Unleashed Design. Angular offers the possibility to include SVG images as templateUrl. We delete the seats.component.html and replace it with our SVG office plan named seats.component.svg. In the seats.component.ts we can replace the templateUrl with the SVG file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">selector: 'app-seats',
templateUrl: './seats.component.svg',
styleUrls: ['./seats.component.sass'],</pre>
<p>The custom form field can now be included in the reactive form:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">&lt;app-seats id="seat" formControlName="seat"&gt;&lt;/app-seats&gt;</pre>
<p>In the Sass file, the SVG office plan can be customized as desired. Colors, line thicknesses, and much more can be set here. I have customized it so that the office plan turns red when the SVG form field is invalidated:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="scss" data-enlighter-theme="atomic">$successColour: #19e619

:host
    &amp;.ng-touched, &amp;.ng-dirty
            &amp;.ng-invalid
                svg
                    .wall, .seat
                        stroke: red

    svg
        margin: 25px 0 25px 0
        
        .wall
            stroke: black
            fill: #fff 
            stroke-width: 5
        .separators
            stroke: black
            fill: none
            stroke-width: 5
        .separate-room
            stroke: black
            fill: none
            stroke-width: 5

        .seat
            stroke: grey
            cursor: pointer
            fill: #fff 
            transition: all 250ms
            stroke-width: 4
            &amp;.selected
                fill: $successColour
                stroke-width: 1
</pre>
<h2>Adding the ControlValueAccessor</h2>
<p>We can already see our office plan in the Reactive Form, but it is still without functionality. To change that a ControlValueAccessor is needed. The ControlValueAccessor serves as an interface for a custom form control that integrates with Angular forms. The ControlValueAccessor asks for these four methods:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">interface ControlValueAccessor {
  writeValue(obj: any): void
  registerOnChange(fn: any): void
  registerOnTouched(fn: any): void
  setDisabledState(isDisabled: boolean)?: void
}</pre>
<p>More information about the ControlValueAccessor can be found in the doc: https://angular.io/api/forms/ControlValueAccessor</p>
<p>In order for the seats.component.ts component to get access to the VALUE_ACCESSOR we need to configure the following provider:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() =&gt; SeatsComponent),
      multi: true,
    },
  ],</pre>
<h2>Variables and methods for the Angular Forms ControlValueAccessor</h2>
<p>The next step looks more complicated than it actually is. Basically, these are fixed variables and methods that every custom form field needs.</p>
<p>Every custom reactive form needs the following variables. The variable onTouched, in order for the form field to become touched later. Also onChange and the static variable touched as a boolean to know if the form field is already touched. A form field can also be disabled, so the static variable isDisabled is also required as a boolean. Of course every custom form also uses a value.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">public onTouched = () =&gt; {};
public onChange = (value: string) =&gt; {};
public touched: boolean = false;
public isDisabled: boolean = false;
public value: string = '';</pre>
<p>Every Custom Reactive Form also needs the possibility to change these variables. This is where the ControlValueAccessor methods discussed in the previous section come into play. One is the writeValue function, which sets the value variable to a new value. The markAsTouched function calls onTouched and sets the variable touched to true if the custom form field has not been clicked before. Finally, the two methods registerOnChange and registerOnTouched are needed. Both actually only update their respective value. The registerOnChange function updates the value onChange and registerOnTouched updates the value onTouched. The reactiveFormModule can also disable entire forms. To ensure that the custom reactive form field also listens to this, the setDisabledState method is used. With this method the variable isDisabled can be changed.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">writeValue(value: string): void {
  this.value = value;
}
markAsTouched(): void {
  if (!this.touched) {
    this.onTouched();
    this.touched = true;
  }
}
registerOnChange(onChange: any): void {
  this.onChange = onChange;
}
registerOnTouched(onTouched: any): void {
  this.onTouched = onTouched;
}

setDisabledState(isDisabled: boolean): void {
  this.isDisabled = isDisabled;
}</pre>
<h2>Bind SVG groups to the form variables</h2>
<p>In order for the SVG office plan to be functionally usable, we still need the possibility to select individual workstations. For this we use the Angular binding possibilities. A function isSelected() is required to detect and change the sytling of the workstation.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="atomic">[class.selected]="isSelected('seat-0')"
(click)="select('seat-0')"</pre>
<p>Also a function select(), which recognizes the selected seat of the Custom Angular Reactive SVG Form by the name (&#8220;seat-1&#8221;, &#8220;seat-2&#8243;&#8230;). Within this select() function it is first checked if the form is disabled in general. If this is not the case, a second query checks if the seat has already been selected. If this is the case the value becomes nothing, otherwise the value becomes the name of the seat, for example &#8220;seat-3&#8221;.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="atomic">public select(option: string): void {
  if (!this.isDisabled) {
    if (this.isSelected(option)) {
      this.value = '';
    } else {
      this.value = option;
    }
    this.onChange(this.value);
    this.markAsTouched();
  }
}

public isSelected(option: string): boolean {
  return option === this.value;
}</pre>
<h2>Download files</h2>
<ul>
<li><a href="https://github.com/hanneslim/Angular-form-with-SVG-options">Project on Github</a></li>
</ul>
<p>The post <a href="https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/">How to build a Custom Angular Reactive SVG Form with clickable elements</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/how-to-build-a-custom-angular-reactive-svg-form-with-clickable-elements/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>How to build a PUSH based architecture in Angular &#8211; Facade Design Pattern</title>
		<link>https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/</link>
					<comments>https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/#comments</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Sun, 05 Dec 2021 03:36:36 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[angularjs]]></category>
		<category><![CDATA[behavior subject description: Make Reactive Applications]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[observables]]></category>
		<category><![CDATA[Push Based Architecture with RxJS]]></category>
		<category><![CDATA[Remove term: Push Based Architecture with RxJS tags: angular Push Based Architecture with RxJS]]></category>
		<category><![CDATA[rxjs]]></category>
		<category><![CDATA[rxjs observables]]></category>
		<category><![CDATA[state management]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/?p=1095</guid>

					<description><![CDATA[<p>Typically, a PULL-based architecture is used in software development and only rarely a PUSH-based architecture. A service is called to request data from a server, &#8230; </p>
<p>The post <a href="https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/">How to build a PUSH based architecture in Angular &#8211; Facade Design Pattern</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Typically, a PULL-based architecture is used in software development and only rarely a PUSH-based architecture. A service is called to request data from a server, which sends a request to the server and receives the required data. However, during this process, the main UI thread is blocked.</p>
<p>Angular itself regularly checks the view model for changes. If the view model changes due to a state change, Angular re-renders the view because Angular automatically adjusts the UI when the model changes. These continuous observations make the whole application slower.</p>
<p>Moreover, with the traditional pull approach, complexity increases. Especially when multiple views need the same data. What happens when the data changes? How are views notified that new data is available? Callback functions could help, but as a result, the application quickly becomes confusing. They also have a negative impact on handling and maintenance, especially for larger applications. After all, the objects have to be initialized individually and the dependencies or the order of the methods have to be considered.</p>
<p>A push-based architecture can be used to avoid this problem. Angular offers a great way to implement this with RxJS and the facades design pattern! The implementation is explained using an Angular example in this blog article and is transferable for all platforms and frameworks (Angular, React, Vue.js, etc.).</p>
<h2>List of components</h2>
<ul>
<li>IDE (Visual Studio Code)</li>
<li>Angular CLI</li>
</ul>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1110 zoooom" src="https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH.png" alt="Push based Architecture Facade Service example" width="650" height="443" srcset="https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH.png 659w, https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH-300x204.png 300w" sizes="auto, (max-width: 650px) 100vw, 650px" /></p>
<h2>What is a facade actually?</h2>
<p>The facade design pattern is a central interface that communicates with various interfaces of one or more lower-level subsystems. It can perform additional functions both before and after a client request.</p>
<p>The facade object provides a unified and usually simplified interface to one or more subsystems. As an intermediary, it ensures that communication or access to the individual components of a subsystem is simplified, thereby also minimizing direct dependence on these components. It delegates the client calls in such a way that clients need to know neither the classes nor their relations and dependencies.</p>
<p>This is especially helpful in large systems when a subsystem contains many technically oriented classes that are rarely used externally. Using a facade reduces complexity by combining multiple interfaces into one. In addition, the subsystem can be extended more easily due to the loose coupling.</p>
<h2>The PUSH Architecture</h2>
<p>For a push based architecture, advanced design patterns like Redux or NgRx can be used. However, a very elegant and performant push based solution can also be achieved using RxJS.</p>
<p>Using the long-living RxJS Observable streams, changes in the data can be pushed to all subscribers. To do so, the views subscribe to the desired data stream. If the data changes, the changes are pushed directly to all subscribers via the stream without blocking the UI thread.</p>
<p>In this way, direct data access is prevented and the data is read-only. The actual data source is accessed similar to an API used by the views. The facade described at the beginning serves as the central interface here. This consists of streams that provide data when the data changes and methods to request changes to the data or request specific user-defined streams.</p>
<p>The actual raw data is only available after it has been pushed through the stream(s). This shielding centralizes all logic and forces views to passively respond to incoming data. With the push based services, Angular View components become highly performant using both ChangeDetectionStrategy.OnPush, and the async pipe for the delivered stream data.</p>
<p>Therefore, the system is lazy loading. The UI framework does not need to check for state changes of the view model and instead lazily waits for a new state to be pushed.</p>
<h2>Practical example</h2>
<p>As an example for a push based architecture a simple application is used, which receives a random beer type via the HTTP request https://random-data-api.com/api/beer/random_beer?size=1. The type of beer is displayed in a view. An input field can be used to vary the number of beers to be shown. A facade as a central element automatically pushes the new beers to the view as soon as they are available.</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1120 zoooom" src="https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1.png" alt="PUSH vs PULL based architecture facade design Angular" width="1275" height="717" srcset="https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1.png 1280w, https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1-300x169.png 300w, https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1-1024x576.png 1024w, https://nerd-corner.com/wp-content/uploads/2021/11/facade_explanation-1-768x432.png 768w" sizes="auto, (max-width: 1275px) 100vw, 1275px" /></p>
<p>As a basis for the design pattern serves the article by Thomas Burleson: <a href="https://thomasburlesonia.medium.com/push-based-architectures-with-rxjs-81b327d7c32d" target="_blank" rel="noopener">https://thomasburlesonia.medium.com/push-based-architectures-with-rxjs-81b327d7c32d</a></p>
<h3>The first step is to set up the state management:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">export interface Beer {
  brand: string;
  name: string;
  style: string;
  hop: string;
  alcohol: string;
}

export interface BeerState {
  beerArray: Beer[];
  size: number;
}</pre>
<h3>Next, we initialize the values of the facade&#8217;s state management:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">export interface BeerState {
  beerArray: Beer[];
  size: number;
}

let _state: BeerState = {
  beerArray: [],
  size: 4
};</pre>
<h3>The facade uses RxJS streams to push data directly to the views. These streams can also automatically execute a Rest API call when the states change:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">combineLatest(this.size$)
      .pipe(
        //switchMap: Maps values to observable. Cancels the previous inner observable.
        switchMap(([size]) =&gt; {
          return this.findBeerArray(size);
        })
      )
      .subscribe((beerArray) =&gt; {
        this.updateState({ ..._state, beerArray });
      });</pre>
<h3>Streams are set up to be persistent and only become active when data changes:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">export class BeerFacade {

  beerArray$ = this.state$.pipe(
    map((state) =&gt; state.beerArray),
    distinctUntilChanged()
  );

  size$ = this.state$.pipe(
    map((state) =&gt; state.size),
    distinctUntilChanged()
  );

  private updateState(state: BeerState) {
    this.store.next((_state = state));
  }
}
</pre>
<h3>For better management, the streams are combined into a single one:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">vm$: Observable&lt;BeerState&gt; = combineLatest(this.beerArray$, this.size$).pipe(
    map(([beerArray, size]) =&gt; {
      return { beerArray, size };
    })
  );</pre>
<h5>The HTTP request can be outsourced to a separate data service. However, since this is only a small sample program, the Rest API call is implemented and executed within the Facade:</h5>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">/** RandomBeer REST call */
  private findBeerArray(size: number): Observable&lt;Beer[]&gt; {
    const url = `https://random-data-api.com/api/beer/random_beer?size=${size}`;
    return this.http.get&lt;Beer[]&gt;(url);
  }</pre>
<h3>The facade and view model stream can now be easily initialized and used. Incredibly less code is required:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">export class AppComponent {
  vm$: Observable&lt;BeerState&gt; = this.facadeService.vm$;

  //facadeService is public for direct usage in html
  constructor(public facadeService: RandomBeerFacadeService) {} 
  title = 'RandomBeerApp';
}</pre>
<h3>The view model stream data is displayed with the following code snippet:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">&lt;div *ngIf="vm$ | async as vm"&gt;  
  &lt;ul&gt;
    &lt;li id="random-beer-list" *ngFor="let u of vm.beerArray"&gt;
      Brand: {{ u.brand }}, Alcohol: {{ u.alcohol }}, Hop: {{ u.hop }}
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;input id="input-rand-beer" type="number" (change)="facadeService.updateSize($event)" /&gt;
&lt;/div&gt;</pre>
<p>Angular&#8217;s Async Pipe ensures that the most current data is always displayed. <a href="https://angular.io/api/common/AsyncPipe" target="_blank" rel="noopener">Here is a detailed explanation of the async pipe.</a></p>
<h5>Since the facade service is declared as public, the inputs are passed directly to the updateSize function of the facade:</h5>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">updateSize(selectedSize: any) {
    const size = selectedSize.target.value;
    this.updateState({ ..._state, size });
  }</pre>
<p>As a result, the application initially displays 4 random beers. Afterwards the number can be increased to 7 by the input field. This calls the updateSize() function, which updates the state of the size$ stream using updateState(). As a result, a new REST call is automatically executed and the result is pushed to the view model. With the help of the async pipe the latest data is displayed. In our case the 7 random beer types.</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1110 zoooom" src="https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH.png" alt="Push based Architecture Facade Service example" width="650" height="443" srcset="https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH.png 659w, https://nerd-corner.com/wp-content/uploads/2021/11/RandomBeerPUSH-300x204.png 300w" sizes="auto, (max-width: 650px) 100vw, 650px" /></p>
<h3>Finally, it makes sense to test the functionality of the individual facade components:</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="atomic">it('should get individual Observable "stream" of vm data', (done) =&gt; {
    testFacade.vm$.subscribe((vm) =&gt; {
      expect(vm.size).toEqual(initStateMock.size);
      done();
    });
  });

  it('should update state values', (done) =&gt; {
    const updatedStateMock: TestBeerState = {
      beerArray: [
        {
          brand: 'Pabst Blue Ribbon',
          name: 'Two Hearted Ale',
          style: 'Merican Ale',
          hop: 'Sorachi Ace',
          alcohol: '2,9%',
        },
        {
          brand: 'Bud Light',
          name: 'La fin Du Monde',
          style: 'Stout',
          hop: 'Bullion',
          alcohol: '2,7%',
        },
      ],
      size: 2,
    };
    testFacade['updateState'](updatedStateMock);
    testFacade.vm$.subscribe((vm) =&gt; {
      expect(vm).toEqual(updatedStateMock);
      done();
    });
  });

  it('should update the size value', (done) =&gt; {
    const newSize = 9;
    const mockEvent = {
      target: {
        value: newSize,
      },
    };
    testFacade['updateSize'](mockEvent);
    testFacade.vm$.subscribe((vm) =&gt; {
      expect(vm.size).toEqual(newSize);
      done();
    });
  });

  it('should perform a mocked http request', (done) =&gt; {
    const httpMock: HttpTestingController = TestBed.inject(
      HttpTestingController
    );

    const mockResponse = {
      brand: 'Pabst Blue Ribbon',
      name: 'Two Hearted Ale',
      style: 'Merican Ale',
      hop: 'Sorachi Ace',
      alcohol: '2,9%',
    };

    testFacade['findBeerArray'](1);
    testFacade.vm$.subscribe((tb) =&gt; {
      expect(tb.beerArray).toBeTruthy();
      expect(tb.beerArray[0].brand).toBe(mockResponse.brand);
      expect(tb.beerArray[0].name).toBe(mockResponse.name);
      expect(tb.beerArray[0].style).toBe(mockResponse.style);
      expect(tb.beerArray[0].hop).toBe(mockResponse.hop);
      expect(tb.beerArray[0].alcohol).toBe(mockResponse.alcohol);

      done();
    });

    const mockRequest = httpMock.expectOne(
      'https://random-data-api.com/api/beer/random_beer?size=1'
    );
    mockRequest.flush(mockResponse);
  });</pre>
<p>The post <a href="https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/">How to build a PUSH based architecture in Angular &#8211; Facade Design Pattern</a> appeared first on <a href="https://nerd-corner.com">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/how-to-build-a-push-based-architecture-in-angular-facade-design-pattern/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
