December 20, 2022

What is the purpose of using tsconfig.json file ?

tsconfig.json file allows you to point the root level files and different compiler options to setup that require to compile a TypeScript based projects. The existence of this file in a project specifies that the given directory is the TypeScript project folder root.

Here is an example tsconfig.json file.

{
"compileOnSave": true,
"compilerOptions": {
        "target": "es5",
		"module": "system",
		"moduleResolution": "node",
		"noImplicitAny": true,
		"sourceMap": true,
        "removeComments": false
},
	"files": [
		"program.ts",
		"sys.ts"
	],
	"include": [
		"src/**/*"
	],
	"exclude": [
		"node_modules",
		"src/**/*.spec.ts"
	]
}

Lets understand what each option specifies:

  • compileOnSave: If sets true, it instructs the IDE to automatically compile the given TypeScript files and generate the output.
  • compilerOptions: It allows specifying additional options to the TypeScript compiler:
    • target: the language used for the compiled output, e.g. es5, es6.
    • module: the module manager used in the compiled output. system is for SystemJS, commonjs for CommonJS.
    • moduleResolution: the strategy used to resolve module declaration files (.d.ts files). With the node approach, they are loaded from the node_modules folder like a module (require('module-name'))
    • noImplicitAny: if sets false, Raise error on expressions and declarations with an implied any type.
    • sourceMap: if sets true, it will generate source map files to debug directly your application TypeScript files in the browser,
    • removeComments: if set, Remove all comments except copy-right header comments beginning with /*!
  • files: Gives a list of TypeScript files that will be included by the compiler. The URL of the files can be both relative or absolute.
  • include: Allows you to include a list of TypeScript files using the glob wildcards pattern.
  • exclude: Allows you to exclude a list of TypeScript files using the glob wildcards pattern.

Install TypeScript compiler in VS Code

If you need to run the typescript from VS Code terminal you need to install the typescript compiler either globally or in your workspace.

This typescript compiler will transpile the TypeScript code to JavaScript.

Following are the steps we need to install and compile TypeScript in VS Code.

  • Install node.js Package Manager (npm).
  • Install TypeScript globally (-g) by this command:
    npm install -g typescript
    
  • If want to install TypeScript locally in a single project, you can use this command:
    npm install --save-dev typescript
    
  • Test your install by checking the version.
    tsc --version
    

TypeScript HelloWorld:

Let's start with a simple Hello World example. Create a new folder HelloWorld and open in VS Code.

mkdir HelloWorld
cd HelloWorld
code .

Create a new file called helloworld.ts.

Add the following TypeScript code in helloworld.ts file.

let message: string = 'Hello World';
console.log(message);

To compile the TypeScript code, you can open the Integrated Terminal (Ctrl+`)

Run this command to compile helloworld.ts

tsc helloworld.ts

It will create a new helloworld.js JavaScript file in the same folder.

To run the javascript file, you can use this command:

node helloworld.js

It will run the javascript code and display the script output in console.

November 21, 2022

SQL Server Logins vs Database Users

Usually there is a confusion over logins and users in SQL Server, especially for new SQL Server users. Here I have summarized the points to help understand the difference between these two concepts.

SQL Login

  • SQL Login is for Authentication. Authentication can decide if we have permissions to access the server or not.
  • Login is created at the SQL Server instance level.
  • The logins will be assigned to server roles (for example, public, serveradmin, sysadmin etc).
  • Create Login:
    CREATE LOGIN [idrees_login] WITH PASSWORD = 'password-goes-here';
    
  • Assign Server-Role to Login:
    ALTER SERVER ROLE [sysadmin] ADD MEMBER [idrees_login]
    

SQL User

  • SQL Server User is for Authorization. Authorization decides what are different operations we can perform in a database. Permissions inside the database are granted to the database users, not the logins.
  • User is created at the SQL Server database level. We can have multiple users from different databases (one user per database) connected to a single login to a server. User will always mapped to a Login.
  • Users will be assigned to roles within that database (eg. db_owner, db_datareader, db_datawriter etc).
  • Create User:
    CREATE USER [idrees_user] FOR LOGIN [idrees_login];
    
  • Assign Database-Role to User:
    ALTER ROLE [db_owner] ADD MEMBER [idrees_user]
    

General:

  • Logins only allow you to access to server. If the login is not mapped to any database user, then it will not be allowed to access any objects in the database.
  • You can not have a (database) user without a (server) login.
  • You cannot speficy the crendentials for user. Since user is mapped to a login, the login credentials are user for connection access. The same login credentials will be used to access all the databases for which a user is mapped.
  • Within a database, the objects-level permissions will be granted/revoked on user.

SQL Server - Change Authentication mode from Windows to Sql Server Authentication

During SQL Server installation, the wizard allows to select the authentication mode. At that time you can pick the required authentication scheme as per your needs.

In case if you have selected the Windows Authentication, the server will not configure the SQL Authentication mode and will not setup the default 'sa' account.

At later time if you want to enable the SQL Authentication, following steps will be required:

  1. Enable SQL Server Authentication Mode:

    • In SQL Server Management Studio Object Explorer, right-click the Server node, and then click Properties.

    • On the Security page, under Server authentication, select SQL Server and Windows Authentication mode. Then click OK.

    • When it asks you to restart the SQL Server, click OK.
  2. Enable Existing Login account sa:

    • By default, the sa account remains disable (if Windows Authentication mode is selected during SQL Server installation).

      First step is to enable sa login.

      ALTER LOGIN sa ENABLE ;
      GO
      
    • Second step is to set strong password for login sa.

      ALTER LOGIN sa WITH PASSWORD = '[enter-strong-password-here]';
      GO
      

October 24, 2022

.NET Core - asp-append-version tag helper

To have better user experience and improve website's performance, modern browsers used to cache the static files like css, js and images. While it helps your website to perform better but it could also lead to serve stale files. If you have made any changes to your css, js or image files, the browsers will keep showing the old images until it refreshes it cache. Sometimes the users have to do a full refresh (Ctrl + F5 or Ctrl + R) for the browser to get latest or fresh content of these files.

In this case we need to tell the browser to get the new files from server to make sure that the user will always be served with latest files without doing full refresh on the browser.

Some ways to acheive this behavior could be:

  1. Every time you make any changes in the file content, also change the file name and its references.
  2. Another way is to add a random string behind the js, css or image url.

Here we will use the second approach to add a random string for these files urls.

The good news is that ASP.NET Core has in-build feature for this issue. We can use the tag helper:

asp-append-version="true" 

To enable this feature ON for particualr static file, we just need to add the above asp-append-version tag-helper/attribute as below.

CSS
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />    
JS 
<script src="~/js/site.js" asp-append-version="true"></script>
Image
<img src="~/images/logo.png" asp-append-version="true" />

After making these changes you can check the rendered html from browser source code or inspect element using browser's developer tools. It will be found that there is a random string attached behind file name.

If you make any change within the file content for css/js etc, when the next time browser will render it, it will fetch the fresh file from server because of different random string attached to the file URL.

CSS
https://localhost:7163/css/site.css?v=1Ip96t8Xk8GevF37Kz0Wu_1tuNyEZJcH5PYrmiK1fNs

JS
https://localhost:7163/js/site.js?v=mC13cRUFjf1YiinDRFWfv-eOXac88lLptssglYLhYtQ

You will see a different random string appended each time the changes are made to the file cotent, which makes sure that the browser will fetch the latest copy from server.

October 19, 2022

Azure Devops - OpenSSL SSL_connect: Connection was reset in connection to dev.azure.com:443

While working with repos in Azure DevOps, sometimes it will display the following error when try to communicate with remote repo by push/pull commands.

OpenSSL SSL_connect: Connection was reset in connection to dev.azure.com:443

Usually you can get work around this error if you keep trying opening/closing Visual Studio etc.

With Git repos in Azure-DevOps, I found that it seems to have something to do with IPv6. After I disable the IPv6 from network connections, it works.

You can disable IPv6 by the following way:

  1. Open your Network Connections.

  2. Right click on your current network and select Properties.

  3. In the Network Properties dialog box, deselect Internet Prorotcol Version 6 (TCP/IPv6).

  4. Click OK to close the dialog.

September 19, 2022

How to add a custom HTTP header to WCF method call?

I have an environment with SOA architecture spans a number of WCF services. Some of these services need to identity its clients. Based on different client's identity or scope, the service needs to run different conditional code. One way to achieve this functionality is to add a custom http-header in each WCF method call on client side, which will enable WCF service to identity the client for any given request.

In this exmaple, I will add a custom http-header named Client-Id, using custom implemenation of IClientMessageInspector interace.

You need to create two classes

  1. One is CustomHeaderEndpointBehavior to implment IEndpointBehavior interface.
  2. Second is CustomHeaderMessageInspector which implements the IClientMessageInspector interface.

The CustomHeaderEndpointBehavior class will add our custom CustomHeaderMessageInspector to ClientMessageInspectors collection for clientRuntime object.

clientRuntime.ClientMessageInspectors.Add(customHeaderMessageInspector);

In CustomHeaderMessageInspector class, we can add the custom header in BeforeSendRequest() method.

Complete code listing for CustomHeaderMessageInspector class is:

public class CustomHeaderMessageInspector : IClientMessageInspector
{
   private const string CLIENT_ID_HTTP_HEADER = "Client-Id";
   private string _clientId;

   public CustomHeaderMessageInspector(string clientId)
   {
      this._clientId = clientId;
   }

   public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, 
                                 object correlationState)
   {

   }

   public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, 
                                   System.ServiceModel.IClientChannel channel)
   {
      HttpRequestMessageProperty httpRequestMessage;
      object httpRequestMessageObject;
		
      if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, 
                                         out httpRequestMessageObject))
      {
         httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
         if (string.IsNullOrEmpty(httpRequestMessage.Headers[CLIENT_ID_HTTP_HEADER]))
         {
            httpRequestMessage.Headers[CLIENT_ID_HTTP_HEADER] = this._clientId;
         }
      }
      else
      {
         httpRequestMessage = new HttpRequestMessageProperty();
         httpRequestMessage.Headers.Add(CLIENT_ID_HTTP_HEADER, this._clientId);
         request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
      }

      return request;
   }
}

Code listing for CustomHeaderEndpointBehavior class is:

public class CustomHeaderEndpointBehavior : IEndpointBehavior
{
   private string _clientId;

   public CustomHeaderEndpointBehavior(string clientId)
   {
      this._clientId = clientId;
   }

   public void AddBindingParameters(ServiceEndpoint endpoint, 
               System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
   {

   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, 
               System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
   {
      CustomHeaderMessageInspector inspector = new CustomHeaderMessageInspector(this._clientId);

      clientRuntime.ClientMessageInspectors.Add(inspector);
   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
               System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
   {

   }

   public void Validate(ServiceEndpoint endpoint)
   {

   }
}

When calling the service methods on the client side, you can simply add the custom EndpointBehavior (CustomHeaderEndpointBehavior) on the service client instance object.

ServiceReference1.Service1Client service1Client = new ServiceReference1.Service1Client();

var requestInterceptor = new CustomHeaderEndpointBehavior();
service1Client.Endpoint.EndpointBehaviors.Add(requestInterceptor);

Now you can call any service method, the custom htpp-header will be automatically added to each request.

Related Post(s):

How to trace soap xml from Web Service client?

In this post I will explain how to trace the raw xml for each request and response sent between client/server for Soap/WCF Services.

I found this idea/code from stackoverflow post:

how to trace soap xml as a webservice client in netcore? .

You need to create two classes

  1. One is InspectorBehavior to implment IEndpointBehavior interface.
  2. Second is MyMessageInspector which implements the IClientMessageInspector interface.

The InspectorBehavior class will use the ApplyClientBehavior() method to add the real message inspector by calling Add() method on ClientMessageInspectors collection for clientRuntime object.

clientRuntime.ClientMessageInspectors.Add(myMessageInspector);

Further in MyMessageInspector class, we can retreive and save the Request and Response Xml content in local variables/properties in these two methods.

  • BeforeSendRequest
  • AfterReceiveReply

Complete code listing for MyMessageInspector class is:

public class MyMessageInspector : IClientMessageInspector
{
   public string LastRequestXML { get; private set; }
   public string LastResponseXML { get; private set; }

   public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, 
                                 object correlationState)
   {
      LastResponseXML = reply.ToString();
   }

   public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, 
                                   System.ServiceModel.IClientChannel channel)
   {
      LastRequestXML = request.ToString();
      return request;
   }
}

Code listing for InspectorBehavior class is:

public class InspectorBehavior : IEndpointBehavior
{
   public string LastRequestXML
   {
      get
      {
         return myMessageInspector.LastRequestXML;
      }
   }

   public string LastResponseXML
   {
      get
      {
         return myMessageInspector.LastResponseXML;
      }
   }

   private MyMessageInspector myMessageInspector = new MyMessageInspector();

   public void AddBindingParameters(ServiceEndpoint endpoint, 
               System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
   {

   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
               EndpointDispatcher endpointDispatcher)
   {

   }

   public void Validate(ServiceEndpoint endpoint)
   {

   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, 
               ClientRuntime clientRuntime)
   {
      clientRuntime.ClientMessageInspectors.Add(myMessageInspector);
   }
}

I used the WFC service instance created by Visual Studio template with default two methods GetData() and GetDataUsingDataContract();

When calling the service methods on the client side, you can simply add the custom EndpointBehavior (InspectorBehavior) on the service client instance object.

ServiceReference1.Service1Client service1Client = new ServiceReference1.Service1Client();

var requestInterceptor = new InspectorBehavior();
service1Client.Endpoint.EndpointBehaviors.Add(requestInterceptor);

After service method call, you can get the Request and Response Xml content by requestInterceptor's properties:

string str1 = service1Client.GetDataAsync(1).GetAwaiter().GetResult();
string req1Xml = requestInterceptor.LastRequestXML;
string res1Xml = requestInterceptor.LastResponseXML;

Here is the sample of raw sample I received by above call.

Request

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"
    >http://tempuri.org/IService1/GetData</Action>
  </s:Header>
  <s:Body>
    <GetData xmlns="http://tempuri.org/">
      <value>1</value>
    </GetData>
  </s:Body>
</s:Envelope>

Response

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <GetDataResponse xmlns="http://tempuri.org/">
      <GetDataResult>You entered: 1</GetDataResult>
    </GetDataResponse>
  </s:Body>
</s:Envelope>

Call the second method, and get the Request and Response Xml content by same properties:

ServiceReference1.CompositeType compositeType = new ServiceReference1.CompositeType();
compositeType.BoolValue = true;
compositeType.StringValue = "some text";

ServiceReference1.CompositeType compositeTypeRes = 
       service1Client.GetDataUsingDataContractAsync(compositeType).GetAwaiter().GetResult();
string req2Xml = requestInterceptor.LastRequestXML;
string res2Xml = requestInterceptor.LastResponseXML;

Here is the sample of raw sample I received by above call.

Request

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"
    >http://tempuri.org/IService1/GetDataUsingDataContract</Action>
  </s:Header>
  <s:Body>
    <GetDataUsingDataContract xmlns="http://tempuri.org/">
      <composite xmlns:d4p1="http://schemas.datacontract.org/2004/07/WcfService1" 
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <d4p1:BoolValue>true</d4p1:BoolValue>
        <d4p1:StringValue>some text</d4p1:StringValue>
      </composite>
    </GetDataUsingDataContract>
  </s:Body>
</s:Envelope>

Response

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <GetDataUsingDataContractResponse xmlns="http://tempuri.org/">
      <GetDataUsingDataContractResult xmlns:a="http://schemas.datacontract.org/2004/07/WcfService1" 
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:BoolValue>true</a:BoolValue>
        <a:StringValue>some textSuffix</a:StringValue>
      </GetDataUsingDataContractResult>
    </GetDataUsingDataContractResponse>
  </s:Body>
</s:Envelope>

References:

Related Post(s):

August 18, 2022

Angular - Configure application environments

You might have deployed the Angular application on different environments like staging, production etc. Each environment will need specific default configuration settings. These default settings may apply to the various builder target like build, serve and test.

The Angular CLI build, serve, and test commands can then replace the default file with the environment-specific file depending on the configuration name provided in the command argument.

Configure default values for specific environment

Each angular project contains src/environments/ folder, which contains the base configuration file, environment.ts. It provides the default environment settings. You can add additional environment files, such as production and staging, with settings specific to the intended environment.

For example:

myProject/src/environments
	environment.ts
	environment.prod.ts
	environment.staging.ts

The base file environment.ts, contains the default environment settings. For example:

export const environment = {
  production: false
};

The build command uses this file (environment.ts) as the build target when no environment is specified in the argument. You can add further variables as additional properties on the environment object.

For example, the following adds a new variable (apiUrl) to the default environment:

export const environment = {
  production: false,
  apiUrl: 'http://my-api-url-default'
};

You can add more configuration files, such as environment.prod.ts. The following shows the default values for production build target:

export const environment = {
  production: true,
  apiUrl: 'http://my-api-url-production'
};

Using environment-specific variables in your app

For example you have following applicaton structure to configure build targets for production and staging environments.

src
	app
		app.component.html
		app.component.ts
	environments
		environment.ts
		environment.prod.ts
		environment.staging.ts

To use the environment configurations, your components need to import the original environments file:

import { environment } from './../environments/environment';

This ensures that the applicaiton can find the configurations for specific build targets (environments) which you provided through build and serve commands. Note that, if you do not provide any environment in the command, then the default environment configuration will be used.

The following code in the component file (app.component.ts) uses the environment object with variables (production and apiUrl) defined in the configuration files above.

import { Component } from '@angular/core';
import { environment } from './../environments/environment';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor() {
    console.log(environment.production); // Logs 'false' for default environment
    console.log(environment.apiUrl); // Logs 'http://my-api-url-default' for default environment
  }
  title = 'app works!';
}

References:

August 14, 2022

Angular - Initial exceeded maximum budget

While deploying my Angular 11 project for production, I built the project with --prod.

ng build --prod

And I received the error message:

Error: budgets: initial exceeded maximum budget. 
Budget 6.00 MB was not met by 418.81 kB with a total of 6.41 MB.

To work around this error, first lets understand how budget is defined in Angular.

We can describe our Angular application as a set of compiled JavaScript files called bundles which are generated by the build process. Angular budgets allows us to configure expected sizes of these bundles. We can configure thresholds for conditions when we want to notify as warning or fail build with an error if the bundle size gets exceeded that limit.

As per Offical documentation:

As applications grow in functionality, they also grow in size. The CLI lets you set size thresholds in your configuration to ensure that parts of your application stay within size boundaries that you define.
You can specify size budgets for the entire app, and for particular parts.

To set the budget custom limit, open angular.json file and find budgets keyword.

It should look like:

    "budgets": [
       {
          "type": "initial",
          "maximumWarning": "2mb",
          "maximumError": "5mb"
       }
    ]

You can increase the maximumWarning value to prevent the warning, or maximumError value to change the limit for failed error message, i.e.:

    "budgets": [
       {
          "type": "initial",
          "maximumWarning": "4mb",
          "maximumError": "6mb"
       }
    ]

References:

July 25, 2022

TypeScript: How to Pass a Function as a Parameter

In JavaScript you can pass the callback functions as parameters when triggering other functions. In this post, we will see an example how to do the same in TypeScript.

Let see the following code:

function f1(callback) {
  console.log('f1() function called!');
  callback();
}

function f2() {
  console.log('f2() function called!');
}

f1(f2);

In this exmaple, we have two functions f1() and f2(). We are passing f2() function as a callback paramter to function f1(), which will internally call the function f2().

It seems all ok in Javascript. However we are not leveraging the power of TypeScript.

If we pass anything (other than function, e.g. number) as a parameter to f1(), it will be compiled successfully but gives the runtime error. To avoid this issue, we can define the type of the callback parameter as Function.

So the f1() function will become:

function f1(callback: Function) {
  console.log('f1() function called!');
  callback();
}

Here f1() is enforcing the paramter should be of type Function. If you will pass anything other than the Function type, you will get compile error.

If you want to also use the return type of the callback function (lets say the return type will be number), then this solution will not work. Because the Function type could not enforce TypeScript to pass a function with desired return type.

For this, you can use an arrow function expression that returns a type to provide a valid type definition.

Let’s modify the definition of the f1() function.

function f1(callback: () => number) {
  console.log('f1() function called!');
  const number = callback();
  console.log('callback() function returns value: ' + number);
}

This helps the code to be more predictable with TypeScript, and prevent the unexpected runtime behavior often caused by lack of type definition.

How to change angular port from 4200 to other

You might be using ng serve command to build and run the Angular project. By default it is using the port 4200. After successfull build you can access the application in the browser by visiting the link

	http://localhost:4200/

If you need to work on more than one application simultaneously, then the second application will not work, because the port will already be in use by the first application. Or there may the scenario where you just want to run the application on the port other than the default one.

Following are the ways you can use different port when building the angular application.

  1. You can specify the port each time when running ng serve command from the terminal using --port argument. Like this:

    	ng serve --port 4201
    
  2. For legacy applications, where you have angular-cli.json file. In this file you can specify the port in the defaults:

    	"defaults": {
    	  "serve": {
    		"port": 4201
    	  }
    	}
    
  3. For newer applications (@angular/cli@9.x and over), you can use angular.json file to specify a port per project

    	"projects": {
    		"myproject1": {
    			... (rest of project config settings)
    			"architect": {
    				"serve": {
    					"options": {
    						"port": 4201
    					}
    				}
    			}
    		}
    	}
    

June 20, 2022

Use ngIf else in angular template

In Angular template we can use if, if-then, if-else, if-then-else structures:

To acheive the required behavior, we have to create a template reference variable for the target element which needs to be shown in the given condition.

Lets say our component has boolean variable isValid, and we will check this variable in our example to display different UI elements based on truthy or falsy values.

Using simple if condition

For simple if condition, we can write:

<div *ngIf="isValid">
  this content will render when the isValid has truthy value.
</div>

Using if-then condition

We can also write the above code with if-then structure, which behaves exactly the same way as above, but have different syntax. We can write:

<div *ngIf="isValid;then thenBlock">
   this will never display
</div>
<ng-template #thenBlock>
   this content will render when the isValid has truthy value.
</ng-template>
Here we have defined a template reference variable (#thenBlock) on ng-template tag, and used it in the if-then structure to display it when this condition is true.

The above exmaple can also be written with ngIf and ngIfThen:

<ng-template [ngIf]="isValid" [ngIfThen]="thenBlock">
   this will never display
</ng-template>
<ng-template #thenBlock>
   this content will render when the isValid has truthy value.
</ng-template>

Using if-else condition

For case if with else, we can use ngIf and ngIfElse.

<ng-template [ngIf]="isValid" [ngIfElse]="elseBlock">
   this content will render when the isValid has truthy value.
</ng-template>
<ng-template #elseBlock>
   this content will render when the if condition is not truthy.
</ng-template>

Using if-then-else condition

We can also combine ngIf, ngIfThen, and ngIfElse.

<ng-template [ngIf]="isValid" [ngIfThen]="thenBlock" [ngIfElse]="elseBlock">
   this will never display
</ng-template>
<ng-template #thenBlock>
   this content will render when the isValid has truthy value.
</ng-template>
<ng-template #elseBlock>
   this content will render when the if condition is not truthy.
</ng-template>

Convert seconds to hh-mm-ss with JavaScript/TypeScript

I received this requirement while working on Angular application and developing the two-factor authentication screen with SMS OTP. This screen has the timer countdown to show remaining time in seconds (in mm:ss format) to enable the button to resend OTP.

I found two different functions to format the seconds in hh:mm:ss format.

In first method, you can manually perform the arithmetic operations to extract hours, minutes and seconds from given value.

Convert_Seconds_To_HHMMSS(seconds) {

      let hour = Math.floor(seconds / 3600);
      let minute = Math.floor((seconds % 3600) / 60);
      let second = seconds % 60;

      if(hour.toString().length === 1) {
            hour = `0${hour}`;
      }
      if(minute.toString().length === 1) {
            minute = `0${minute}`;
      }
      if(second.toString().length === 1) {
            second = `0${second}`;
      };

      let timeFormatted = `${hour}-${minute}-${second}`;

      return timeFormatted;
}

In second method, you can use one-liner solution using Date.toISOString() function.

new Date(seconds * 1000).toISOString().substring(11, 16)

If the seconds value is less than 3600 (less than an hour) or you don't want t show the hours in formatted string, and only need to show minutes and seconds (mm:ss), then simply change the arguments for substring() function to extract the required string part.

new Date(seconds * 1000).toISOString().substring(14, 19)

May 19, 2022

Configure IIS for CORS preflight OPTIONS request

To configure IIS to allow an ASP.NET app to receive and handle OPTIONS requests, we have to add the following configuration to the app's web.config file in the system.webServer > handlers section:

<system.webServer>
  <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    <remove name="OPTIONSVerbHandler" />
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" 
       type="System.Web.Handlers.TransferRequestHandler" 
       preCondition="integratedMode,runtimeVersionv4.0" />
  </handlers>
</system.webServer>

Since the default ExtensionlessUrlHandler-Integrated-4.0 module registration only allows GET, HEAD, POST, and DEBUG requests with extensionless URLs. We will replace this module by first removing it and add with different attribute values to allow OPTIONS requests to reach the app.

After making these configuration changes, if the application still not responding as expected then you need to check the IIS's Request Filtering. It might be the case that IIS disallows OPTIONS verb at the root web application level.

  • Open IIS Manager
  • Click on root application
  • Click on Request Filtering
  • If OPTIONS appears in list, remove that entry and re-add with with Allow Verb... context menu option.

References:

Related Post(s):

How Cross Origin Resource Sharing (CORS) Works

Browser security prevents a web page from making AJAX requests to another domain. This restriction is called the same-origin policy, which preempts a malicious site from reading sensitive data from another site. .

Cross Origin Resource Sharing (CORS) is a W3C standard that allows a server to lighten the same-origin policy. Because sometimes you might want to let other sites call your web API, in this case you have to configure CORS policy as per the requirements, so that the server can accept traffic for pre-defined scenarios and reject the calls otherwise.

You might enable the CORS using [EnableCors] attribute correctly in .Net Web API Project, but still the things don't work as per the expectation. So its important to understand how CORS works.

The CORS specification introduces several new HTTP headers that enable cross-origin requests. If a browser supports CORS, it sets these headers automatically for cross-origin requests; you don't need to do manually in your JavaScript code.

Lets say you are making an AJAX call to the API http://abc.com/api/test, from the website http://localhost:4201. Since the Origin header defines the domain of the source website which is making the request, in this case the Origin is http://localhost:4201

Here is an example of a cross-origin request representation:

(In Raw Format)

Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Host: http://abc.com/api/test
Origin: http://localhost:4201
Referer: http://localhost:4201/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0

If the server allows the request, it sets the Access-Control-Allow-Origin response header. The value of this header either matches the Origin header (if the given domain is allowed), or is the wildcard value * (if any origin is allowed).

(In Raw Format)

content-type: application/javascript
content-length: 678
access-control-allow-origin: *
date: Mon, 16 May 2022 09:31:51 GMT

If the response does not include the Access-Control-Allow-Origin header, the AJAX request fails, and the browser disallows the request.

Preflight Requests

For some CORS requests, the browser sends an additional request, called a "preflight request", before it sends the actual request for the resource.

Browser sends the preflight request in certain conditions. Following are conditions in which the browser will not send the preflight request:

  1. The request method is GET, HEAD, or POST
  2. The application sends only these request headers: Accept, Accept-Language, Content-Language, Content-Type, or Last-Event-ID (any other request header will cause the browser to send preflight request).
    • Note that this restriction applies to the headers which the application will add to the request by calling setRequestHeader() method on the XMLHttpRequest object. These request headers are called as author request headers in the CORS specification .
    • The headers set by the browser (like User-Agent, Host, or Content-Length) are excluded from this restriction.
  3. If the Content-Type header is set, its value could only be one of the following (any other value for this header will cause the browser to send preflight request):
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Here is an example of a preflight OPTIONS request:

(In Raw Format)

OPTIONS http://abc.com/api/test HTTP/2
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Access-Control-Request-Headers: myheader1
Access-Control-Request-Method: GET
Connection: keep-alive
Host: http://abc.com
Origin: http://localhost:4201
Referer: http://localhost:4201/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0

As seen in above example request, the pre-flight request uses the HTTP OPTIONS method. It includes two special headers:

  • Access-Control-Request-Method: The HTTP method that will be used for the actual request (GET method in this above example).
  • Access-Control-Request-Headers: A list of request headers that the application set on the actual request, myheader1 is a custom header set in above example. Note that this does not include headers that the browser sets itself.

Here is an example response, assuming that the server allows the request:

(In Raw Format)

HTTP/1.1 200 OK
Access-Control-Allow-Headers: myheader1
Access-Control-Allow-Origin: *
Content-Length: 0
Date: Mon, 16 May 2022 09:40:05 GMT

The response can include the Access-Control-Allow-Methods header that lists the allowed methods (not listed in above example). The Access-Control-Allow-Headers header lists the allowed headers. If the preflight request succeeds (as in above case), then the browser sends the actual request.

References:

Related Post(s):

April 25, 2022

Angular - Can't bind to 'x' since it isn't a known property of 'y'

In Angular 11, I got this error:

error NG8002: Can't bind to 'x' since it isn't a known property of 'my-component'.
  1. If 'my-component' is an Angular component and it has 'x' input, then verify 
       that it is part of this module.
  2. If 'my-component' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the 
       '@NgModule.schemas' of this component to suppress this message.
  3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.

Apparently it is telling the reasons behind it, but still it did not inform about which specific module is missing if you do not know it yourself.

While searching for my problem, I have found the following possible scenarios, which may cause this error.

  1. When you have defined a custom input field 'x' in your component, first thing to check is if the property 'x' is defined in your component with an proper Input() decorator.

    In Html:

    <my-component [someInputProperty]="someValue">
    	

    In .ts file:

    export class MyComponent {
    
      @Input()
      someInputProperty: string;
      ...
    }
    	
  2. Also check the spelling for property names (case-sensitive) to make sure its free from typo.

    In .ts file

    export class MyComponent {
    
      @Input()
      someInputProperty: string;
      ...
    }
    	

    In Html (wrong):

    <my-component [someinputproperty]="someValue">
    	

    Which should be (correct):

    <my-component [someInputProperty]="someValue">
    	
  3. If you have defined the component in a custom module, make sure that you have registered this component (or directive or pipe) class in NgModule's declarations array:

    @NgModule({
      ...
      declarations: [
    	...,
    	MyComponent
      ],
      ...
    })
    export class AModule { }
    	
  4. If you have defined the component in a custom module (AModule), and want to use it in another module (BModule). Make sure that you have registered this component (or directive or pipe) class in source (AModule) module's declarations array as well as exports array:

    @NgModule({
      ...
      declarations: [
    	...,
    	MyComponent
      ],
      ...
      exports: [
    	...,
    	MyComponent
      ],
    
    })
    export class AModule { }
    	
  5. For common Angular default attributes, we need to memorize the module needs to be imported. For example:

    • For ngFor attribute, we need to import CommonModule.
    • In a similar fashion, for ngModel we need to import FormsModule.

April 20, 2022

Angular CLI - Generate components in a specific folder

In Visual Studio Code, following are the methods that can be used to create a component in a specific directory.

Method 1: Open in Integrated Terminal

You want to create a component in a app/components folder as shown in the image below:

  • Right click on the folder in which you want to create component.
  • Select option Open in Integrated Terminal

  • It will open a new terminal pane with the selected path.

  • In new terminal, type the command to create new component:

       ng g c component1
    

Method 2: Copy Relative Path and Paste on Terminal

  • Right click on folder in which you want to create component
  • From context menu, select Copy Relative Path

  • On termincal, type cd, press space and then paste the copied path. It will change the current working directory.
  • Then you can run the command to create new component.

       ng g c component1
    

Method 3: Manually Type complete path on terminal

In create component command, append the full folder path before compnent name.

   ng g c path/from/app/folder/component1

In our exmaple, to create a component in components folder (which is a sub-folder inside app), the command will be:

   ng g c components/component1

If your application have multiple modules, you may want to specify the existing module in which you need to create new component.

   ng g c employee/component1 --module=employee/employee.module.ts

This command will create component in employee module.

March 21, 2022

Using JavaScript Object.assign() method

In this post, we will see how to use the JavaScript Object.assign() method to copy and merge objects.

The syntax of the Object.assign() method is:

Object.assign(target, ...sources)

The Object.assign() method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.

The Object.assign() invokes the getters on the source objects and setters on the target.

Clone an object

The following example uses the Object.assign() method to clone an object.

let book = {
    title: 'My Title'
};

let clonedBook = Object.assign({}, book);

console.log(clonedBook);
Output will contain the properties copied from source object.
{ title: 'My Title' }

Note that the Object.assign() only creates a shallow clone, not a deep clone.

Merge objects

The Object.assign() can merge two or more source objects into a target object which will contain properties consisting of all the properties of the source objects. For example:

let book = {
    title: 'My Title'
};

let bookTemplate = {
    noOfPage: 200,
    author: 'Author'
};

let bookPublishTemplate = {
    publisher: 'My Publisher',
    publishDate: '21-Mar-2022'
};

let newBook = Object.assign({}, book, bookTemplate, bookPublishTemplate);

console.log(newBook);
Output will contain the properties merged from all the source objects.
{
    title: 'My Title',
    noOfPage: 200,
    author: 'Author'
    publisher: 'My Publisher',
    publishDate: '21-Mar-2022'
}

If two or more source objects have the property with same name, the property of the later object overwrites the earlier one:

let book = {
    title: 'My Title'
};

let bookTemplate = {
    title: 'My Title from bookTemplate'
    noOfPage: 200,
    author: 'Author'
};

let bookPublishTemplate = {
    author: 'Author from bookPublishTemplate'
    publisher: 'My Publisher',
    publishDate: '21-Mar-2022'
};

let newBook = Object.assign({}, book, bookTemplate, bookPublishTemplate);

console.log(newBook);
Output will contain the properties merged from all the source objects, also the duplicate properties will be overwritten by the later source objects.
{
    title: 'My Title from bookTemplate'
    noOfPage: 200,
    author: 'Author from bookPublishTemplate'
    publisher: 'My Publisher',
    publishDate: '21-Mar-2022'
}

Angular - Add conditional css class

Angular provides multiple ways to add css classes based on conditions.

Lets say we have a div and we want to apply the classes myclass1, myclass2, myclass3 based on different conditions using a variable counter defined in the component class.

Following are the different snytax methods we can use to add css class with conditions.

Method # 1

Add myclass1, if the counter is equal to 1

    <div [class.myclass1]="counter === 1">

Method # 2

Add myclass1, if the counter is equal to 1

	<div [ngClass]="{'myclass1' : counter === 1}">

Add myclass2, if the counter is greater than 1

	<div [ngClass]="{'myclass2' : counter > 1}">

You can use the same syntax to add multiple classes with their own conditions, each class-condition pair will be spearated by a comma.

For example, here the myclass1 will be added if the counter's value is 1, myclass2 will be added if the counter's value is 2, and myclass3 if the counter has a value greater than 2

   <div [ngClass]="{'myclass1': counter === 1, 'myclass2' : counter === 2 }, 
        'myclass3' : counter > 2 }">

Method # 3

We can use the ternary operator to pick one of the two classes.

If the counter's value is 1, then myclass1 will be added, else myclass2 will be applied.

    <div [ngClass]="counter == 1 ? 'myclass1' : 'myclass2'">

Method # 4

You can write a function inside the component which will return the the class(es) to be added based on some complex condition.

    <div [class]="getClass(6)">

The function will return class names like this:

  getClass(count: number){
    var classList='';

    if(count === 1){
       classList = 'myclass1'; 
    }else if (count > 1 && count < 5){
        classList = 'myclass2';
    }else if(count > 5){
        classList = 'myclass2 myclass3';
    }
    return classList;
  }
}

February 24, 2022

Angular - Receive event notification from child component

Angular enables the components based development which helps you create small cohesive components to design the application in a manageable approach. This may also lead to a complex heirarchy among the components. Then you need a mechanism to communicate between these components which may be in two directions top-down and bottom-up.

In this post we will see an example of bottom-up approach to allow communication from the child component to the parent component.

Lets say we have two components, ParentComponent and ChildComponent, with structure like this.

<parent-component>
    <child-component />
</parent-component>

The child-component has a button called btnSearch, which needs to invoke the parent-component's function searchCalledByChild();

Lets walk through this example to see how we can achieve this behavior.

This is the child component's ts file:

// child.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-child-component',
  templateUrl: './child-component.component.html',
  styleUrls: ['./child-component.component.css']
})
export class ChildComponentComponent implements OnInit {
  count: number = 0;
  child_msg : string = "";

  constructor() { }

  ngOnInit(): void {
  }
  
  btnSearchClicked() {
    this.child_msg = "Clicked Counter: " + this.count++;
  }
}

This will display a string child_msg in html template, showing the counter for button clicks.

This is the parent component's ts file:

// parent.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-parent-component',
  templateUrl: './parent-component.component.html',
  styleUrls: ['./parent-component.component.css']
})
export class ParentComponentComponent implements OnInit {
	
  parent_msg : string = "";
  chil_msg_inside_parent : string = "";

 constructor() { }

  ngOnInit(): void {
  }
	
  //method in parent class, this needs to be invoked 
  //when button is clicked in child component
  searchCalledByChild(child_msg_received: string)
  {	
    this.parent_msg = "Message from parent component";
		
    //child_msg_received is the data passed from child component.
    this.chil_msg_inside_parent = child_msg_received;
  }
}

To enable the parent component to receive notification of child-component's event, we have to makes these changes in child-component's ts file:

First import Output and EventEmitter from '@angular/core'

import { Output, EventEmitter } from '@angular/core';

Decorate a property with @Output(). Here searchButtonClickedEvent is the name of the property declared as EventEmitter, which means it's an event.

@Output() searchButtonClickedEvent = new EventEmitter<string>();

The type parameter we passed to EventEmitter<> tells angular that this event will emit the string data.

Raise this event from child-component's local method btnSearchClicked() using the emit() function.

btnSearchClicked() 
{
   this.child_msg = "Clicked Counter: " + this.count++;

   this.searchButtonClickedEvent.emit(this.child_msg);
}

Here is the html template for child-component:

<div style="background-color:grey;margin:10px;padding:10px;">
   <button id="btnSearch" (click)="btnSearchClicked()">Click child</button>
   <p>Child Content: {child_msg}}</p>
</div>

Now the child component is ready to emit events whenever the btnSearchClicked() function is called. In this example we are calling this function from child-component's button click.

To enable the parent-component to receive this event, we will bind the parent' local method to the child's event. To bind the event we will use the same event property of EventEmitter we have defined in the child-component.

<div style="background-color:tan;margin:10px; padding:10px;">
   
   <app-child-component 
         (searchButtonClickedEvent)="searchCalledByChild($event)">
   </app-child-component>
   
   <p>{{parent_msg}}</p>
   <p>Parent Content: {{chil_msg_inside_parent}}</p>
   
</div>

This event binding, (searchButtonClickedEvent)="searchCalledByChild($event), connects the event in the child (searchButtonClickedEvent) to the function in the parent(searchCalledByChild).

The $event parameter contains the data that we have passed from the child-compoment in the emit() function.

The complete listing of the parent-component's ts file will be look like this:

// parent.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-parent-component',
  templateUrl: './parent-component.component.html',
  styleUrls: ['./parent-component.component.css']
})
export class ParentComponentComponent implements OnInit {
	
  parent_msg : string = "";
  chil_msg_inside_parent : string = "";

 constructor() { }

  ngOnInit(): void {
  }
	
  //method in parent class, this needs to be invoked 
  //when button is clicked in child component
  searchCalledByChild(child_msg_received: string)
  {	
    this.parent_msg = "Message from parent component";
		
    //child_msg_received is the data passed from child component.
    this.chil_msg_inside_parent = child_msg_received;
  }
}

References:

Related Post(s):

Angular-Redux/Store Missing Dependencies Error

I was trying to use redux in my Angular 11.0.4 application but I was getting error as:

Error: The target entry-point "@angular-redux/store" has missing dependencies 
- redux-devtools-extension

I installed the following dependencies, which helps fix above error:

  • npm install redux --save
  • npm install redux-devtools --save
  • npm install redux-devtools-extension --save

If you get the following error:

  error TS2420: Class 'NgRedux' incorrectly implements interface 'ObservableStore'.
  Property '[Symbol.observable]' is missing in type 'NgRedux' 
  but required in type 'ObservableStore'.

It is because of the versions conflict among redux packages. To fix this, uninstall above packages and install with specific versions. For Angular 11.0.4, I found following packages helpful:

  • npm install --save redux@4.0.1
  • npm install --save @angular-redux/store@^9

January 24, 2022

Angular - Call child component method from parent component

Angular enables the components based development which helps you create small cohesive components to design the application in a manageable approach. This may also lead to a complex heirarchy among the components. Then you need a mechanism to communicate between these components which may be in two directions top-down and bottom-up.

In this post we will see an example of top-down approach to allow communication from the parent component to the child component.

Lets say we have two components, ParentComponent and ChildComponent, with structure like this.

<parent-component>
    <child-component />
</parent-component>

The parent-component has a button called Search, which needs to invoke the child-component's method loadData();

Lets walk through this example to see how we can achieve this behavior.

This is the child component's ts file:

// child.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'child-component',
    template: '<p>{{ message }}</p>'
})

class ChildComponent {
    message: String = 'Hello World!';

    loadData() {
        console.log('loading data from service');
    }
}

This is the parent component's ts file:

// parent.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'parent-component',
    template: `
        <child-component />
	<button (click)="parentLocalMethod()">Call Child Component Method</button>    
	`
})

export class ParentComponent {

    parentLocalMethod() {
	//here we need to call the child component's method
    }
}

To enable the parent component to invoke child-component's method, we have to makes these changes in parent-component's ts file:

First import ViewChild from '@angular/core'

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

Import the ChildComponent class iteself:

import { ChildComponent } from '../components/child.component';

To enable the access for child-component, we can inject the child component into the parent with the help of ViewChild decorator.

@ViewChild('childComponentTemplateVariable') tempChildComponent: ChildComponent;

Where childComponentTemplateVariable passed to the ViewChild decorator is the template variable (with # symbol) we need to set in the parent template's html for child-component tag:

<child-component #childComponentTemplateVariable />

Finally we can call the child-component's method by using the variable we have defined with ViewChild decorator. Like:

tempChildComponent.loadData();

The complete listing of the parent-component's ts file will be look like this:

// parent.component.ts
import { Component, OnInit, ViewChild  } from '@angular/core';

@Component({
    selector: 'parent-component',
    template: `
        <child-component #childComponentTemplateVariable />
	<button (click)="parentLocalMethod()">Call Child Component Method</button>    
	`
})

export class ParentComponent {

    @ViewChild('childComponentTemplateVariable') tempChildComponent: ChildComponent;

    parentLocalMethod() {
	//calling child-component's method
	tempChildComponent.loadData();
    }
}

ngAfterViewInit

When working with child components using the ViewChild decorator, an important thing to consider is the ngAfterViewInit lifecycle hook.

Respond after Angular initializes the component's views and child views, or the view that contains the directive.

The child component isn't available until after Angular displays the parent view. So if you are planning to process something once the view is loaded, then the best approach could be to use the ngAfterViewInit lifecycle hook to process any initialization code.

In the example above, we have called the child-components method from a button click event on the parent-component.

In case if we need to call the child-components method right after the view is loaded, then we can use the lifecycle hook ngAfterViewInit. To use the ngAfterViewInit we have to import the reference for the interace AfterViewInit and then define the ngAfterViewInit hook body.


import { Component, OnInit, ViewChild, AfterViewInit  } from '@angular/core';

//...

ngAfterViewInit() {
tempChildComponent.loadData();
}

References:

Related Post(s):

January 20, 2022

What is Redux Library

When the application size grows in terms of codebase and number of components, the state management become one of the major issues. There are many different options to achieve centeral state management, one of which is the Redux library.

Redux is a library for managing and updating application state. It helps you manage the "global" state that is required by different parts of your application. Redux serves as a centralized store for state that needs to be accessed across the entire application. It asks you to follow certain restrictions and rules to ensure that the state can only be updated in a certain manner to achieve a predictable behavior.

Redux is useful in scenarios like:

  • Large amount of application state is needed to be shared in different parts of the app
  • The app state is updated frequently
  • Application has complex logic for state update
  • Large application codebase

Redux organizes the application state in a single data structure called as store. The different components of the application read the state from this store. Having the restrictive rules, it ensures that the store is never be mutated directly. A reducer function is used to make the new state by combining the old state and the mutations defined by the action.

Following are the basic elements of Redux:

  • Store

    The store is a single JS object. Usually you need to add a TypeScript file to the project with a new interface type declaration. This interface will contain all the properties that are required to keep in the store.

  • Actions

    Actions are plain JS objects that represent something that has happened or triggered. Can be compared to events.

  • Reducers

    A reducer is a function that specifies the logic how the state changes in response to an action (or event). An important point here is the fact that a reducer function does not modify the state, it always returns a new state object by merging the old state object with the new modifications.

    A reducer function must always be a pure function, means that the function must ensure that if the same input is provided, then always the same output is produced.

    For example, the following reducer function takes the old state and return the increment by adding 1 to the the state property count. This way, it will always return the same new state if the old state do not have any changes. Hence the the same input will always produce the the same output.

    function reducer(state, action) {
      switch (action.type) {
    	case: 'INCREMENT':
    	   return { count: state.count + 1 };
      }
    }
    	

References: