Sunday, 3 February 2019

Angular content projection










Content projection helps us create reusable components. In Angular 1, this is called transclusion. Let us understand content projection, with an example. We want to create a reusable accordion type of control. The panel heading must be clickable, and when clicked the panel body and footer must be collapsed. Clicking on the panel heading again, must expand the collapsed panel body and footer.  


Another important requirement is, this accordion panel must be reusable with any other component in our application. The component that uses this accordion panel component, must be able to specify what content it wants in the accordion panel body and footer. 

angular 2 ng-content select multiple 

For example, if we use this accordion panel, with a ProductComponent that displays a product, then in the accordion panel body, the ProductComponent may want to project and display product image, price, weight etc. In the footer, the ProductComponent may want to project and display buttons to customise the product or buy. 

In our case we want to use this accordion panel, with DisplayEmployeeComponent. So in the panel body we want to project and display, employee photo, gender, date of birth, email etc. In the footer, we want to project and display buttons to View, Edit and Delete employee as shown below. 

angular content projection

So the important question that we need to answer is, how will the components that use this accordion component be able to inject variable content into the acoordion panel body and footer. 
By using <ng-content> tag

As you can see in the image below, you can think of this <ng-content> as a place holder for the variable content. In a bit we will understand, how a component that uses this accordion component can project variable content depending on the requirements of your application.  

angular 2 transclusion example 

First, let's create our reusable accordion component. This is a reusable component and can be used by another component in our application. So, let's place this component in the "Shared" folder. Use the following Angular CLI command to create the component.
ng g c shared/accordion --flat

accordion.component.ts : Notice, in the component class we have introduced 3 properties. The code is commented and self-explanatory. 

export class AccordionComponent implements OnInit {
  // We use this property to set a different CSS class on the employee
  // panel if we have just viewed his details
  @Input() hasJustViewed: boolean;
  // Sets the panel title, in our case the name of the employee
  @Input() title: string;
  // Controls hiding and showing panel body and footer
  @Input() isHidden = false;

  constructor() { }

  ngOnInit() {
  }
}

accordion.component.css : The "pointerCursor" class makes the cursor a pointer when hovered over panel title, so the end user knows, it is clickable. 

.pointerCursor {
    cursor: pointer;
}

accordion.component.html : As you can see, we have defined the shell for the accordion panel i.e accordion panel header, body and footer. We also have encapsulated the logic in this component to show and hide the panel body and footer. But the content that goes in the panel body and footer will be decided by the component that consumes this accordion component. The consuming component will also need to bind and pass data for the 3 input properties (title, isHidden and hasJustViewed). 

<!-- Add panel-success class only if hasJustViewed property is true -->
<div class="panel panel-primary" [class.panel-success]="hasJustViewed">
    <!-- pointerCursor class changes the cursor style to pointer when hovered
             over the employee panel title. When clicked on the title, isHidden
             boolean property is toggled from true to false & vice-versa. We use
             this property to toggle the visibility of panel body & footer -->
    <div class="panel-heading pointerCursor" (click)="isHidden = !isHidden">
        <h3 class="panel-title">{{title | uppercase}}</h3>
    </div>
    <div class="panel-body" [hidden]="isHidden">
        <!-- ng-content specifies the slot into which the content will be projected
               by the component that consumes this accordion component -->
        <ng-content select=".myPanelBody"></ng-content>
    </div>
    <div class="panel-footer" [hidden]="isHidden">
        <!-- Another slot into which the content can be projected. Since we have more
               than one slot into which the content can be projected, this is called
               multi-slot content projection-->
        <ng-content select=".myPanelFooter"></ng-content>
    </div>
</div>

Changes in display-employee.component.html : The changes are commented and self-explanatory. 

<!-- Pass employee name as the value for title input property. Also set
     isHidden input propety to false if you want the panel body and footer
     to be collapsed on the initial page load.-->
