Full Trust European Hosting

BLOG about Full Trust Hosting and Its Technology - Dedicated to European Windows Hosting Customer

AngularJS Hosting Europe - HostForLIFE :: Build Custom Audio Player With Audio Waveform In Angular

clock August 19, 2022 10:18 by author Peter

If you are working on a platform that needs to play some audio to a user, for example to sell an audio file, it's awesome to show its wave form. That way, the user will be impressed about the structure of the audio and of what your platform can do. To extract the information from the audio file, Web Audio API can be used. This allows you to extract frequency, waveform and other data from the audio file. Then, the received data from the audio source can be visualized as audio-waves. While dealing with the huge data that an audio waveform will have, drawing waveform smoothly and more quickly without lagging the web page is essential. As a developer, the performance of the page matters a lot, irrespective of the content shown on the page to the developer. So, I'm using CanvasJS chart to visualize the waveform. Note: CanvasJS can draw millions of datapoints in few milliseconds.


This tutorial shows how to create simple MP3 player using web audio API, and how to visualize audio files using CanvasJS. The underlying techniques work within plain JavaScript, Angular, React or any other JavaScript framework. In this case, I'm using Angular to create waveforms.

Browse & Read Audio File
The first step to play audio and visualize waveforms is to get the audio file. Let's add an input field to accept MP3 files. Here I've restricted it to allow the user to browse just MP3 files. However, web audio API supports WAV, MP3, AAC, OGG and other formats.
<input type="file" class="file-input"
       accept="audio/mp3"
       change)="onFileSelected($event)" #fileUpload>


Read Audio File
To fetch audio using the Web Audio API, we need to get an ArrayBuffer of audio data and pass it to a BufferSource. To get an audio buffer of the sound, you need to use the AudioContext.decodeAudioData method. The decoded AudioBuffer is resampled to the AudioContext's sampling rate, then passed to a callback or promise.
let margin = 10,
    chunkSize = 50,
    scaleFactor = (150 - margin * 2) / 2;
let audioContext = new AudioContext(),
    buffer = await file.arrayBuffer(),
    audioBuffer = await audioContext.decodeAudioData(buffer),
    float32Array = audioBuffer.getChannelData(0);
let array = [],
    i = 0,
    length = float32Array.length;
while (i < length) {
    array.push(float32Array.slice(i, i += chunkSize).reduce(function(total, value) {
        return Math.max(total, Math.abs(value));
    }));
}

Add Play / Pause & Stop Buttons
Add two buttons, one for play/pause and another to stop. When the audio is playing, the icon should show what the user can do by clicking that button. So, it will show the "Pause" icon when the audio is playing and "Play" icon when the audio is paused. To do this, we need to toggle between the play and pause states. In Web Audio API, you can check for the state of the audio-context, and based on the current state either resume the audio or suspend it.
togglePlaying = (event: any) => {
    if(audioContext.state === 'running') {
        audioContext.suspend().then(() => {
          buttonStatus = "Play";
        });
    }
    else if(audioContext.state === 'suspended') {
        audioContext.resume().then(() => {
          buttonStatus = "Pause";
        });
    }
}

When it comes to the stop option, this is pretty simple. Web Audio API has option to stop the source by calling stop() method.
stopPlaying = (event: any) => {
    source.stop();
}


Generate Datapoints from the Audio Data
CanvasJS supports varieties of chart types for different sets of data, including line, area, pie, range, and financial charts, etc. For our case, range-area suits well - it looks like audio waves. The only task for us to do is to generate datapoints, pass it to datapoints and call chart.render(). CanvasJS draws wave graphs like a charm.
let dps = []
for (let index in array) {
    dps.push({ x: margin + Number(index), y: [50 - array[index] * scaleFactor, 50 + array[index] * scaleFactor]});
}

this.chart.options.data[0].dataPoints = dps;
this.chart.render();


Add Audio Playing Effect to the Wave

When audio begins playing, it is an excellent idea to shade the region that has already played in the waveform. Add a stripline to show the shaded region in the chart and keep updating it every few milliseconds or second. Stop updating it once the audio stops playing.
source.onended = () => {
    chart.axisX[0].stripLines[0].set("endValue", chart.axisX[0].get("maximum"));
    clearInterval(intervalId);
}
let intervalId = setInterval(() => {
    chart.axisX[0].stripLines[0].set("endValue", audioContext.currentTime * (chart.data[0].dataPoints.length / audioBuffer.duration));
}, 250);


Yippee! You just built a custom audio player with play, pause and stop options, along with the audio waveform generated using CanvasJS range-area chart. You can also use column chart, range-column chart to show waves differently. You can even customize the look and feel of the audio player using simple CSS properties, and can match the same with the waveform by changing CanvasJS chart properties.

This waveform generated by CanvasJS chart can be integrated with an audio/video player to make it more appealing to the user. Library has more customization options to change the look and feel, which gives you more flexibility to customize the chart look and feel to match with your website/player theme. In this tutorial, I have disabled chart interactivity so as to showcase only the waveform. However, CanvasJS supports interactivity where it shows tooltip and highlights when you hover over the chart.



European Visual Studio 2022 Hosting - HostForLIFE :: Automating NuGet Package Uploads

clock August 9, 2022 07:44 by author Peter

The Challenge
When maintaining a larger number of NuGet packages, updating to a new version can become a tedious task. You need to upload all new packages, if there are dependencies between the different packages you also need to be fast in order to avoid breaking your packages. However, this task can also be automated - here's how.

Creating an API key
First of all, you need to create an API key that allows to push new packages to the NuGet server. Once logged in, you can choose the corresponding menu from here:

On the following page you can then choose the key name, the actions available for this key and the packages this key should apply to. In this example, I've used a global pattern to allow uploading all packages starting with combit.ListLabel:


After clicking "Create" you'll have the only chance ever to copy/view the generated key - make sure to use this opportunity wisely. Also, note that keys do have an expiration date. After this, you need to regenerate the key.


Using the Key for Automated Uploads
The next step is to use this key for an automated upload, of course. We've created a rather sophisticated batch file for this purpose which I'm sharing here. All required input is queried from the user. As the owner of this batch file may upload any packages on your behalf, make sure to store it in a very secure path only. The nuget push is repeated for each applicable package at the end.

@ECHO OFF

REM ==================================================================================================================================================
REM CONFIGURATION BEGIN
REM DO NOT EDIT BEFORE THIS LINE!
REM ==================================================================================================================================================
SET MajorVersion=27

SET NuGetExePath=.\nuget.exe

SET ApiKey=<Your API key>
SET Server=https://api.nuget.org/v3/index.json

