Full Trust European Hosting

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

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._%+-][email protected][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/[email protected]

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.



AngularJS Hosting Europe - HostForLIFE :: Show File Upload Progress With Multiple Files In Angular

clock June 15, 2022 08:47 by author Peter

This article demonstrates the file upload with progress bar indicator showing how bytes or percentage has been completed.

Create Angular application
Let's create an angular application using angular cli.

We need to have node.js and angular cli installed on our pc to get started with angular application.

First we have to make sure that node.js is installed. You can download node.js from here.

In order to make sure that we have Angular CLI installed, open the command prompt and type the below command and press Enter:
npm install -g @angular/cli

Create a new project with choice of your name by entering name in command prompt like this:
ng new FileUploadProgress

Let's create a service for file upload. code of angular service looks like this:
import { Injectable } from '@angular/core';
import { HttpHeaders, HttpClient, HttpEventType } from '@angular/common/http';
import { map } from 'rxjs/operators';

@Injectable()
export class MediaService {
  fileSizeUnit: number = 1024;
  public isApiSetup = false;

  constructor(private http: HttpClient) {}

  getFileSize(fileSize: number): number {
    if (fileSize > 0) {
      if (fileSize < this.fileSizeUnit * this.fileSizeUnit) {
        fileSize = parseFloat((fileSize / this.fileSizeUnit).toFixed(2));
      } else if (
        fileSize <
        this.fileSizeUnit * this.fileSizeUnit * this.fileSizeUnit
      ) {
        fileSize = parseFloat(
          (fileSize / this.fileSizeUnit / this.fileSizeUnit).toFixed(2)
        );
      }
    }

    return fileSize;
  }

  getFileSizeUnit(fileSize: number) {
    let fileSizeInWords = 'bytes';

    if (fileSize > 0) {
      if (fileSize < this.fileSizeUnit) {
        fileSizeInWords = 'bytes';
      } else if (fileSize < this.fileSizeUnit * this.fileSizeUnit) {
        fileSizeInWords = 'KB';
      } else if (
        fileSize <
        this.fileSizeUnit * this.fileSizeUnit * this.fileSizeUnit
      ) {
        fileSizeInWords = 'MB';
      }
    }

    return fileSizeInWords;
  }

  uploadMedia(formData: any) {
    const headers = new HttpHeaders().set('Content-Type', 'application/json');

    return this.http
      .post(`http://yourapiurl`, formData, {
        headers,
        reportProgress: true,
        observe: 'events',
      })
      .pipe(
        map((event) => {
          switch (event.type) {
            case HttpEventType.UploadProgress:
              const progress = Math.round((100 * event.loaded) / event.total);
              return { status: 'progress', message: progress };

            case HttpEventType.Response:
              return event.body;
            default:
              return `Unhandled event: ${event.type}`;
          }
        })
      );
  }
}


Here, if you see we have used HttpClient to send POST request with multi-part form data to the server.

Please check uploadMedia method in the above code. HttpClient's post method's third parameter expects options object. The notable properties in our case are reportProgress and observe.

In order to get the progress reportProgress must be set to true and observe must be set to 'events'.

Here, inside map function of rxjs, we will check for the event type in swtich case statements. Rather than using integer values to compare, we can use  HttpEventType enum provided by the package @angular/common/http. In our case, only two enum values are useful such as UploadProgress and Response.

In both cases, I have decided to use the common object having two properties such as status and message.

status can have two values such as 'progress' and 'completed', later one will be returned from the server which will be handled by case HttpEventType.Response.

Also, this service contains two other methods such as getFileSize and getFileSizeUnit. These methods will be used to show the file size and it's unit either bytes, KB or MB.

Let's see how to use this service into our component.

Let's create a new component and typescript code looks like this:
import { Component, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { MediaService } from '../media.service';

@Component({
  selector: 'app-media',
  templateUrl: './media.component.html',
  styleUrls: ['./media.component.css'],
})
export class MediaComponent implements OnInit {
  uploadedMedia: Array<any> = [];

  constructor(private mediaService: MediaService) {}

  ngOnInit() {}

  onFileBrowse(event: Event) {
    const target = event.target as HTMLInputElement;
    this.processFiles(target.files);
  }
  processFiles(files) {
    for (const file of files) {
      var reader = new FileReader();
      reader.readAsDataURL(file); // read file as data url
      reader.onload = (event: any) => {
        // called once readAsDataURL is completed

        this.uploadedMedia.push({
          FileName: file.name,
          FileSize:
            this.mediaService.getFileSize(file.size) +
            ' ' +
            this.mediaService.getFileSizeUnit(file.size),
          FileType: file.type,
          FileUrl: event.target.result,
          FileProgessSize: 0,
          FileProgress: 0,
          ngUnsubscribe: new Subject<any>(),
        });

        this.startProgress(file, this.uploadedMedia.length - 1);
      };
    }
  }

  async startProgress(file, index) {
    let filteredFile = this.uploadedMedia
      .filter((u, index) => index === index)
      .pop();

    if (filteredFile != null) {
      let fileSize = this.mediaService.getFileSize(file.size);
      let fileSizeInWords = this.mediaService.getFileSizeUnit(file.size);
      if (this.mediaService.isApiSetup) {
        let formData = new FormData();
        formData.append('File', file);

        this.mediaService
          .uploadMedia(formData)
          .pipe(takeUntil(file.ngUnsubscribe))
          .subscribe(
            (res: any) => {
              if (res.status === 'progress') {
                let completedPercentage = parseFloat(res.message);
                filteredFile.FileProgessSize = `${(
                  (fileSize * completedPercentage) /
                  100
                ).toFixed(2)} ${fileSizeInWords}`;
                filteredFile.FileProgress = completedPercentage;
              } else if (res.status === 'completed') {
                filteredFile.Id = res.Id;

                filteredFile.FileProgessSize = fileSize + ' ' + fileSizeInWords;
                filteredFile.FileProgress = 100;
              }
            },
            (error: any) => {
              console.log('file upload error');
              console.log(error);
            }
          );
      } else {
        for (
          var f = 0;
          f < fileSize + fileSize * 0.0001;
          f += fileSize * 0.01
        ) {
          filteredFile.FileProgessSize = f.toFixed(2) + ' ' + fileSizeInWords;
          var percentUploaded = Math.round((f / fileSize) * 100);
          filteredFile.FileProgress = percentUploaded;
          await this.fakeWaiter(Math.floor(Math.random() * 35) + 1);
        }
      }
    }
  }

  fakeWaiter(ms: number) {
    return new Promise((resolve) => {
      setTimeout(resolve, ms);
    });
  }

  removeImage(idx: number) {
    this.uploadedMedia = this.uploadedMedia.filter((u, index) => index !== idx);
  }
}


Now, add below code in HTML file of this component:
<h2>File upload with progress bar indicator</h2>
<input type="file" accept=".jpg,.jpeg,.png" (change)="onFileBrowse($event)" />
<div class="media-upload-table-container" *ngIf="uploadedMedia.length > 0">
  <table class="media-upload-table table table-borderless">
    <thead>
      <tr>
        <th style="width: 246px"></th>
        <th class="media-progress-bar"></th>
        <th style="width: 100px;"></th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let media of uploadedMedia; let i = index">
        <td>
          <div class="d-flex flex-row align-items-center">
            <!-- <div style="margin-right: 8px;">
                <img  class="add-media-img" src="{{media.FileUrl}}">
              </div> -->
            <div class="media-file-name">
              <span style="word-wrap: break-word; white-space: pre-line">
                {{ media.FileName }}
              </span>
            </div>
          </div>
        </td>
        <td style="vertical-align:middle;">
          <div class="d-flex flex-column" style="margin-top: 18px;">
            <div>
              <div class="first-progress">
                <div
                  [ngStyle]="{ 'width.%': media.FileProgress }"
                  class="second-progress"
                ></div>
              </div>
            </div>
            <div class="text-center">
              {{ media.FileProgessSize }} of {{ media.FileSize }}
            </div>
          </div>
        </td>
        <td style="vertical-align:middle;text-align: right;">
          <div class="media-upload-check">
            <span *ngIf="media.FileProgress === 100"> Completed</span>
          </div>
        </td>
        <td style="vertical-align:middle;">
          <a class="remove-media-txt" (click)="removeImage(i)"> Remove </a>
        </td>
      </tr>
    </tbody>
  </table>
</div>

If you see in above typescript code of the new component we have just created, there is a method startProgress. Here, we are using uploadedMedia array to keep track of the media uploaded by the user and it will show the progress of each uploaded file in the grid.

If you have noticed, our media service typescript code has one boolean flag isApiSetup. Here. We are using this flag to decide whether we want to upload files on actual server or not.

If you want to use the actual API of server then follow below steps,

  • Set value of isApiSetup to true and we will use the file upload on the server. here when 'progress' or 'completed' status received we will calculate file size and update it in the relevant object in the list.
  • Also, file object in the list has ngUnsubscribe property which is used in takeUntil operator of rxjs. So once, the user removes the file before 100% completion, we will send some value to it. So, file upload on the server will be canceled.

If you want to use the just fake waitor to simulate the working of file upload,

  • Set value of isApiSetup to false and we will use fake waiter to emulate the file upload rather than uploading the file on the server. It is useful if there is no api developed for file upload but still you want to check and modify and design of progress bar, percentage, file size etc. so, you don't have to rely on the api to test and modify the design.
  • In this case, fakeWaitor method will return the promise which will be resolved after a certain amount of time in parameter and this will be continuously done until for loop variable has reached to value of original file size.

Now, we need to use our component and service both in our application and for that we need to update app.module.ts file (which will be generated automatically by angular cli when new project is created).

Typescript code for app.module.ts looks like this,
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { MediaComponent } from './media/media.component';
import { MediaService } from './media.service';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
  imports: [BrowserModule, FormsModule, HttpClientModule],
  declarations: [AppComponent, MediaComponent],
  bootstrap: [AppComponent],
  providers: [MediaService],
})
export class AppModule {}


That’s it. Fire the following command to see the charm!
ng serve

Now, open your browser and visit this URL: http://localhost:4200/ to see it in action.

Here are a few snapshots of this application:




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