<app-accordion [title]="employee.name" [isHidden]="true"
[hasJustViewed]="selectedEmployeeId === employee.id">
<!-- Notice myPanelBody css class is present on this <div>. This CCS class is
used as the selector on the <ng-content> tag in accordion component. So all this
content in this DIV will be projected at the location where we have <ng-content>
tag with css class selector .myPanelBody -->
<div class="col-xs-10 myPanelBody">
  <div class="row vertical-align">
    <div class="col-xs-4">
      <img class="imageClass" [src]="employee.photoPath" />
    </div>
    <div class="col-xs-8">

      <div class="row">
        <div class="col-xs-6">
          Gender
        </div>
        <div class="col-xs-6">
          : {{employee.gender}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Date of Birth
        </div>
        <div class="col-xs-6">
          : {{employee.dateOfBirth | date}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Contact Preference
        </div>
        <div class="col-xs-6">
          : {{employee.contactPreference}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Phone
        </div>
        <div class="col-xs-6">
          : {{employee.phoneNumber}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Email
        </div>
        <div class="col-xs-6">
          : {{employee.email}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Department
        </div>
        <div class="col-xs-6" [ngSwitch]="employee.department">
          :
          <span *ngSwitchCase="1">Help Desk</span>
          <span *ngSwitchCase="2">HR</span>
          <span *ngSwitchCase="3">IT</span>
          <span *ngSwitchCase="4">Payroll</span>
          <span *ngSwitchDefault>N/A</span>
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Is Active
        </div>
        <div class="col-xs-6">
          : {{employee.isActive}}
        </div>
      </div>

    </div>
  </div>
</div>
<!-- The content in the following DIV will be projected at the location
where we have <ng-content> tag with css selector .myPanelFooter -->
<div class="myPanelFooter">
  <button class="btn btn-primary" (click)="viewEmployee()">View</button>
  <button class="btn btn-primary" (click)="editEmployee()">Edit</button>
  <span *ngIf="confirmDelete">
    <span>Are you sure you want to delete ?</span>
    <button class="btn btn-danger" (click)="deleteEmployee()">Yes</button>
    <button class="btn btn-primary" (click)="confirmDelete=false">No</button>
  </span>
  <span *ngIf="!confirmDelete">
    <button class="btn btn-danger" (click)="confirmDelete=true">Delete</button>
  </span>
</div>
</app-accordion>

At the moment we are using class selector to match the projection content with the ng-content slot. We can use any of the CSS selectors (class selector, element selector, attribute selector etc) 

Friday, 1 February 2019

Managing Subscriptions in Angular With the Async Pipe



If..Then..Else

The ngIf directive gets a nice improvement in Angular version 4.0.0. It’s been the target of many critiques even in AngularJS (v1.x) because of the lack of an “else” clause. In order to simulate if-then-else blocks in Angular templates, we had to use two ngIf directives with opposed boolean conditions.
<div *ngIf=”isLoggedIn()”>
   Hi, {%raw%}{{ user.name }}{%endraw%}
</div>
<div *ngIf=”!isLoggedIn()”>
   You’re not logged in.
</div>
In Angular version 4 we now get an “else” instruction as part of the ngIf directive. We can thus transform the above template to the following:
<div *ngIf="isLoggedIn(); else notLoggedIn">
    Hi, {%raw%}{{ user.name }}!{%endraw%}
</div>
<ng-template #notLoggedIn>
    You're not logged in.
</ng-template>

Better Observables support in templates

RxJS and Observables are already heavily being used within Angular, even when it comes to rendering async data into a template. When we execute an HTTP call with Angular, we get an Observable in return.
import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Component({
  selector: 'users-list',
  template: `
    <ul>
      <li *ngFor="let user of users">
        {%raw%}{{ user.username }}{%endraw%}
      </li>
    </ul>
  `
})
export class UsersListComponent {
  users;
  
  constructor(private http: Http) {  }

  ngOnInit() {
    this.http
        .get('/api/users')
        .map(res => res.json())
        .subscribe((data) => {
          this.users = data;
        });
  }
}
In this example, we use the Observable’s subscribe function to register a callback for when the data is retrieved from our backend API. Once we have the data, we assign it to a local variable of our component, users, which in turn is data-bound on the ngFor in our template. The async pipe which is already present in Angular version 2, allows to write this in a more elegant way:
import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Component({
  selector: 'users-list',
  template: `
    <ul>
        <li *ngFor="let user of users$ | async">
            {%raw%}{{ user.username }}{%endraw%}
        </li>
    </ul>
  `
})
export class UsersListComponent {
  users$;

  constructor(private http: Http) {  }

  ngOnInit() {
    this.users$ = this.http
        .get('/api/users')
        .map(res => res.json());
  }
}
We can directly assign the returned Observable to our users$ variable and bind it in our template. The Async Pipe (.. users$ | async) handles the subscription and unsubscription on the Observable for us, which makes it really convenient for directly binding asynchronous data in our templates.
Note, the “$” suffix in our variable name is simply a naming convention to communicate this variable holds an Observable.
Learn how to use the async pipe to write elegant, RxJS powered async code
There’s one caveat though. We cannot access the collection within our template.Consider for instance if we wanted to enumerate the position of the rendered user entry in the collection with respect to the total number of entries.

Enumerate *ngFor loops using as and async pipes

While in version 2 we had to fallback to subscribing to the Observable in the component class, Angular version 4 now gives us a possibility to handle such scenario by assigning the async result from the Observable to a template variable: .. of users$ | async as users. A template variable is a variable declaration in our template, just like the user in our ngFor loop statement.
import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Component({
  selector: 'users-list',
  template: `
      <ul>
        <li *ngFor="let user of users$ | async as users; index as i">
          {%raw%}{{ user.username }} ({{ i }} of {{ users.length }}){%endraw%}
        </li>
      </ul>
  `
})
export class UsersListComponent {
  users$;

  constructor(private http: Http) {  }

  ngOnInit() {
    this.users$ = this.http
        .get('/api/users')
        .map(res => res.json());
  }
}

Leveraging the as keyword with *ngIf

Using the as keyword also works with ngIf. Within the ngIf expression we can again directly use the Observable and assign it to a template variable. Hence, once the asynchronous call resolves, we can render that data in our template.
import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Component({
  selector: 'users-list',
  template: `
    <div *ngIf="user$ | async as user">
        Hi, {%raw%}{{ user.name }}!{%endraw%}
    </div>
  `
})
export class UserLoginComponent {
  user$;

  constructor(private http: Http) {  }

  ngOnInit() {
    this.user$ = this.http
        .get('/api/auth/currentuser')
        .map(res => res.json());
  }
}
Check out my Egghead video lesson on how to leverage the new else clause in the *ngIftogether with the async pipe for creating a loading indicator.
{% assign video_title = “Show a loading indicator in Angular using *ngIf/else, the as keyword and the async pipe” %} {% assign video_url = “https://egghead.io/lessons/show-a-loading-indicator-in-angular-using-ngif-else-the-as-keyword-and-the-async-pipe" %} {% assign affiliate_client = “eggheadio” %} {% assign affiliate_uid = “lessons/show-a-loading-indicator-in-angular-using-ngif-else-the-as-keyword-and-the-async-pipe” %} {% include video-banner.html %}

Conclusion

These two additions to the ngIf and ngFor directives makes working with Observables directly within the templates a lot easier and more convenient.
Try them out by yourself with this runnable Plunker.

Monday, 28 January 2019

Interview Questions

- Interceptor in Angular
-data binding in angular
-temp vs table variable
-how AOT implmented in angular
-router outlet in angular
-nested objects in entity framework
-idempotence in webapi
-attribute routing in webapi
-passing values in angular
-bundling in angular
-rootscope in angular
-binding in angular
-directive in angular
-ngcontent in angular
-access modifiers in abstract class
-can we define private in abstract class
-memory management in c#
-CLR
-print string multiple combinations ABC in c#
-difference between in temp table and table varible
-how to override url in angular like override the localhost:4200 port
-how to secure the url in angular
-local storage vs session storage vs cookies in angular
-lazy loading in angular and entity framework
-route vs route children in angular
-how to communicate between the component in angular
-how angular understand <app-root> tag in html
-how the application start in angualr
-cors , how actually it works
-http vs http2
-find nth prime no
-formatters in webapi and can we get both format xml vs json to the client
-singleton pattern
-strategy pattern
-kesteral vs weblistner in .net core
-asyn and await in c#
-microservices architectures and principles
-aop in c#
-filters in mvc
-how to add middleware in .net core
-whats startup.cs in .net core\
-how to increase the entity framework performance
-how to increase the performance from sql server database side
-fetch entity in linq
-polyfins in angular
-how to define foreign key relationship in entity framework
-deference b/w entity framework and core
-how to handle big data from database or webapi
-event hub in service bus azure
-microservice architecture and flow
- deadlock in sql server
-async and await
- oauth and jwt
-delegate and event
liskov principle
-anynymous method in c#
-




Monday, 26 November 2018

localStorage and sessionStorage in Angular 6

localStorage and sessionStorage, part of the web storage API, are two great tools to save key/value pairs locally. If you click the save button at the top of this post, localStorage is what’s used to store your saved posts.
Both localStorage and sessionStorage offer advantages compared to using cookies:
  • The data is saved locally only and can’t be read by the server, which eliminates the security issue that cookies present.
  • It allows for much more data to be saved (10Mb for most browsers).
  • It’s simpler to use and the syntax is very straightforward.
It’s also supported in all modern browsers, so you can use it today without an issue. Obviously, since the data can’t be read on the server, cookies still have a use, especially when it comes to authentication.

localStorage vs sessionStorage

localStorage and sessionStorage accomplish the exact same thing and have the same API, but with sessionStorage the data is persisted only until the window or tab is closed, while with localStorage the data is persisted until the user manually clears the browser cache or until your web app clears the data. The examples in this post are for localStorage, but the same syntax works for sessionStorage.

Creating Entries

Create key/value pair entries with localStorage.setItem, providing a key and a value:
let key = 'Item 1';
localStorage.setItem(key, 'Value');

Reading Entries

Read entries with localStorage.getItem:
let myItem = localStorage.getItem(key);

Updating Entries

Update an entry just as you would create a new one with setItem, but with a key that already exists:
localStorage.setItem(key, 'New Value');

Deleting Entries

Delete an entry with the removeItem method:
localStorage.removeItem(key);

Clearing Everything

Here’s how to clear everything that’s stored in localStorage:
localStorage.clear();

Storing Json Objects

Only strings can be stored with localStorage or sessionStorage, but you can use JSON.stringify to store more complex objects and JSON.parse to read them:
// Create item:
let myObj = { name: 'Skip', breed: 'Labrador' };
localStorage.setItem(key, JSON.stringify(myObj));

// Read item:
let item = JSON.parse(localStorage.getItem(key));

Checking for Items

Here’s how you can test for the presence of items in the loclaStorage:
if (localStorage.length > 0) {
  // We have items
} else {
  // No items
}

Checking for Support

Test for localStorage support by checking if it’s available on the window object:
if (window.localStorage) {
  // localStorage supported
}

Iterating Over Items

localStorage or sessionStorage don’t have a forEach method, but you can iterate over the items with a good old for loop:
for (let i = 0; i < localStorage.length; i++){
  let key = localStorage.key(i);
  let value = localStorage.getItem(key);
  console.log(key, value);
}

Recent Post

how to control duplicate order