REM ==================================================================================================================================================
REM CONFIGURATION END
REM DO NOT EDIT AFTER THIS LINE!
REM ==================================================================================================================================================

ECHO INFO: The NuGet version must match the format "Major.Minor.Patch[-Suffix]" (see examples):
ECHO    27.0.0-alpha1
ECHO    27.0.0-beta1
ECHO    27.0.0-beta2
ECHO    27.1.0
ECHO    27.2.1

SET NugetVersionString=%MajorVersion%

:UserPrompt_PrereleaseVersion
ECHO.
SET "UserChoice_PrereleaseVersion="
SET /P "UserChoice_PrereleaseVersion=Enter Pre-release version (values: "alpha" or "beta" without quotes; press 'Enter' to proceed without Pre-release version): %NugetVersionString%.0.0-"

IF /I "%UserChoice_PrereleaseVersion%" == "" (
    GOTO UserPrompt_MinorVersion
) ELSE (
    SET NugetVersionString=%NugetVersionString%.0.0-%UserChoice_PrereleaseVersion%
    GOTO UserPrompt_PrereleaseVersionSuffix
)

:UserPrompt_PrereleaseVersionSuffix
ECHO.
SET "UserChoice_PrereleaseVersionSuffix="
SET /P "UserChoice_PrereleaseVersionSuffix=Enter Pre-release version suffix (values: "2" and higher without quotes; press 'Enter' to proceed with Pre-release suffix default "1"): %NugetVersionString%"

IF /I "%UserChoice_PrereleaseVersionSuffix%" == "" (
    SET NugetVersionString=%NugetVersionString%1
) ELSE (
    SET NugetVersionString=%NugetVersionString%%UserChoice_PrereleaseVersionSuffix%
)

GOTO UserPrompt_FinalWarning

:UserPrompt_MinorVersion
ECHO.
SET "UserChoice_MinorVersion="
SET /P "UserChoice_MinorVersion=Enter Minor version (values: "1" or higher without quotes; press 'Enter' to proceed with default "0"): %NugetVersionString%."

IF /I "%UserChoice_MinorVersion%" == "" (
    SET NugetVersionString=%NugetVersionString%.0
) ELSE (
    SET NugetVersionString=%NugetVersionString%.%UserChoice_MinorVersion%
)

GOTO UserPrompt_PatchVersion

:UserPrompt_PatchVersion
ECHO.
SET "UserChoice_PatchVersion="
SET /P "UserChoice_PatchVersion=Enter Patch version (values: "1" or higher without quotes; press 'Enter' to proceed with default "0"): %NugetVersionString%."

IF /I "%UserChoice_PatchVersion%" == "" (
    SET NugetVersionString=%NugetVersionString%.0
) ELSE (
    SET NugetVersionString=%NugetVersionString%.%UserChoice_PatchVersion%
)

GOTO UserPrompt_FinalWarning

:UserPrompt_FinalWarning
ECHO.
IF /I NOT "%UserChoice_PrereleaseVersion%" == "" (
    SET PackageSourcePath=\\srvchk\prod\LL%MajorVersion%\%UserChoice_PrereleaseVersion%%UserChoice_PrereleaseVersionSuffix%\NuGet
) ELSE (
    SET PackageSourcePath=\\srvchk\prod\LL%MajorVersion%\Release\%MajorVersion%.00%UserChoice_MinorVersion%\NuGet
)

SETLOCAL EnableExtensions EnableDelayedExpansion
SET "UserChoice_FinalWarning=N"
SET /P "UserChoice_FinalWarning=WARNING: This cannot be undone. Really upload NuGet packages for version "%NugetVersionString%" ("%PackageSourcePath%") [Y/N]? "
SET "UserChoice_FinalWarning=!UserChoice_FinalWarning: =!"

IF /I "!UserChoice_FinalWarning!" == "N" ENDLOCAL & GOTO :EOF
IF /I NOT "!UserChoice_FinalWarning!" == "Y" GOTO UserPrompt_FinalWarning

ENDLOCAL
GOTO Upload

:Upload
REM Push packages to server
ECHO.
ECHO Uploading packages...
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.AdhocDesign.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.AdhocDesign.Web.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.CassandraDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.FirebirdConnectionDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.MongoDBDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.MySqlConnectionDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.NpgsqlConnectionDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.NuoDbConnectionDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.OdbcConnectionDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.OleDbConnectionDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.RedisDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.ReportServerIntegration.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.SalesforceDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.SqlConnectionDataProvider.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.Web.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ListLabel%MajorVersion%.Wpf.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ReportServer%MajorVersion%.ClientApi.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%
%NuGetExePath% push "%PackageSourcePath%\combit.ReportServer%MajorVersion%.SharedTypes.%NugetVersionString%.nupkg" -ApiKey %ApiKey% -Source %Server%

PAUSE


The Result
Once executed, the package is uploaded and shows up with the newly created version. The result looks just like a "normal" upload, but the process is much less error prone and executed in a matter of seconds:


Wrapping Up
The presented batch file allows to automate the management of larger NuGet package zoos. We're using it successfully to maintain our roundabout 50 packages with 87k downloads on nuget.org. It will be a great help for others facing the same challenges.



AngularJS Hosting Europe - HostForLIFE :: How To Add Charts In Angular Material Components?

clock August 5, 2022 09:53 by author Peter

Angular Material is a UI component library based on material design, the UI standard developed by Google, that provides clean and intuitive components. Components can be easily integrated with angular apps, which helps in achieving elegant and consistent UI. You can also create beautiful dashboards using these components.

Dashboards generally contain charts representing useful data to make analysis easier. In this article, I will guide how to add charts in the material tab component. I will be using CanvasJS angular chart component, which supports 30+ chart types, like line, column, bar, pie, etc. This also makes our life easier using its simple API to customize the look and feel of the chart. It also comes with various features, like zooming, panning, export chart as image, etc. out of the box.

 

Steps By Steps Instructions
Step 1

Create a simple angular application using angular cli command. If you have already set up the angular application, you can skip this step.
ng new angular-charts-in-material-component

Step 2
Now, navigate to the project directory and install angular material using ng add command. This will also install Component Dev Kit(CDK), Animation Module. To make it simple, I will be using predefined themes and will enable BrowserAnimationModule.
ng add @angular/material

Step 3
Register and import the components in app.module.ts. In this tutorial, I will be using Material Tab Component (MatTabsModule). You can use other material components like dialog, expansion panel, etc. as per your needs.
import { MatTabsModule } from '@angular/material/tabs';
@NgModule({
    declarations: [
        AppComponent,
    ],
    imports: [..
        MatTabsModule.
    ],
    providers: [],
    bootstrap: [AppComponent]
})

Step 4
Now, we will add Material Tabs to the template file app.component.html. Add matTabContent directive attribute to each tab body so that content is shown only when it becomes active.
<div [@.disabled]="true">
  <mat-tab-group dynamicHeight>
    <mat-tab label="Column Chart">
    <ng-template matTabContent>
    </ng-template>
  </mat-tab>
  <mat-tab label="Pie Chart">
     <ng-template matTabContent>
     </ng-template>
  </mat-tab>
  <mat-tab label="Line Chart">
     <ng-template matTabContent>
     </ng-template>
   </mat-tab>
 </mat-tab-group>
</div>

Step 5
After adding tabs to the application, we will now add charts to individual tabs. Before doing that, we will need to install CanvasJS angular chart component and register it. Please refer to this tutorial for basic setup of chart components. After installing the chart components, we will define chart options for different charts to be shown inside individual tabs in our app.component.ts.
export class AppComponent {
    columnChartOptions = {
        animationEnabled: true,
        title: {
        text: 'Angular Column Chart in Material UI Tabs',
        },
        data: [
        {
            // Change type to "doughnut", "line", "splineArea", etc.
            type: 'column',
            dataPoints: [
            { label: 'apple', y: 10 },
            { label: 'orange', y: 15 },
            { label: 'banana', y: 25 },
            { label: 'mango', y: 30 },
            { label: 'grape', y: 28 },
            ],
        },
        ],
    };

    pieChartOptions = {
        animationEnabled: true,
        title: {
        text: 'Angular Pie Chart in Material UI Tabs',
        },
        theme: 'light2', // "light1", "dark1", "dark2"
        data: [
        {
            type: 'pie',
            dataPoints: [
            { label: 'apple', y: 10 },
            { label: 'orange', y: 15 },
            { label: 'banana', y: 25 },
            { label: 'mango', y: 30 },
            { label: 'grape', y: 28 },
            ],
        },
        ],
    };

    lineChartOptions = {
        animationEnabled: true,
        title: {
        text: 'Angular Line Chart in Material UI Tabs',
        },
        theme: 'light2', // "light1", "dark1", "dark2"
        data: [
        {
            type: 'line',
            dataPoints: [
            { label: 'apple', y: 10 },
            { label: 'orange', y: 15 },
            { label: 'banana', y: 25 },
            { label: 'mango', y: 30 },
            { label: 'grape', y: 28 },
            ],
        },
        ],
    };
}

Step 6
After adding the chart component, we will add the canvasjs-chart directive inside individual tab content with respective chart options defined in app.component.ts.
<div [@.disabled]="true">
<mat-tab-group>
  <mat-tab label="Column Chart">
    <ng-template matTabContent>
      <canvasjs-chart
        [options]="columnChartOptions"
        [styles]="{ width: '100%', height: '360px' }"
      ></canvasjs-chart>
    </ng-template>
  </mat-tab>
  <mat-tab label="Pie Chart">
    <ng-template matTabContent>
      <canvasjs-chart
        [options]="pieChartOptions"
        [styles]="{ width: '100%', height: '360px' }"
      ></canvasjs-chart>
    </ng-template>
  </mat-tab>
  <mat-tab label="Line Chart">
    <ng-template matTabContent>
      <canvasjs-chart
        [options]="lineChartOptions"
        [styles]="{ width: '100%', height: '360px' }"
      ></canvasjs-chart>
    </ng-template>
  </mat-tab>
</mat-tab-group>
</div>


Ta-da! We have successfully plotted a chart inside angular material tabs. Please check out this StackBlitz example for the complete working code.

To take this article to the next step, you can alos add charts inside different angular material components, like dialog, expansion panel, cards, etc. and create beautiful dashboards using it.

You can refer to this link if you want to know more about the other components in angular material. Also, check out this link if you are new to CanvasJS angular chart component and want to explore more about its customization and features.



Node.js Hosting Europe - HostForLIFE :: Difference Between Node Cache And Redis Cache

clock July 26, 2022 10:15 by author Peter

What is Caching and why it is required?
When the same response needs to be served multiple times, store the data in a temporary memory cache and it can be retrieved faster than the data retrieved from the storage layer for every single call. Caching is an ability of an application to duplicate the values for a specified period of time and serve the web request instantly.


These techniques will be effective when
    There is a need to call for a 3rd party API and the call counts
    Cost of data transfer between cloud and the server.
    Server response is critical based on the concurrent requests.

Types of server caching available in Node JS
    In-app memory Cache
    Distributed Cache

In-app memory Cache

Data storage and retrieval will be in the process of the app memory cache. In-app caching is achieved through NodeJS packages such as node-cache, memory-cache, api-cache, etc.,


Distributed Cache
Data storage and retrieval will be carried out in centralized distributed systems. Though many options are available in this category the most popular ones are Redis and Memcached.


Other aspects of these cache techniques
In the Node Cache, the cached data are accessible only in the current process. If there is a cluster deployed with load balancer then multiple caches need to be stored which leads to constant updating of the data in every system or otherwise the user fetches the wrong information.

Also, if the stored cache is not properly maintained it may result in out of memory failures since the same memory space is utilized. On the other hand if the application is restarted the cached data will be disposed.

Redis can handle the above limitations easily, still it increases the dependency of the system. And that system needs to be monitored constantly not only for the availability but also for the performance degradations, outages.

Though Redis offers features like replication, level of durability, clustering and high availability (HA) but simple node-cache will be easy if the application needs to be scaled up and down easily and quickly.

Static information stored in cache does not require a network call dependency. Node cache is faster to store and retrieve data with a TTL (Time To Live).

Things to consider before choosing the right Caching technique:
    Security risks for storing and retaining the data in the cache.
    Data object serialization is really required for storing the data.
    Prevention of App crash by handling cache failures due to memory leaks or unavailability.
    Policy creation for cache maximum size, expiration of the cached memory, frequency of writing data to cache.
    Calculating the advantages of using cached data for the application.

 



AngularJS Hosting Europe - HostForLIFE :: Angular HTTP (Web API Integration)

clock July 18, 2022 10:42 by author Peter

HttpClient is used to make HTTP requests like GET | POST | PUT | DELETE to back end server.


The Angular HTTP client module is firstly introduced in the Angular 4.3 version.

This new API is available in the package @angular/common/http. This is a replacement for the old HttpModule.

The HTTP Client makes use of the RxJs Observables. The Response from the HttpClient Is observable, hence it needs to be Subscribed.

Import HttpClient Module in Root Module

STEP 1
The first thing is to import the HttpClientModule in app.module.ts
import {
    HttpClientModule
} from '@angular/common/http';
imports: [
    HttpClientModule
],


Import Required Module in Component/Service and then Inject HttpClient service
import {
    HttpClient
} from '@angular/common/http';
constructor(public http: HttpClient) {}


STEP 2
Define your base URL of API and inject the HttpClient in service constructor then define your GET/POST/PUT/DELETE calls as shown below
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

import {  Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { User } from '../User';

@Injectable({
  providedIn: 'root'
})
export class UserService {
    private apiURL = "http://localhost:56299/api/"; //YOUR API URL
    httpOptions = {
        headers: new HttpHeaders({
            'Content-Type': 'application/json'
        })
    }
    constructor(private httpClient: HttpClient) {}
    getUsers(): Observable < User[] > {
        return this.httpClient.get < User[] > (this.apiURL + 'userapi/').pipe(catchError(this.errorHandler));
    }
    addUser(user: User): Observable < User > {
        return this.httpClient.post < User > (this.apiURL + 'userapi/', JSON.stringify(user), this.httpOptions).pipe(catchError(this.errorHandler))
    }
    getUsersByID(id: number): Observable < User > {
        return this.httpClient.get < User > (this.apiURL + '/userapi/' + id).pipe(catchError(this.errorHandler))
    }
    updateUser(user: User): Observable < User > {
        return this.httpClient.put < User > (this.apiURL + '/userapi/' + user.id, JSON.stringify(user), this.httpOptions).pipe(catchError(this.errorHandler))
    }
    removeUser(id: number) {
        return this.httpClient.delete < User > (this.apiURL + 'userapi/' + id, this.httpOptions).pipe(catchError(this.errorHandler));
    }
    errorHandler(error: {
        error: {
            message: string;
        };status: any;message: any;
    }) {
        let errorMessage = '';
        if (error.error instanceof ErrorEvent) {
            errorMessage = error.error.message;
        } else {
            errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
        }
        return throwError(errorMessage);
    }
}


STEP 3
In your component file subscribe to the service to get the response
//GET
this.userService.getUsers().subscribe((data: User[]) => {
    this.userList = data;
});
//DELETE
this.userService.removeUser(id).subscribe(() => {
    this.refreshUser();
});
//POST
this.userService.addUser(this.userform.value).subscribe((data: User) => {
    //Redirecting to user List page after save or update
    this.router.navigate(['/user']);
});
//PUT
this.userService.updateUser(this.userform.value).subscribe((data: User) => {
    //Redirecting to user List page after save or update
    this.router.navigate(['/user']);
});



AngularJS Hosting Europe - HostForLIFE :: Angular Forms

clock July 13, 2022 08:43 by author Peter

User INPUT data are collected using Angular forms.

There are two approaches by which we can create forms in angular.
    Template Driven Forms
    Model Driven Forms

1. TEMPLATE DRIVEN FORMS
First, we build a simple Contact form. The ngForm directive will convert it to the Template-driven form and create the top-level FormGroup control.\
Next, we use the ngModel directive to create the FormControl instance for each of the HTML form elements.
<form #contactForm="ngForm" (ngSubmit)="onSubmit(contactForm)">
  <h1 class="text-center"> <strong> ANGULAR TEMPLATE DRIVEN FORM DEMO</strong></h1>
  <br>
  <div class="container">
    <div class="row">
      <div class="col-md-6">
        <div class="mb-1">
          <label class="form-label" for="firstname">First Name</label>
          <div class="input-group">
            <input type="text" class="form-control" name="firstname" ngModel>
          </div>
        </div>
        <div class="mb-1">
          <label class="form-label" for="lastname">Last Name</label>
          <div class="input-group">
            <input type="text"  class="form-control" name="lastname" ngModel>
          </div>
        </div>
        <div class="mb-1">
          <label class="form-label" for="email">Email </label>
          <div class="input-group">
            <input type="text" class="form-control" id="email" name="email" ngModel>
          </div>
        </div>
        <div class="mb-1">
          <label class="form-label" for="gender">Geneder</label>
          <div class="input-group">
            <input type="radio" value="male" name="gender" ngModel> Male
            <input type="radio" value="female" name="gender" ngModel> Female
          </div>
        </div>
        <div class="mb-1">
          <label class="form-label" for="isMarried">Married</label>
          <div class="input-group">
            <input type="checkbox" name="isMarried" ngModel>
          </div>
        </div>
        <div class="mb-1">
          <label class="form-label" for="country">Country</label>

          <div class="input-group">
            <select name="country"  class="form-control" ngModel>
              <option [ngValue]="c.id" *ngFor="let c of countryList">
                {{c.name}}
              </option>
            </select>
          </div>
        </div>
        <div ngModelGroup="address">
          <div class="mb-1">
            <label class="form-label" for="city">City</label>
            <div class="input-group">
              <input type="text" class="form-control" name="city" ngModel>
            </div>
          </div>
          <div class="mb-1">
            <label class="form-label" for="street">Street</label>
            <div class="input-group">
              <input type="text" class="form-control" name="street" ngModel>
            </div>
          </div>
          <div class="mb-1">
            <label class="form-label" for="pincode">Pin Code</label>
            <div class="input-group">
              <input class="form-label" class="form-control" type="text" name="pincode" ngModel>
            </div>
          </div>
          <div class="mb-1">
            <div class="input-group">
              <button class="btn btn-primary" type="submit">Submit</button>
            </div>
          </div>

      </div>
      </div>
      <div class="col-md-6">
        <pre>Value : {{contactForm.value | json }} </pre>
        <pre>Valid : {{contactForm.valid}} </pre>
        <pre>Touched : {{contactForm.touched  }} </pre>
        <pre>Submitted : {{contactForm.submitted  }} </pre>
      </div>
    </div>
  </div>
  </form>


Next, we will submit the form data to the component class.
import { Component, OnInit } from '@angular/core';
export class country {
  id:string;
  name:string;

  constructor(id:string, name:string) {
    this.id=id;
    this.name=name;
  }
}
@Component({
  selector: 'app-templatedrivenform',
  templateUrl: './templatedrivenform.component.html',
  styleUrls: ['./templatedrivenform.component.css']
})
export class TemplatedrivenformComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }
  countryList:country[] = [
    new country("1", "India"),
    new country('2', 'USA'),
    new country('3', 'England')
  ];
  onSubmit(contactForm: { value: any; }) {
    console.log(contactForm.value);
  }

}

OUTPUT


2. MODEL DRIVEN FORMS (REACTIVE FORMS)
In Reactive forms we define the structure of the form in the component class. i.e. We define the form model with Form Groups, Form Control and Form Arrays. And then we define validation rules in the component class. And finally, we bind it to the HTML form in the template.
How to use Reactive Forms

    Import ReactiveFormsModule
    Defining Form Model in the component
    Create the HTML Form uses the Form Model properties.Bind the HTML Form to the Form Model

1. Import ReactiveFormsModule
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

 imports: [

     //  Angular Form Modules
    FormsModule,
    ReactiveFormsModule
  ],


2. Defining Form Model in the component
FormGroup Represents a collection of form controls. It can also contain other Form Groups and FormArrays. In fact, an angular form is a FormGroup.

FormControl Encapsulates the state of a single form element in our form. It stores the value and state of the form element and helps us to interact with them using properties & methods.
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { UserService } from '../service/user.service';

@Component({
  selector: 'app-add-user',
  templateUrl: './add-user.component.html',
  styleUrls: ['./add-user.component.css']
})
export class AddUserComponent implements OnInit {

  id: number = 0;
  userform: FormGroup;

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private fb: FormBuilder,
    private userService: UserService
  ) {
    //**************Create Reactive Form with validation********************* */
    this.userform = this.fb.group({
      name: ['', [Validators.required]],
      mobile: ['', []],
      email: ['', [Validators.required, Validators.email, Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$')]],
      gender: ['', [Validators.required]],
      dob: [null, [Validators.required]],
      id: [0, [Validators.required]],
      isActive: [true],
      rating: [0, []],
      userType: ['', [Validators.required]],
    });

  }

  ngOnInit(): void {
    //**************Get User ID On Edit********************* */
    this.route.params.subscribe(params => {
      this.id = params['id'];
      if (params['id'] != null) {
        this.userform.get('Id')?.setValue(params['id']);
        const data = this.userService.getUsersByID(this.id);
        if (data) {
          this.userform.setValue(data);
        }
      }
    });
  }

  save() {
    if (this.userform.invalid) // true if any form validation fail
      return

    if (this.userform.get('id')?.value === 0) {
      // on Create New User
      this.userService.addUser(this.userform.value);
    } else {
      // on Update User info
      this.userService.updateUser(this.userform.value);
    }

    //Redirecting to user List page after save or update
    this.router.navigate(['/user']);
  }

}


3. User Form
<div class="container">
  <form [formGroup]="userform" autocomplete="off">
      <div class="mb-1">
          <label for="name" class="form-label">Name</label>
          <div class="input-group has-validation">
              <input type="text" #name [ngClass]="{'form-control': true, 'is-invalid': userform.get('name')?.invalid &&
              (userform.get('name')?.dirty || userform.get('name')?.touched)}" id="name" name="name"
                  formControlName="name" placeholder="Name">
              <div class="invalid-feedback">
                  This field is required.
              </div>
          </div>
      </div>
      <div class="mb-1">
          <label for="mobile" class="form-label">Mobile</label>
          <div class="input-group has-validation">
              <input type="number" maxlength="10" [ngClass]="{'form-control': true, 'is-invalid': userform.get('mobile')?.invalid &&
              (userform.get('mobile')?.dirty || userform.get('mobile')?.touched)}" id="mobile" name="mobile"
                  formControlName="mobile" placeholder="Mobile">
              <div class="invalid-feedback">
                  This field is required.
              </div>
          </div>
      </div>
      <div class="mb-1">
          <label for="rating" class="form-label">Rating</label>
          <div class="input-group has-validation">
            <input type="number" maxlength="10" [ngClass]="{'form-control': true, 'is-invalid': userform.get('rating')?.invalid &&
            (userform.get('rating')?.dirty || userform.get('rating')?.touched)}" id="rating" name="rating"
                formControlName="rating" placeholder="rating">
              <div class="invalid-feedback">
                  This field is required.
              </div>
          </div>
      </div>
      <div class="mb-1">
          <label for="email" class="form-label">Email</label>
          <div class="input-group has-validation">
              <input type="email" [ngClass]="{'form-control': true, 'is-invalid': userform.get('email')?.invalid &&
                  (userform.get('email')?.dirty || userform.get('email')?.touched)}" id="email" name="email"
                  formControlName="email" placeholder="[email protected]">
              <div class="invalid-feedback">
                  {{userform.get('email')?.hasError('required') ? 'This field is required.':'Invalid Email'}}
              </div>
          </div>
      </div>
      <div class="mb-1">
          <label for="DOB" class="form-label">DOB</label>
          <input type="date" [ngClass]="{'form-control': true, 'is-invalid': userform.get('dob')?.invalid &&
                  (userform.get('dob')?.dirty || userform.get('dob')?.touched)}" id="dob" name="dob"
                  formControlName="dob">
      </div>
      <div class="mb-1">
          <label for="email" class="form-label">Gender {{userform.get('gender')?.value}} </label>
          <div class="input-group has-validation">
              <select [ngClass]="{'form-select': true, 'is-invalid': userform.get('gender')?.invalid &&
                  (userform.get('gender')?.dirty || userform.get('gender')?.touched)}"
                  aria-label="Default select example" formControlName="gender">
                  <option value=""> --Select--</option>
                  <option value="Male" selected="userform.get('gender')?.value=='Male'">Male</option>
                  <option value="Female" selected="userform.get('gender')?.value=='Female'">Female</option>
              </select>
              <div class="invalid-feedback">
                  This field is required.
              </div>
          </div>
      </div>
      <div class="mb-1">
          <label for="name" class="form-label">User Type</label>
          <div class="input-group has-validation">
              <div class="form-check form-check-inline">
                  <input class="form-check-input" formControlName="userType" type="radio" id="User" value="User">
                  <label class="form-check-label" for="User">User</label>
              </div>
              <div class="form-check form-check-inline">
                  <input class="form-check-input" formControlName="userType" type="radio" id="Admin" value="Admin">
                  <label class="form-check-label" for="Admin">Admin</label>
              </div>
          </div>
      </div>
      <div class="mb-1">
          <div class="form-check form-switch">
              <input class="form-check-input" type="checkbox" formControlName="isActive" id="isActive">
              <label class="form-check-label" for="isActive">Is Active</label>
          </div>
      </div>
      <div class="mb-1">
          <div class="btn-group" role="group" aria-label="Basic example">
              <button (click)="save()" [disabled]="userform.invalid" class="btn btn-primary" type="button">
                  {{id==0 || id==null ?'Save':'Update'}}</button>
              <button class="btn btn-secondary" type="button">Reset </button>
          </div>
      </div>

      <div class="mb-1">
          {{userform.value |json}}
      </div>
  </form>
</div>

OUTPUT

 



Node.js Hosting Europe - HostForLIFE :: How To Check If A File Exists In NodeJS?

clock July 6, 2022 10:29 by author Peter

Node.js comes bundled with the file system module which allows the developers to interact with the file system of the operating system. This module is commonly used to create, read, update, delete and rename a file. However, before we start performing the above-mentioned operations it is always a better idea to check if the file we're trying to access exists in the file system. And the file system module provides multiple ways to perform this check.
Using existsSync method

The easiest way to test if a file exists in the file system is by using the existsSync method. All you need to do is pass the path of the file to this method.
const fs = require('fs');
const path = './my-awesome-file.txt';

if (fs.existsSync(path)) {
  console.log('file exists');
} else {
  console.log('file not found!');
}


The existsSync method will return true if the file exists and else it'll return false.
One thing that we need to keep in mind is this method is synchronous in nature. that means that it’s blocking.

Using exists method (Deprecated)
The exists method checks for the existence of a file asynchronously. It accepts two parameters:
    Path to the file
    Callback function to execute once path is verified passing a boolean parameter value to the function as its argument.
const fs = require('fs');
const path = './my-awesome-file.txt';

fs.exists(path, function (doesExist) {
  if (doesExist) {
    console.log('file exists');
  } else {
    console.log('file not found!');
  }
});


The parameter value will be true when the file exists otherwise it'll be false.

Using accessSync method
The accessSync method is used to verify the user’s permission for the specified path. If the path is not found, it will throw an error that we need to handle using try...catch block.

This method accepts two parameters as follows,
    Path to the file
    Mode of verification

The mode parameter is optional. It specifies the accessibility checks that need to be performed.0

Following constants can be used as the second parameter to specify the mode.
      fs.constants.R_OK to check for read permission
    fs.constants.W_OK to check for write permission
    fs.constants.X_OK to check for execute permission

If the second parameter is not provided it defaults to  fs.constants.F_OK constant.
const fs = require('fs');
const path = './my-awesome-file.txt';

try {
  fs.accessSync(path);
  console.log('file exists');
} catch (err) {
  console.log('file not found');
  console.error(err);
}

The above code verifies the existence of my-awesome-file.txt file:

If you wish to determine the write and read access, you can pass the mode parameter with a bitwise OR operator as follows:
const fs = require('fs');
const path = './my-awesome-file.txt';

try {
  fs.accessSync(path, fs.constants.R_OK | fs.constants.W_OK);
  console.log('read/write access');
} catch (err) {
  console.log('no access:');
  console.error(err);
}


Using access method
The access method is basically the asynchronous version of accessSync method.

The access method allows the developers to verify the existence or permissions of a specified path asynchronously.

The method accepts three parameters, first two parameters are the same as accessSync method parameters, and last parameter is a callback function:
    Path to the file
    Mode of verification
    The callback function to execute

const fs = require('fs')
const path = './my-awesome-file.txt'

fs.access(path, fs.F_OK, (err) => {
  if (err) {
    console.error(err)
    return;
  } else {
    console.log('file exists')
  }
})


existsSync, exists, accessSync, and access are the four methods that allow the developers to verify if the file exists in the file system. It’s recommended to use existsSync method if you only wish to check for the existence of a file. When you wish to check for specific permissions as well as the existence of the file, you can use either accessSync or access method. The exists method is deprecated from node.js and hence needs to be avoided. 



AngularJS Hosting Europe - HostForLIFE :: Angular 14 New Features

clock July 1, 2022 08:53 by author Peter

How to install Angular 14?
Angular 14 could be installed via npm using the next flag.

Simply open a new command line interface and run the following command to install the latest version of Angular:
    npm install --global @angular/cli@next

This will install the latest version of Angular CLI globally on your development machine.

Check the angular CLI version using below command
    ng version

Angular 14 Features
1. Standalone Components
With the release of Angular 14, standalone components will, at last, be a feasible option, and Angular modules will no longer be required.

A standalone component is not declared in any existing NgModule, and it directly manages its own dependencies (instead of having them managed by an NgModule) and can be depended upon directly, without the need for an intermediate NgModule.

Key Points
    Standalone component has the flag "standalone" we need to set the value true.
    Not Required to add the standalone component in ngModule.
    We can import the required modules in the component itself.
    Command,
    ng g c standalonedemo --standalone

import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
    selector: 'app-standalonedemo',
    standalone: true,
    imports: [CommonModule],
    templateUrl: './standalonedemo.component.html',
    styleUrls: ['./standalonedemo.component.css']
})
export class StandalonedemoComponent implements OnInit {
    constructor() {}
    ngOnInit(): void {}
}

<div class="container pages text-justify pb-5">
    <h1 class="mb-4">Angular 14 Standalone Component</h1>
    <p>standalonedemo works!</p>
</div>


2. Typed Forms
The most common request for an Angular feature on GitHub is for strictly typed forms, which, would improve the framework’s model-driven approach to the process of dealing with forms.
Key Points
    This feature is only for reactive forms.
    For using this feature tsconig.js should be in strict mode.
    Typed forms ensure that the values inside of form control, groups and array are type safe across the entire API surface.
    This helps developer for generating safer forms and it helps in case of complex nested object.
    If you want to use the older version you can use the untyped version.

E.g. create a contact us standalone component and add 4 fields in it (name, number, email, message) and import ReactiveFormsModule in it as shown below,
import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms';

@Component({
    selector: 'app-contactus',
    standalone: true,
    imports: [CommonModule, ReactiveFormsModule],
    templateUrl: './contactus.component.html',
    styleUrls: ['./contactus.component.css']
})
export class ContactusComponent implements OnInit {
    constructor() {}
    ngOnInit(): void {}
    contactForm = new FormGroup({
        name: new FormControl < string > (''),
        email: new FormControl(''),
        message: new FormControl(''),
        number: new FormControl()
    });
    contactFormUntyped = new UntypedFormGroup({
        name: new UntypedFormControl(''),
        email: new FormControl(''),
        message: new FormControl(''),
        number: new FormControl()
    });
    Submit() {
        console.log(this.contactForm.value);
        console.log(this.contactForm.value.email?.length); //check the null value
        console.log(this.contactForm.value.email!.length); //If you are sure value is not null
        console.log(this.contactFormUntyped.value.name.length); // throw error in browser
    }
}


<div class="container pages text-justify pb-5">
    <h1 class="mb-4">Angular 14  Typed Form</h1>
    <section class="mb-4">
        <!--Section heading-->
        <div class="row">
            <!--Grid column-->
            <div class="col-md-9 mb-md-0 mb-5">
                <form [formGroup]="contactForm" (ngSubmit)="Submit()">
                    <!--Grid row-->
                    <div class="row">
                        <!--Grid column-->
                        <div class="col-md-6">
                            <div class="md-form mb-0">
                                <input formControlName="name" type="text" class="form-control">
                                <label for="name" class="">Your name</label>
                            </div>
                        </div>
                        <!--Grid column-->
                        <!--Grid column-->
                        <div class="col-md-6">
                            <div class="md-form mb-0">
                                <input formControlName="email" type="text" class="form-control">
                                <label for="email" class="">Your email</label>
                            </div>
                        </div>
                        <!--Grid column-->
                    </div>
                    <!--Grid row-->
                    <!--Grid row-->
                    <div class="row">
                        <div class="col-md-12">
                            <div class="md-form mb-0">
                                <input formControlName="number" type="text" class="form-control">
                                <label for="subject" class="">Number</label>
                            </div>
                        </div>
                    </div>
                    <!--Grid row-->
                    <!--Grid row-->
                    <div class="row">
                        <!--Grid column-->
                        <div class="col-md-12">
                            <div class="md-form">
                                <textarea formControlName="message" type="text" rows="2" class="form-control md-textarea"></textarea>
                                <label for="message">Your message</label>
                            </div>
                        </div>
                    </div>
                    <!--Grid row-->
                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>
            <!--Grid column-->
        </div>
    </section>
</div>


3. Streamlined page title accessibility (Title Strategy)
Your page title shows the content of your page differently when you are developing applications. In Angular 13, the entire process of adding titles was streamlined with the fresh Route.title property in the Angular router. However, Angular 14 doesn't have more additional imports needed when you are adding a title to your page.

Go to the routing module where we define our routes now. We have a feature to add the title in the route and implement the TitleStrategy by extending the approuting module as shown.
import { NgModule } from '@angular/core';
import { RouterModule, RouterStateSnapshot, Routes, TitleStrategy } from '@angular/router';
import { ContactusComponent } from './contactus/contactus.component';
import { HomeComponent } from './home/home.component';
import { StandalonedemoComponent } from './standalonedemo/standalonedemo.component';

const routes: Routes = [
  {path:'',component:HomeComponent, title : "Core Knowledge Sharing"},
  { path: 'standalonedemo', component: StandalonedemoComponent, title : "Stand alone Component" },
  { path: 'contactus', component: ContactusComponent, title : "Contact Us" }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule extends TitleStrategy {
  updateTitle(snapshot: RouterStateSnapshot): void {
     const pageTitle = this.buildTitle(snapshot);
     if(pageTitle != undefined){
      document.title = "${pageTitle}"
     }
  }
}


4. Extended developer diagnostics (ng compilation)
This feature from Angular v14 delivers an extendable framework that assists better insights into your templates and offers suggestions for potential boosts. . It also checks the syntax error in our component like in contact us component you remove the reactive

E.g. you type the wrong command like ng sevre then it will give suggestion for right commands

5. Bind to protected component members
In v14, you can now bind to protected component members directly from your templates, thanks to a contribution from Zack Elliott!
@Component({
    selector: 'my-component',
    template: '{{ message }}',  // Now compiles!
})
export class MyComponent {
    protected message: string = 'Hello world';
}


6. Optional Injectors in Embedded Views
v14 adds support for passing in an optional injector when creating an embedded view through ViewContainerRef.createEmbeddedView and TemplateRef.createEmbeddedView. The injector allows for the dependency injection behavior to be customized within the specific template.

This enables cleaner APIs for authoring reusable components and for component primitives in Angular CDK.
viewContainer.createEmbeddedView(templateRef, context, {
  injector: injector,
})


7. NgModel OnPush
And finally, a community contribution by Artur Androsovych closes a top issue and ensures that NgModel changes are reflected in the UI for OnPush components.

I have two components: the first one is a simple child component with some input and basic support of [ngModel] directive via ControlValueAccesor interface. The second one is a parent component that has onPush change detection strategy and populates a value into child component via [ngModel] directive (right after that it's marked for changes via ChangeDetectorRef class). When [ngModel] is updated child component still displays an old value in the template while the component object has actual value in target property.
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';

@Component({
    selector: 'app-onpushdemo',
    template: `<div>
  <app-child [ngModel]="value"></app-child>
</div>`,
    styleUrls: ['./onpushdemo.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnpushdemoComponent implements OnInit {
    public value: any = "old value";
    constructor(private _changeDetector: ChangeDetectorRef) {
        setTimeout(() => {
            debugger;
            this.value = "new value";
            this._changeDetector.markForCheck();
        }, 5000)
    }
    ngOnInit(): void {}
}

import { Component, forwardRef, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
    selector: 'app-child',
    template: `<div (click)="click()">Current Value: {{value}}.
  Click me to force change detection</div>`,
    styleUrls: ['./child.component.css'],
    inputs: ['value'],
    providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => ChildComponent),
        multi: true
    }],
})
export class ChildComponent implements OnInit {
    constructor() {}
    public value: any;
    public onChange: (_: any) => void = (_: any) => {
        // do nothing
    };
    public onTouched: () => void = () => {
        // do nothing
    };
    public writeValue(value: any): void {
        this.value = value;
    }
    public click(): void {
        debugger;
        this.value = "child new value";
        // event just forces angular to re run change detection
    }
    public registerOnChange(fn: (_: any) => void): void {
        this.onChange = fn;
    }
    public registerOnTouched(fn: () => void): void {
        this.onTouched = fn;
    }
    ngOnInit(): void {}
}



AngularJS Hosting Europe - HostForLIFE :: Angular Pagination

clock June 29, 2022 08:01 by author Peter

Pagination is a very basic function that we need in every application. So let's try to understand how we can apply pagination in our angular app. To implement pagination we are using PrimeNG DataTable Pagination


What is PAGINATION?
Pagination is a component that displays page informations like page-number | total-records. To implement pagination we need to manipulate our data and split it into page collection.

Getting Started
First Install the required libraries
npm install bootstrap
npm install primeng
npm install primeicons
npm install @angular/cdk


Second add the reference in styles
"styles": [
   "node_modules/bootstrap/dist/css/bootstrap.min.css",
   "node_modules/primeng/resources/themes/saga-blue/theme.css",
   "node_modules/primeng/resources/primeng.min.css",
   "node_modules/primeicons/primeicons.css",
   "src/styles.scss"
 ],


Third register the module in app.module.ts file
import { TableModule } from 'primeng/table';

imports: [
      //  PrimeNG  Modules
      TableModule
  ]


Fourth step is to define the datatable. Now open the component.html file and add the ptable
<p-table></p-table>

Rows and TotalRecords
Rows, Rows Per Page, Current Page Report Template and other datatable options we need to define how many pages the paginator should display. Paginator below will have 10 rows per page.
<p-table [value]="userList" [paginator]="true" [rows]="10" [showCurrentPageReport]="true" responsiveLayout="scroll" currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries" [rowsPerPageOptions]="[10,25,50]">
</p-table>


Defining the table header
<ng-template pTemplate="header">
   <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Mobile</th>
      <th>DOB</th>
      <th>isActive</th>
      <th>Action</th>
   </tr>
</ng-template>

Defining the table body
<ng-template pTemplate="body" let-user>
   <tr [ngClass]="{'inActive': user.isActive == false}">
      <td>{{user.name}}</td>
      <td>{{user.email}}</td>
      <td>{{user.mobile}}</td>
      <td>{{user.dob | date:'d/M/yyyy'}}</td>
      <td>{{user.isActive}}</td>
      <td>
         <a pButton pRipple type="button" [routerLink]="['/update-user',user.id]" icon="pi pi-user-edit"
            class="p-button-rounded"></a>
         <a pButton pRipple type="button" (click)="remove(user.id)" style="margin-left: 5px;"
            icon="pi pi-trash" class="p-button-rounded"></a>
      </td>
   </tr>
</ng-template>


Defining table footer where we add various options like add new user
<ng-template pTemplate="paginatorleft">
            <a [routerLink]="['/add-user']" class="btn btn-primary">Add New</a>
</ng-template>


Complete Code
<div class="container" style="margin-top: 20px;">
    <p-table [value]="userList" [paginator]="true" [rows]="10" [showCurrentPageReport]="true" responsiveLayout="scroll"
        currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries"
        [rowsPerPageOptions]="[10,25,50]">
        <ng-template pTemplate="header">
            <tr>
                <th>Name</th>
                <th>Email</th>
                <th>Mobile</th>
                <th>DOB</th>
                <th>isActive</th>
                <th>Action</th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-user>
            <tr [ngClass]="{'inActive': user.isActive == false}">
                <td>{{user.name}}</td>
                <td>{{user.email}}</td>
                <td>{{user.mobile}}</td>
                <td>{{user.dob | date:'d/M/yyyy'}}</td>
                <td>{{user.isActive}}</td>
                <td>
                    <a pButton pRipple type="button" [routerLink]="['/update-user',user.id]" icon="pi pi-user-edit"
                        class="p-button-rounded"></a>
                    <a pButton pRipple type="button" (click)="remove(user.id)" style="margin-left: 5px;"
                        icon="pi pi-trash" class="p-button-rounded"></a>
                </td>
            </tr>
        </ng-template>
        <ng-template pTemplate="paginatorleft">
            <a [routerLink]="['/add-user']" class="btn btn-primary">Add New</a>
        </ng-template>
    </p-table>
</div>

Open the component file and add the below mentioned methods for pagination
import { Component, OnInit } from '@angular/core';
import { UserService } from '../service/user.service';
import { User } from '../User';

@Component({
    selector: 'app-user-list',
    templateUrl: './user-list.component.html',
    styleUrls: ['./user-list.component.css']
})
export class UserListComponent implements OnInit {
    userList: User[] = [];
    first = 0;
    rows = 10;
    constructor(private userService: UserService) {}
    ngOnInit(): void {
        // Get Users from UserService
        this.userList = this.userService.getUsers();
    }
    //****************PrimeNG DataTable Pagination method Start*********************** */
    //***************Reference: https://primefaces.org/primeng/showcase/#/table/page********** */
    next() {
        this.first = this.first + this.rows;
    }
    prev() {
        this.first = this.first - this.rows;
    }
    reset() {
        this.first = 0;
    }
    isLastPage(): boolean {
        return this.userList ? this.first === (this.userList.length - this.rows) : true;
    }
    isFirstPage(): boolean {
        return this.userList ? this.first === 0 : true;
    }
    //****************PrimeNG DataTable Pagination Method End*********************** */
    // ********************User To Remove User from User List*************************/
    remove(id: number) {
        this.userService.removeUser(id);
        this.userList = this.userService.getUsers();
    }
}


Run the application using npm start.



European Blazor Hosting - HostForLIFE :: Blazor Route Parameter

clock June 20, 2022 10:12 by author Peter

In this article, we are going to discuss route parameters in Blazor. A route parameter is defined in the URL by wrapping its name in a pair of {braces} along with @page declaration.

Example; @page “/employee/{employeeId}

For this tutorial I’m using Microsoft Visual Studio Community 2022 (64-bit) – Preview with Version 17.2.0 Preview 5.0.

Parameter value capture

Value of a parameter can be captured by simply adding a property with the same name and decorating it with an attribute [Parameter]
[Parameter]
public string FruitCode { get; set; }

For demo purposes, I’m using the Counter.razor component in which I am adding three anchor tags with parameter value
<li><a href="/counter/Orange">Orange</a></li>
<li><a href="/counter/Mango">Mango</a></li>
<li><a href="/counter/Apple">Apple</a></li>

The route will look like below
@page "/counter"
@page "/counter/{FruitCode}"


Here {FruitCode} is the parameter

When you click on Orange – the value “Orange” will be passed as parameter in the URL

If you look at the image, in the address bar, you can see that “Orange” has been passed and the same has been displayed as “Selected Fruit: Orange”. The entire code from Counter.razor component has been given below for reference.
@page "/counter"
@page "/counter/{FruitCode}"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<p role="banner"> Selected Fruite : @FruitCode</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<h1>Select a Fruit</h1>
<ul>
  <li><a href="/counter/Orange">Orange</a></li>
  <li><a href="/counter/Mango">Mango</a></li>
  <li><a href="/counter/Apple">Apple</a></li>
</ul>
@code {
    private int currentCount = 0;
 [Parameter]
    public string FruitCode { get; set; }
    private void IncrementCount()
    {
        currentCount++;
    }
}

Note
As we are navigating to the same page,

    The component will not be destroyed before navigation.
    OnInitialized lifecycle methods will not be executed.

Route Parameter Constraints
To define a constraint for a parameter it is suffixed with a colon and then the constraint type. For example, :int will only match the component’s URL if it contains a valid integer value in the right position.

The route looks like below
@page "/counter"
@page "/counter/{CurrentCount:int}"


Please refer to the Microsoft documentation for more details.
Thank you for reading my article. Please leave your comments in the comment box below.



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Tag cloud

Sign in