19
Sep
2018
Client Side Web Part – Image Gallery using SPFx in Modern Communication Site

In the modern era, most of the enterprises are moving their SharePoint development towards the cloud and they started migrating their intranet sites/contents to SharePoint online (Office 365). We see several updates in SharePoint online – Office 365, they are providing more user-friendly and lightweight components in the sites which are known as modern experience. Microsoft introduced the communication site as a new feature which is completely in new/modern user experience.

When SharePoint developers need customization, we used to deploy full trust C# assembly earlier in on-premises environment but it does not work in Office 365, so we used to inject JavaScript for customization and most favorite web part of SharePoint consultants is Script Editor, but Script Editor web part is also not a ‘Safe For Scripting’ web part.

To work with the customization and custom solution in modern user experience/communication sites, SPFx client-side web parts are being used. Further information can be covered in SharePoint consulting services.

We will create here Image Gallery web part, which displays albums as a thumbnail image and a click on each album displays carousel image slider related to that album. Albums and images will be fetched from the picture library, where each folder will be considered as an album and images inside the folder will be displayed in a slider. We will also add a custom column for the album’s thumbnail image. So let’s start step by step to create a dynamic image gallery web part in communication site.

Step 1 – To Create Picture Library

  1. Go to Site Contents, click on New  App.
  2. Click on Picture Library, give it name “Image Lib”:
  3. Picture Library

  4. Open created picture library and click on setting icon on upper right corner and click on Library Setting.
  5. Library setting

  6. Scroll down and click on “Create column”:
  7. create column

  8. Give column name “AlbumPicURL”, select type ‘Single line of text’, and click on Okay.
  9. single line of text

  10. Create few folders in this Image Lib Picture Library.
  11. Using Quick Edit, add URL of an image in AlbumPicURL property for each folder, that image will be viewed as thumbnail.

quick edit
Album Pic URL

Note: For security reasons we have erased URL, make sure to add full URL of the image.

Step 2 – To Create SPFx web part

We – SharePoint Programmers, assume that following prerequisites installed in your machine:

  • Nodejs
  • Yeoman
  • Gulp

For more information about setting up development environment refer this link:

https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-development-environment

  1. Open PowerShell.
  2. Create a new project folder
  3. md Image-Gallery
  4. Go to project folder
  5. cd Image-Gallery
  6. Create a new web part by running following command:
  7. yo @microsoft/sharepoint
  8. Enter ‘Image-Gallery’ as your solution name, and then select Enter.
  9. Select ‘SharePoint Online only (latest)’, and select Enter.
  10. Select ‘Use the current folder’ for where to place the files.
  11. Select ‘N’ to require the extension to be installed on each site explicitly when it’s being used.
  12. Select Web Part as the client-side component type to be created.
  13. Enter ‘Image-Gallery’ as your web part name, and then select Enter.
  14. Accept the default ‘Image-Gallery’ description as your web part description, and then select Enter.
  15. Accept the default No JavaScript web framework as the framework you would like to use, and then select Enter.
  16. No JavaScript web framework

  17. Once process will be completed, it will show success message like below:
  18. Suggested Message

  19. After that execute following command one by one:
  20. gulp trust-dev-cert
    npm install jquery --save
    npm install @types/jquery --save
    npm install bootstrap --save
    npm install @types/bootstrap --save

Step 3 – To Write Code for Image Gallery

♦ Here we will replace 3 files with the following code, lets replace each file one by one. To edit web part in visual code, enter below command in command window:

Code.

1.  ImageGalleryWebPart.module.scss

  • From the left pane, src webpart  imageGallery  ImageGalleryWebPart.module.scss
  • image gallery web part

  • Replace the following code to this file and save it.

ImageGalleryWebPart.module.scss

@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
 
.albumblock{
  position: relative;
    overflow: hidden;
    padding-bottom: 50px;
    background-color: #f5f5f5;
    width: 32%;
    float: left;
    height: 100px !important;
    margin-left: 1%;
    margin-top: 3%;
    cursor: pointer;
}
 
.album-info{
  background-color: rgba(0,0,0,0.65);
  color: #515155;
  font-size: 1.2em;
  color: white;
  padding: 10px;
  position: absolute;
  bottom: -7px;
  left: 0;
  right: 0;
  font-family: sans-serif;
  font-size: 16px;
  text-align: center;
  font-weight: normal;
  height: 33px;
  cursor: pointer;
 
  h3{
    margin: 0;
    cursor: pointer;
    padding: 0 0px 5px 0px;
    font-size: 1.2em;
    vertical-align: middle;
    font-family: DubaiBold;
  }
}
 
.imgGalleyTitle{
  float: left;color: white !important;
  margin: 0.2em !important;
  font-size: 22px !important;
}
 
.btnBackStyle{
  float: right !important;
  width: 100px !important;
  background-color: rgb(64, 82, 171) !important;
  color: white !important;
  height: 30px !important;
  text-transform: uppercase !important;
  cursor: pointer !important;
  border: 3px solid !important;
  margin: 0.7em !important;
}
 
.btnBackStyle:hover{  
  background-color:  white !important;
  color: rgb(64, 82, 171) !important;  
  background-color: 0e83cd !important;
}
 
.ImageGallery {
  .container {
    max-width: 1000px;
    margin: 0px auto;
    box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
  }
 
  .row {
    @include ms-Grid-row;
    @include ms-fontColor-white;
    background-color: $ms-color-themeDark;
    padding: 20px;
  }
 
  .list {
    color: #333333;
    font-family: 'Segoe UI Regular WestEuropean', 'Segoe UI', Tahoma, Arial, sans-serif;
    font-size: 12px;
    font-weight: normal;
    box-sizing: border-box;
 
    line-height: 50px;
    list-style-type: none;
    width: 25%;
 
   }
 
   .listItem {
    color: #333333;
    box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
    vertical-align: center;
    font-family: 'Segoe UI Regular WestEuropean', 'Segoe UI', Tahoma, Arial, sans-serif;
    font-size: 14px;
    font-weight: normal;
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    float: left;
    box-shadow: none;
    padding-top: 12%;
    *zoom: 1;
    height: 100px; 
    margin: 10;
    padding: 10;    
    margin: auto;   
    position: relative;
   }
 
  .column {
    @include ms-Grid-col;
    @include ms-lg10;
    @include ms-xl8;
    @include ms-xlPush2;
    @include ms-lgPush1;
  }
 
  .title {
    @include ms-font-xl;
    @include ms-fontColor-white;
  }
 
  .subTitle {
    @include ms-font-l;
    @include ms-fontColor-white;
    width: 100%;
    height: 100%;
  }
 
  .description {
    @include ms-font-l;
    @include ms-fontColor-white;
  }
 
  .button {
    // Our button
    text-decoration: none;
    height: 32px;
 
    // Primary Button
    min-width: 80px;
    background-color: $ms-color-themePrimary;
    border-color: $ms-color-themePrimary;
    color: $ms-color-white;
 
    // Basic Button
    outline: transparent;
    position: relative;
    font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
    -webkit-font-smoothing: antialiased;
    font-size: $ms-font-size-m;
    font-weight: $ms-font-weight-regular;
    border-width: 0;
    text-align: center;
    cursor: pointer;
    display: inline-block;
    padding: 0 16px;
 
    .label {
      font-weight: $ms-font-weight-semibold;
      font-size: $ms-font-size-m;
      height: 32px;
      line-height: 32px;
      margin: 0 4px;
      vertical-align: top;
      display: inline-block;
    }
  }
}

2. Config.json

  • From the left pane, Config  Config.json

Config.json

{
  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
  "version": "2.0",
  "bundles": {
    "image-gallery-web-part": {
      "components": [
        {
          "entrypoint": "./lib/webparts/imageGallery/ImageGalleryWebPart.js",
          "manifest": "./src/webparts/imageGallery/ImageGalleryWebPart.manifest.json"
        }
      ]
    }
  },
  "externals": {
    "jquery": {
      "path": "node_modules/jquery/dist/jquery.min.js",
      "globalName": "jquery"
    },    
    "bootstrap": {
      "path": "/Style%20Library/cwp/bootstrap/js/bootstrap.min.js",
      "globalName": "bootstrap",
      "globalDependencies": [
        "jquery"
      ]      
    }    
  },
  "localizedResources": {
    "ImageGalleryWebPartStrings": "lib/webparts/imageGallery/loc/{locale}.js"
  }
}

3. ImageGalleryWebPart.ts

  • Replace your tenant URL and Site Collection Name in yellow highlighted code.
  • From left pane, src  webpart  imageGallery  ImageGalleryWebPart.ts
<u><strong>ImageGalleryWebPart.ts</strong></u>
import { Version } from '@microsoft/sp-core-library';
import {
  BaseClientSideWebPart,
  IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';
import { SPComponentLoader } from '@microsoft/sp-loader';
 
import styles from './ImageGalleryWebPart.module.scss';
import * as strings from 'ImageGalleryWebPartStrings';
 
SPComponentLoader.loadCss('https://{tenant URL}/sites/{Site Collection Name}/Style%20Library/cwp/bootstrap/css/bootstrap.min.css');
 
 import('jquery'); 
require('bootstrap');
 
import {
  SPHttpClient,
  SPHttpClientResponse   
} from '@microsoft/sp-http';
 import {
  Environment,
  EnvironmentType
} from '@microsoft/sp-core-library';
export interface IImageGalleryWebPartProps {
    description: string;
}
 
export interface ISPListAlbums {
    value: ISPListAlbum[];
}
 
 export interface ISPListAlbum {
    Name: string;
    Id: string;  
    ServerRelativeUrl: string;
 
    ListItemAllFields:{AlbumPicURL:string;};
 }
 
 export interface ISPAlbumImages {
    value: ISPAlbumImage[];
 }
 
 export interface ISPAlbumImage {
    Name: string;
    Id: string;  
    ServerRelativeUrl: string;
 }
 
export default class ImageGalleryWebPart extends BaseClientSideWebPart<IImageGalleryWebPartProps> {
 
    public render(): void {
        this.domElement.innerHTML = `
     <div class="${ styles.ImageGallery }">
       <div class="${ styles.container }">
         <div id="spListContainer" />
       </div>
     </div>`;
 
this._renderListAlbumsAsync();
}
 
private _renderListAlbumsAsync(): void {
    // Local environment
    if (Environment.type == EnvironmentType.SharePoint || 
             Environment.type == EnvironmentType.ClassicSharePoint) {
                 this._getAlbumData()
                   .then((response) => {
                       console.log(response.value);
                       this._renderListAlbum(response.value);          
                       var spanTiles=this.domElement.querySelectorAll('div.tiles'), i;
                       for(i=0;i<spanTiles.length;i++)
                       {
                           spanTiles[i].addEventListener('click', (event) => {
                               this._ClickCalled(event);});
                       }
 
 
                   });        
             }
    }
 
public _renderAlbumImagesAsync(albumPath :string): void {
    // Local environment        
    this._getAlbumImages(albumPath)
      .then((response) => {
          console.log("images");
          console.log(response.value);
          this._renderAlbumImages(response.value);    
 
 
          $("#myCarousel").carousel({interval: 5000});          
      });        
 
}
 
private _renderAlbumImages(items: ISPAlbumImage[]): void {
    let html: string = '';
html =`<h2 style="background-color: #4052ab;height: 50px;"><span class="${ styles.imgGalleyTitle }">Image Gallery</span><button id="btnBack" class="${ styles.btnBackStyle }"><span>Back</span></button></h2>
    <div class="container" style='width:1000px !important'>    
    <div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="5000" style='border: 1px solid #0e83cd;'>
 
      <ol class="carousel-indicators">
        <li data-target="#myCarousel" data-slide-to="0" class="active"></li>
        <li data-target="#myCarousel" data-slide-to="1"></li>
        <li data-target="#myCarousel" data-slide-to="2"></li>
      </ol>        
      <div class="carousel-inner">
 
      </div>
 
      <a class="left carousel-control" href="#myCarousel" data-slide="prev">
        <span class="glyphicon glyphicon-chevron-left"></span>
        <span class="sr-only"><</span>
      </a>
      <a class="right carousel-control" href="#myCarousel" data-slide="next">
        <span class="glyphicon glyphicon-chevron-right"></span>
        <span class="sr-only" style='float:right !important'>></span>
      </a>
    </div>
  </div>`;
 
this.domElement.innerHTML=html;
var btnBack=this.domElement.querySelector('#btnBack');
 
btnBack.addEventListener('click', () => {
    this.render();
});
 
 
let slides: string = '',indicat: string = ''; 
let index: number = 0; 
items.forEach((item: ISPAlbumImage) => {            
 
    if(index==0)
    {
 
        indicat += `<li data-target="#myCarousel" data-slide-to="${index}" class="active"></li>`;
 
        slides += `
        <div class="item active">
          <img src="${item.ServerRelativeUrl}" alt="Los Angeles" style="width:1000px;height:500px;" />                      
        </div>`;
    }
    else{
        indicat += `
        <li data-target="#myCarousel" data-slide-to="${index}"></li>`;
        slides += `
        <div class="item">
          <img src="${item.ServerRelativeUrl}" alt="Los Angeles" style="width:1000px;height:500px;" />                      
        </div>`;
    }
    index++;  
});
 
const indicators: Element = this.domElement.querySelector('.carousel-indicators');
indicators.innerHTML = indicat;    
 
const listContainer: Element = this.domElement.querySelector('.carousel-inner');
listContainer.innerHTML = slides;    
}
 
private _renderListAlbum(items: ISPListAlbum[]): void {
    let html: string = '';
items.forEach((item: ISPListAlbum) => {            
    if(item.Name!="Forms" && item.Name.indexOf("_") ===-1)
    {
 
 
        html +=`<div serrel="${item.ServerRelativeUrl}" class="tiles ${ styles.albumblock }">
            <img class="img-responsive" serrel="${item.ServerRelativeUrl}" src="${item.ListItemAllFields.AlbumPicURL}" alt="${item.Name}" title="${item.Name}">
            <div serrel="${item.ServerRelativeUrl}" class="${ styles["album-info"] }"> 
              <h3 serrel="${item.ServerRelativeUrl}">${item.Name}</h3> 
            </div>
          </div>`;
    }
});
 
const listContainer: Element = this.domElement.querySelector('#spListContainer');
listContainer.innerHTML =`<ul>`+ html+`</ul>`;    
}
 
private _ClickCalled(event) : void{    
    this._renderAlbumImagesAsync(event.target.attributes.serrel.value);
 
}
 
private _getAlbumData(): Promise<ISPListAlbums> {
    return this.context.spHttpClient.get(this.context.pageContext.site.absoluteUrl + "/_api/web/getFolderByServerRelativeUrl('Imagelib')/Folders?$select=Name,ServerRelativeUrl,Id,ListItemAllFields/AlbumPicURL&$expand=ListItemAllFields", SPHttpClient.configurations.v1)
      .then((response: SPHttpClientResponse) => {        
          return response.json();
      });
}
 
private _getAlbumImages(albumPath :string): Promise<ISPAlbumImages> {
    return this.context.spHttpClient.get(this.context.pageContext.site.absoluteUrl + "/_api/web/getFolderByServerRelativeUrl('"+albumPath+"')/Files", SPHttpClient.configurations.v1)
      .then((response: SPHttpClientResponse) => {        
          return response.json();
      });
}
 
protected get dataVersion(): Version {
    return Version.parse('1.0');
}
 
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
        pages: [
          {
              header: {
                  description: strings.PropertyPaneDescription
              },
              groups: [
                {
                    groupName: strings.BasicGroupName,
                    groupFields: [
                      PropertyPaneTextField('description', {
                          label: strings.DescriptionFieldLabel
                      })
                    ]
                }
              ]
          }
        ]
    };
}
}// JavaScript source code

♦ After editing the code of the above three mentioned files, run below command:

Gulp serve

♦ Open URL: /_layouts/15/workbench.aspx
♦ Add web part.
Add Web Part

Web Part

♦ For security reasons, we have hide URL. Now we will look how to deploy this web part to SharePoint from development environment.

Step 4 – To Deploy Web Part to SharePoint

  1. Execute following commands one by one
  2. Gulp bundle –ship
    Gulp package-solution --ship
    
  3. Now open the Image-Gallery folder in Explorer and go to SharePoint, go to solution
    “\Image-Gallery\sharepoint\solution”
  4. There will be file named “image-gallery.sppkg”.
  5. Open App Catalog site, go to Site Contents  Apps for SharePoint  Upload the .sppkg file
  6. Go to Site Content of the communication site, and add an application “image-gallery”.
  7. Add web part to your communication site like we did on workbench.
23
Jun
2017
ADFS Configuration in Windows Server 2012 R2 Standard with SharePoint 2013

The procedures in this article describe how to configure AD FS to act as an Identity Provider Security Token Service (IP-STS) for a SharePoint 2013 web application and Provider Hosted APP (SharePoint Add-In). In this configuration, AD FS issues SAML-based security tokens consisting of claims so that client computers can access web applications that use claims-based authentication. You can use an alternative identity provider than AD FS, but it must support the WS-Federation standard.Have a brief view on the major benefits of using AD FS in SharePoint solution:

  • Web single sign-on (SSO) – Federated Partners outside the organization can access organization’s Web-based applications, with Web SSO, an extensive feature of AD FS.
  • Partner user account management not required – Free from tiresome process of resetting and maintaining partner’s credentials. Also, if partnership terminates, the procedure can be performed with a single trust policy change.
  • AD FS Microsoft Management Console (MMC) – Core and centralized part of ADFS to perform management activities for Federal Partners.
  • Extensible architecture – This is more beneficial at times of claim processing. Claim processing and mapping comprises of adding and modifying claims by using business logics and AD FS trust policy.

Steps below present the technique to configure the Single Sign on between Provider Hosted App based on SharePoint Development on SharePoint Server.

(Prerequisite: SQL Server 2008/2012 must be installed.)

Follow below steps to configure ADFS:

    1. Click on “Add role and features” from server manager.
    2. In the respective wizard, select the options mentioned below and click on Next
      • Installation Type screen.
      • On Sever Selection screen, click on Select a server from the server pool
      • On Server Roles screen, click on Active Directory Certificates Services, Active Directory Domain Services and Active Directory Federation Services.
      • On Features screen, click on features based on requirements
      • Click on AD FS. Then further, Click on Next for AD CS
      • On Role Services screen, click on Certification Authority for Domain Certificate
      • AD DS screen will be available
      • On Confirmation screen, click on Install.

If all the above steps are sequentially performed, then it will successfully install. After installation, configure it as follows (Note: All services should be configured without an error as below & green colour showing configuration done successfully)

1

  1. On Server Manager Dashboard, Click on AD FS
  2. Click on More link display in yellow ribbon for Configuration AD FS

    2

  3. Click on Configure
  4. After clicking on Next follow the wizard sequentially and opt the options accordingly,
    • Select Create the first federation server in a federation server farm
    • Click on Change button to select user on Connect to AD DS screen.
    • On Specify Service Properties screen, select Domain Certificate from drop down list and enter Federation Service Name and Federation Service Display Name.
    • On Specify Service Account screen, select Use an existing domain user account or group managed service account. Here, mainly specify service configuration is done.

    After performing each step, Specify Service Account will be seen.

  5. On Specify Service Account screen, enter correct password in Account Password text box.
  6. Click on Next  On Specify Database screen, select Create a database on this server using Windows Internal Database
  7. Click on Next On Review options screen, you can view that the database is created successfully.
  8. Click on Next On Pre-requisite checks screen, check that pre-requisite is configured properly and click on Configure.
  9. To check its configured properly or not open below URL: https://<<FQDN>>/adfs/ls/IdpInitiatedSignon.aspx
  10. Enter valid credentials and click on Sign in button.

    3

  11. It will show Log Out screen.
  12. Click on Sign Out to sign out successfully.

After performing above mentioned, proceed ahead for provider hosted app creation.

Provider Hosted APP (SharePoint Add-In) Creation Demo

Registering APP in SharePoint Server and Hosting App in another Non-SharePoint Server. Follow below steps to register app:

Step 1

Create Register id from SharePoint 2013 site: –

  1. Open created developer site in browser
  2. Append _layouts/15/appregnew.aspx text in browser as below image
    4

  3. Click on Generate button of App Id (code will automatically generate in textbox)
  4. Click on Generate button App Secret (code will automatically generate in textbox)
  5. Please fill remaining field (here you can change your domain name)
  6. Click on OK button.
  7. All id will be displayed as below image
    5

  8. Copy all id and saved it notepad file. (This id will be changed in project’s web.config file)

Step 2

Need to create Provider Hosted App in Visual Studio 2012 or later. After creating it, publish the Provider hosted app then follow step 3 to host app in IIS and update app keys into the web.config file.

Step 3

Create web application in IIS

  1. Open run command and type inetmgr or open IIS
  2. Right click on sites and select Add website

    6

  3. Fill the form as below and click on OK button:

    7

ADFS Relying Party Demo – Provider Hosted APP

Configuration provider hosted app URL in ADFS allows to Single Sign On and pass the token from SharePoint Site. Follow below steps to configure ADFS for Provider Hosted APP Site which is in another non- SharePoint Server or Domain.

Follow below steps to relying party demo:

  1. Add relying party and click on Start
  2. On Select Data Source, select Enter data about the relying party manually
  3. By clicking on Next, follow the hierarchy of steps:
    • On Specify Display Name, enter Display Name
    • On Choose Profile select AD FS Profile. Click Next
    • On Configure URL tick on Enable support for the WS-Federation Passive protocol and enter Passive Protocol URL: (https://ProivderHostedURL/_trust/)

      8

    • Click Next On Configure Identifiers add URN

      9

    • On Configure Multi-Factor Authentication Now? Select I don’t want to configure multi-factor authentication settings for this replying party trust at this time.
    • On Choose Issuance Authorization Rules, select permit all users to access this replying party.
    • Click Next. It will automatically open Choose Rule Type On that in Claim Rule Template, select Send LDAP attributes as Claims
    • On Configure Claim Rule screen, add configure rules are mentioned below: Order requires to be as follows

      10

  4. Click Finish. It will automatically prompt the below screen. If not, right click on ADFS, and click on Properties. Click on Advance in Properties option and select SHA-1 search hash algorithm. Click OK

    11

Single Sign on Configuration for App and Server

Step 1 – Single Sign On Configuration for Server

It is a PowerShell Script to establish ADFS Server and SharePoint Server Connection. Below highlighted point will help SharePoint Server to communicate with on-premises Server (where ADFS is configured) which is in another Server or Domain and it will pass token to SharePoint Server to on-premises Server. Basically, this scenario called as Single Sign On Configuration. Open PowerShell command window and execute the below code:

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\Certs\Certificate.cer")
New-SPTrustedRootAuthority -Name "Token Signing Certificate ADFS Demo" -Certificate $cert
 
$emailClaimMap = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming
 
$roleClaimMap = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" -IncomingClaimTypeDisplayName "Role" -SameAsIncoming
 
$upnClaimMap = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" -IncomingClaimTypeDisplayName "UPN" -SameAsIncoming
 
$realm = "urn:sharepoint:demo"
 
#Sign-in URL will be ADFS Server instance
$signInURL="https://abc. domain.com/adfs/ls"
 
#Create new trusted identity token issuer
$issuer = New-SPTrustedIdentityTokenIssuer -Name "ADFSDemo" -Description "ADFS Trusted Identity Provider Demo" -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $emailClaimMap,$roleClaimMap,$upnClaimMap -SignInUrl $signInURL -IdentifierClaim $upnClaimMap.InputClaimType

(NOTE : The C:\Certs\Certificate.cer is the same certificate which is created in ADFS Relying Party for SharePoint Site in ADFS Server Step 14)
[ C:\Certs\Certificate.cer, urn:sharepoint:demo, https://abc. domain.com/adfs/ls, ADFSDemo and ADFS Trusted Identity Provider Demo need to be replaced based on user’s configuration. ]

Perform the below mentioned steps:

  1. Register SharePoint Site with URN in SharePoint Server:
    $t=Get-SPTrustedIdentityTokenIssuer "ADFSDemo" 
    $uri=new-object System.Uri("https://sp13-012:31418/_trust/") 
    $t.ProviderRealms.Add($uri, "urn:sharepoint:sharepointsite") 
    $t.Update()

    [sp13-012:31418 and urn:sharepoint:sharepointsite require to be replaced based on user’s configuration. ]

  2. Register Provider Hosted Site with URN in SharePoint Server:
    $t=Get-SPTrustedIdentityTokenIssuer "ADFSDemo" 
    $uri=new-object System.Uri("https://localhost:7443/_trust/") 
    $t.ProviderRealms.Add($uri, "urn:sharepoint:localhost ") 
    $t.Update()

    [localhost:7443 and urn:sharepoint:localhost require to be replaced based on user’s configuration. ]

  3. Go to central admin and select Trust Identity Provider:
    12

Get Client Context object for Provider Hosted APP in APP Part:

  1. Select APP Part and got to property or Press F4:
    13

  2. Add Custom Property as below in Provider Hosted Solution:
    14

  3. Add Property as follows:
    15

  4. Get user client context using below code:
    using (ClientContext clientContext = SharePointContextProvider.Current.GetSharePointContext(Context).CreateAppOnlyClientContextForSPHost())
    {
    List oList = clientContext.Web.Lists.GetByTitle("Contact");
    clientContext.Load(oList);
    clientContext.ExecuteQuery();
     
    If(Request.QueryString["UserName"] != null)
    {
    	string strUserEmail = Convert.ToString((Request.QueryString["UserName"]));
    strUserEmail += “@Domain.com// use domain
    ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
    Microsoft.SharePoint.Client.ListItem oListItem = oList.AddItem(itemCreateInfo);
     
    User user = clientContext.Web.EnsureUser(strUserEmail);
    clientContext.Load(user);
    clientContext.ExecuteQuery();
    Response.Write("
    " + user.LoginName + "
     
    "); oListItem["Title"] = "Test"; oListItem["Author"] = user; oListItem["Editor"] = user; oListItem.Update(); clientContext.ExecuteQuery(); } }
  5. Publish your project and add as web part and URL as follow:
    http://sharepointsite/pages/providerapppart.aspx?UserName=adminuser

Conclusion

AD FS being standards-based service allows the secure sharing of identity information between trusted business partners or federated partners across an extranet. In simple words, AD FS is an easy way out of remembering credentials and following multiple times same authentication steps to sign-on in the same web solution.

18
May
2017
SharePoint Provider hosted App with Single Page application with help of Angular JS 2

Environment Setup for Angular2 Development

Note: For this, Windows 2012 R2 OS machine for development is used. In which SharePoint 2013 server is also installed.

  1. Install node JS installer. Download the latest version of the installer file from here.
  2. Install Python 2.7. Download installer from the official website.
  3. Install Visual Studio 2015 with Update 3. You can also download setup from here.
  4. In may be a case where you may get the error during installation of Visual Studio. To resolve the error, you need to install required KB updates for Windows server 2012.
  5. Select Custom option and select only the below mentioned Features:
    1. Visual C++ (all options)
    2. Python tools for Visual Studio
    3. Microsoft Web Developer Tools
  6. Open Visual Studio 2015 From menu, click “Tools” click on “Options” under “Projects and Solutions”, select “External Web Tools”.
  7. Now arrange the locations of external tools. Create new path, if path is not existed click “OK” to save changes. Refer below image for this step.
    create path
  8. Install TypeScript_Dev14Fulll.exe to compile typescripts in Visual Studio. You can get appropriate version from here.
  9. Check whether SharePoint add-in templates are available in the Visual Studio or not. (From Create new project section, you can check if these templates are available or not.) If templates are not available in the Visual Studio, then download Microsoft Office Developer Tools Preview 2 installer from here.Install it for further steps and don’t forget to select SharePoint add-in templates option .
  10. Open command prompt and Run command to set path for Python 2.7: npm config set python python2.7
  11. Also, run another command: npm config set msvs_version 2015 –global

Configuration for SharePoint Provider hosted app

Follow Microsoft link to configure machine for SharePoint provider hosted app in on premise.

CRUD operations in list using SharePoint provider hosted app with Angular2

We are performing CRUD operations in the SharePoint Development where SharePoint list is residing in the host web. List name I have used static “TestAngular” with 2 fields Title, Number with single line column type.

  1. Create basic SharePoint Provider hosted app with MVC web application. Please follow Microsoft link.
  2. Open the appmanifest file of the SharePoint app from Solution explorer.
  3. Give “Manage” permissions on the site collection and list in appmanifest file.Give “Manage” permissions on the site collection and list in appmanifest file
  4. Create Web API controllers in MVC Web Application
    Use static list name “TestAngular”. Change the code in class file with name “WebApiConfig.cs” in the “App_Start” folder. This enables the session for the Web API. Replace existing code with below code in “WebApiConfig.cs” file.

    using System.Web;
    using System.Web.Http;
    using System.Web.Http.WebHost;
    using System.Web.Routing;
    using System.Web.SessionState;
    namespace PHA_MVCWeb.App_Start
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                RouteTable.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                ).RouteHandler = new SessionRouteHandler();
     
                var json = config.Formatters.JsonFormatter;
                json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
                config.Formatters.Remove(config.Formatters.XmlFormatter);
            }
     
            public class SessionRouteHandler : IRouteHandler
            {
                IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
                {
                    return new SessionControllerHandler(requestContext.RouteData);
                }
            }
            public class SessionControllerHandler : HttpControllerHandler, IRequiresSessionState
            {
                public SessionControllerHandler(RouteData routeData)
                    : base(routeData)
                { }
            }
        }
    }
  5. Create new class file inside Filters folder with name “SharePointContextWebAPIFilterAttribute.cs”.
  6. Add below code inside “SharePointContextWebAPIFilterAttribute.cs” file.
    using System;
    using System.Net;
    using System.Net.Http;
    using System.Web;
    using ActionFilterAttribute = System.Web.Http.Filters.ActionFilterAttribute;
    namespace PHA_MVCWeb.Filters
    {
        public class SharePointContextWebAPIFilterAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
            {
                if (actionContext == null)
                {
                    throw new ArgumentNullException("actionContext");
                }
     
                Uri redirectUrl;
                switch (SharePointContextProvider.CheckRedirectionStatus(HttpContext.Current, out redirectUrl))
                {
                    case RedirectionStatus.Ok:
                        return;
                    case RedirectionStatus.ShouldRedirect:
                        var response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Redirect);
                        response.Headers.Add("Location", redirectUrl.AbsoluteUri);
                        actionContext.Response = response;
                        break;
                    case RedirectionStatus.CanNotRedirect:
                        actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.MethodNotAllowed, "Context couldn't be created: access denied");
                        break;
                }
            }
        }
    }

    Notes (for above code):

    • System.Web.Http.Controllers.HttpActionContext doesn’t have HttpContext object associated, so use HttpContext.Current instead of OnActionExecuting when called CheckRedirectionStatus method from SharePointContextProvider class.
    • System.Web.Http.Controllers.HttpActionContext doesn’t have Result property, so use Response property to redirect and create Error response in the code.
  7. To create View Controller, create new Web API controller with name ViewController.cs inside the Controllers folder. This will retrieve all the items from the SharePoint list.
  8. Add below mentioned code in “ViewController.cs” file.
    using System.Collections.Generic;
    using System.Web.Http;
    using Microsoft.SharePoint.Client;
    using System.Web;
    using PHA_MVCWeb.Filters;
     
    namespace PHA_MVCWeb.Controllers
    {
     
        public class TestAngularModel
        {
            public string ID { get; set; }
            public string Title { get; set; }
            public string Number { get; set; }
     
            public TestAngularModel(string ID, string Title, string Number)
            {
                this.ID = ID;
                this.Title = Title;
                this.Number = Number;
            }
     
     
        }
     
        public class ViewController : ApiController
        {
            // GET api//5
            [SharePointContextWebAPIFilter]
            public List Get(int id)
            {
                List TestAngular = null;
                ListItemCollection itmCol = null;
                List itmList = new List();
     
                var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
     
                using (var clientContext = spContext.CreateUserClientContextForSPHost())
                {
                    if (clientContext != null)
                    {
                        TestAngular = clientContext.Web.Lists.GetByTitle("TestAngular");
                        clientContext.Load(TestAngular);
                        clientContext.ExecuteQuery();
     
                        itmCol = TestAngular.GetItems(CamlQuery.CreateAllItemsQuery());
                        clientContext.Load(itmCol);
                        clientContext.ExecuteQuery();
     
                        foreach (ListItem itm in itmCol)
                        {
     
                            itmList.Add(new TestAngularModel(itm["ID"].ToString(), itm["Title"].ToString(), itm["Number"].ToString()));
                        }
     
                        return itmList;
                    }
                    else
                        return itmList;
                }
            }
        }
  9. To create Item Controller, create new Web API controller with name “CreateItemController.cs” in “Controllers” folder. It will create new item in the SharePoint list.
  10. Add below code to “CreateItemController.cs” file.
    using Microsoft.SharePoint.Client;
    using PHA_MVCWeb.Filters;
    using System.Web;
    using System.Web.Http;
     
    namespace PHA_MVCWeb.Controllers
    {
        public class CreateItemController : ApiController
        {
            [SharePointContextWebAPIFilter]
            public string Get(string name, string number)
            {
                List TestAngular = null;
     
                var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
                using (var clientContext = spContext.CreateUserClientContextForSPHost())
                {
                    if (clientContext != null)
                    {
                        TestAngular = clientContext.Web.Lists.GetByTitle("TestAngular");
                        clientContext.Load(TestAngular);
                        clientContext.ExecuteQuery();
     
                        ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
                        ListItem oListItem = TestAngular.AddItem(itemCreateInfo);
                        oListItem["Title"] = name;
                        oListItem["Number"] = number;
     
                        oListItem.Update();
                        clientContext.ExecuteQuery();
     
                        return "Data saved!";
                    }
                    else
                    {
                        return "Error occurred!";
                    }
                }
            }
        }
    }

    Similarly create controllers for update and delete item.

  11. Create “NPM configuration file” with name “package.json” at root level.
  12. Add below code in the package.json file. It contains information about dependencies of angular package with versions for compiler. Here Angular 2 with RC6 is used.
    {
      "name": "aspnet",
      "version": "0.0.0",
      "scripts": {
        "postinstall": "typings install",
        "typings": "typings"
      },
      "license": "ISC",
      "devDependencies": {
       "concurrently": "^2.2.0",
        "lite-server": "^2.2.2",
        "systemjs-builder": "^0.15.16",
        "traceur": "^0.0.91",
        "typescript": "2.0.2",
        "typings":"^1.3.2"
      },
      "dependencies": {
        "@angular/common": "2.0.0-rc.6",
        "@angular/compiler": "2.0.0-rc.6",
        "@angular/core": "2.0.0-rc.6",
        "@angular/http": "2.0.0-rc.6",
        "@angular/platform-browser": "2.0.0-rc.6",
        "@angular/platform-browser-dynamic": "2.0.0-rc.6",
        "@angular/upgrade": "2.0.0-rc.6",
        "@angular/forms": "2.0.0-rc.6",
        "@angular/router": "3.0.0-rc.2",
     
        "core-js": "^2.4.1",
        "reflect-metadata": "^0.1.3",
        "rxjs": "5.0.0-beta.6",
        "systemjs": "^0.19.37",
        "typings": "^1.3.2",
        "zone.js": "^0.6.12",
        "moment": "^2.14.1"
      },
      "main": "systemjs.config.js",
      "author": "",
      "description": ""
    }
  13. Create “TypeScript JSON Configuration file” with name “tsconfig.json” at root level.
  14. Add below code in the “tsconfig.json” file.
    {
    {
      "compileOnSave": true,
      "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false
      },
      "exclude": [
        "node_modules",
        "node_modules/@types/jquery/index.d.ts",
        "typings/main",
        "typings/main.d.ts",
        "wwwroot",
        "Scripts/TypeLite.Net4.d.ts"
      ]
    }
  15. Create “JSON file” with name “typings.json” at root level.
  16. Add below code in “typings.json” file.
    {
      "ambientDependencies": {
        "bootstrap": "github:DefinitelyTyped/DefinitelyTyped/bootstrap/bootstrap.d.ts#56295f5058cac7ae458540423c50ac2dcf9fc711",
        "core-js": "registry:dt/core-js#0.0.0+20160317120654",
        "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#56295f5058cac7ae458540423c50ac2dcf9fc711",
        "TypeLite": "file:scripts/TypeLite.Net4.d.ts"
      }
    }
  17. Create “JavaScript” file with name “systemjs.config.js” at root level. This file loads all packages required for the application while initialization.
  18. Add below code in “systemjs.config.js” file.
    (function (global) {
        System.config({
            paths: {
                // paths serve as alias
                'npm:': '/node_modules/'
            },
            // map tells the System loader where to look for things
            map: {
                // our app is within the app folder
                app: 'app',
     
                // angular bundles
                '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
                '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
                '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
                '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
                '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
                '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
                '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
                '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
     
                // angular testing umd bundles
                '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
                '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
                '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
                '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
                '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
                '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
                '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
                '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
     
                // other libraries
                'rxjs': 'npm:rxjs',
                'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
            },
            // packages tells the System loader how to load when no filename and/or no extension
            packages: {
                app: {
                    main: './main.js',
                    defaultExtension: 'js'
                },
                rxjs: {
                    defaultExtension: 'js'
                },
                'angular2-in-memory-web-api': {
                    defaultExtension: 'js'
                }
            }
        });
    })(this);
  19. Create new “text” file with name “TypeLite.Net4.tt” in “Scripts” folder.
  20. Add below code in “TypeLite.Net4.tt” file.
    <#@ template debug="false" hostspecific="True" language="C#" #>
    <#@ assembly name="$(TargetDir)TypeLite.dll" #>
    <#@ assembly name="$(TargetDir)TypeLite.Net4.dll" #>
    <#@ assembly name="$(TargetDir)$(TargetFileName)" #>
     
    <#@ import namespace="TypeLite" #> 
    <#@ import namespace="TypeLite.Net4" #> 
    <#@output extension=".d.ts"#>
     
     <#@include file="Manager.ttinclude"#>
    <# var manager = Manager.Create(Host, GenerationEnvironment); #>
     
    <# var ts = TypeScript.Definitions()
    		.WithReference("Enums.ts")
    		.For<Models.List>()
    		.For<Models.ViewModel.JSONReturnVM<object>>();
    #>
     
    <#= ts.Generate(TsGeneratorOutput.Properties) #>
     
    <# manager.StartNewFile("Enums.ts"); #>
    <#= ts.Generate(TsGeneratorOutput.Enums) #>
    <# manager.EndBlock(); #>
    <# manager.Process(true); #>
  21. To create root – APP module for Angular2 application, create “app” folder at root level of web application.
  22. Create new “typescript” file with name “main.ts” inside “app” folder. This file will load first and load the AppModule.
  23. Add below code in “main.ts” file.
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    import { AppModule } from './app.module';
    platformBrowserDynamic().bootstrapModule(AppModule);
  24. Create new typescript file with name “app.module.ts” inside “app” folder. Main.ts file will load this file first while initialization of application. The file defines modules that are used in application.
  25. Add below code in “app.module.ts” file.
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { Route, RouterModule } from '@angular/router';
    import { HttpModule } from '@angular/http';
    import { FormsModule } from '@angular/forms';
    import { routing } from './app.routes';
    import { AppComponent } from './app.component';
    import { ViewComponent } from './viewComponent/view.component';
     
    @NgModule({
        imports: [BrowserModule, HttpModule, RouterModule, FormsModule, routing],
        declarations: [AppComponent, ViewComponent],
        bootstrap: [AppComponent]
    })
    export class AppModule { }
  26. Create new “typescript” file with name “app.component.ts” in “app” folder. The file will load content for first page.
  27. Add below code in “app.component.ts” file.
    import { Component,} from '@angular/core';
    import { Http, Response, Headers, RequestMethod, HttpModule, RequestOptions, Request } from '@angular/http';
    import { FormsModule } from '@angular/forms';
    import { ViewDataService } from './services/viewData.service';
     
    @Component({
        moduleId: module.id,
        selector: 'app-work',
        providers: [ViewDataService],
        templateUrl: 'app.component.html'
    })
     
    export class AppComponent {
    }
  28. Create new “html” file with name “app.component.html” in “app” folder. The file contains html part of first page.
  29. Add below code in “app.component.html” file.
    <div class="row">
    <div class="col-md-12">
    <h2>CRUD Operations using Angular2!</h2>
    <hr />
    </div>
    </div>
    <div class="clearfix"></div>
    <div class="row">
    <div class="col-sm-3">
    <div class="sidebar-nav">
    <div class="navbar-collapse collapse sidebar-navbar-collapse">
    <ul class="nav navbar-nav">
    	<li><a routerlinkactive="active" routerlink="/viewcomponent" routerlinkactiveoptions="" exact:="" true="">View all items</a></li>
    	<li><a routerlinkactive="active" routerlink="/createitem">Create new item</a></li>
    	<li><a routerlinkactive="active" routerlink="/updatecomponent">Update item</a></li>
    	<li><a routerlinkactive="active" routerlink="/deletecomponent" href="#">Delete item</a></li>
    </ul>
    </div>
    </div>
    </div>
    <div class="col-md-9">
            <router-outlet></router-outlet>
    </div>
    </div>
  30. To create viewData.service.ts ,create new folder with name “services” in “app” folder.
  31. Create new “typescript” file with name “viewData.service.ts” in “services” folder. It will access Web API “viewController” which is created before.
  32. Add below code in “viewData.service.ts” file.Note: Here static url is used for demo purpose.
    import { Injectable } from '@angular/core';
    import { Http, Response, Headers, RequestMethod, HttpModule, RequestOptions, Request } from '@angular/http';
     
    @Injectable()
    export class ViewDataService {
     
        constructor(private _http: Http) {
        }
     
        viewData() {
            let listUrl = `https://localhost/api/view/1?SPHostUrl=https%3A%2F%2Ftatvasoft607%2Esharepoint%2Ecom%2Fsites%2FProviderApp&amp;SPLanguage=en-US&amp;SPClientTag=0&amp;SPProductNumber=16%2E0%2E6406%2E1200&amp;SPAppWebUrl=https%3A%2F%2FTatvasoft607-69192fd3dcf4a6%2Esharepoint%2Ecom%2Fsites%2FProviderApp%2FPHA_MVC`;
     
            let reqOptions = new RequestOptions({
                url: listUrl,
                method: RequestMethod.Get,
                headers: new Headers({ accept: 'application/json; odata=verbose', 'content-type': 'application/json; odata=verbose' }),
                body: null
            });
            let req = new Request(reqOptions)
            return this._http.request(req).map((res) =&gt; {
                return res.json()
            });
        }
    }
  33. To createData.service.ts, create new “typescript” file with name “createData.service.ts” in “services” folder. It will access Web API “CreateItemController” which is created before.
  34. Add below code “createData.service.ts” file.Note: Here the static url is used for demo purpose.
    import { Injectable } from '@angular/core';
    import { Http, Response, Headers, RequestMethod, HttpModule, RequestOptions, Request } from '@angular/http';
     
    @Injectable()
    export class CreateItemService {
     
        constructor(private _http: Http) {
        }
     
        updateItem(id: string, title: string, number: string) {
            let listUrl = `https://localhost/api/createitem? name=${title}&amp;number=${number}&amp;SPHostUrl=https%3A%2F%2Ftatvasoft607%2Esharepoint%2Ecom%2Fsites%2FProviderApp&amp;SPLanguage=en-US&amp;SPClientTag=0&amp;SPProductNumber=16%2E0%2E6406%2E1200&amp;SPAppWebUrl=https%3A%2F%2FTatvasoft607-69192fd3dcf4a6%2Esharepoint%2Ecom%2Fsites%2FProviderApp%2FPHA_MVC`;
     
            let reqOptions = new RequestOptions({
                url: listUrl,
                method: RequestMethod.Get,
                headers: new Headers({ accept: 'application/json; odata=verbose', 'content-type': 'application/json; odata=verbose' }),
                body: null
            });
            let req = new Request(reqOptions)
            return this._http.request(req).map((res) =&gt; {
                return res.json()
            });
        }
    }

    This way you can create services for update and delete operations.

  35. To create ViewComponent, create new folder with name “viewComponent” in “app” folder.
  36. Create new “typescript” file with name “view.component.ts” in “viewComponent” folder.
  37. Add below code in “view.component.ts” file.
     
    import { Component, OnInit, Input } from '@angular/core';
    import { ViewDataService } from '../services/viewData.service';
     
    @Component({
        selector: 'view-item',
        providers: [ViewDataService],
        template: `
    <table class="table table-bordered">
    <thead>
    <tr>
    <th>Name</th>
    <th>Number</th>
    </tr>
    </thead>
     
     
    <tbody>
    <tr ngfor="let frnd of results;">
    <td>{{frnd.Title}} {{last}}</td>
    <td>{{frnd.Number}}</td>
    </tr>
    </tbody>
     
    </table>
     
    `
    })
    export class ViewComponent implements OnInit {
     
        results: Array<object>;
     
        constructor(private _viewDataService: ViewDataService) {
        }
     
        ngOnInit() {
     
            this._viewDataService.viewData().subscribe(data =&gt; this.results = data);
     
        }
    }
    </object>
  38. Open “index.cshtml” from “Views” folder. Here all required JavaScript libraries are attached as per hierarchy.
  39. Replace existing code of “index.cshtml” file with below one.
    @{
        ViewBag.Title = "Home Page";
    }
    <!-- 1. Include JS libraries -->
    <!-- 2. Configure SystemJS -->
        System.import('app/main');
        System.import('app').catch(function (err) { console.error(err); });
    <base href="/" />
    <div class="jumbotron">
        <app-work>Loading...</app-work>
    </div>
    <div class="row">
    </div>
  40. To create Item Component, create new folder with name “CreateItemComponent” in “app” folder.
  41. Create new “typescript” file with name “createItem.component.ts” in “CreateItemComponent” folder.
  42. Add below code in “createItemModule.ts” file.
     
    export class createItemModule {
        constructor(public name: string, public number: string) { }
    }
  43. Create new “typescript” file with name “createItem.component.ts” in “CreateItemComponent” folder.
  44. Add below code in “createItem.component.ts” file.
     
    import { Component } from '@angular/core';
    import { Http, Response, Headers, RequestMethod, HttpModule, RequestOptions, Request } from '@angular/http';
    import { FormsModule } from '@angular/forms';
    import { createItemModule } from './createItemModule';
    import { Router } from '@angular/router';
    import 'rxjs/add/operator/share';
    import 'rxjs/add/operator/map';
    import 'rxjs/Rx';
     
    @Component({
        moduleId: module.id,
        selector: 'create-item',
        providers: [CreateDataService],
        templateUrl: 'create.item.html',
        styles: ['.ng-valid[required], .ng-valid.required  {border-left: 5px solid #42A948; /* green */} .ng-invalid:not(form)  {border-left: 5px solid #a94442; /* red */} .h3Title{margin-top:0px;}']
    })
     
    export class CreateItemComponent {
     
        model = new createItemModule('', '');
     
        constructor(private _http: Http, private _router: Router, private _createDataService: CreateDataService) {
        }
     
        submitForm(form: any): void {
     
             this._ createDataService.createItem(form.name, form.number).subscribe(data =&gt; alert(data));
     
            this._router.navigateByUrl('/viewcomponent');
        }
    }
  45. Create new “html” file with name “create.item.html” inside “CreateItemComponent” folder.
  46. Add below code in “create.item.html” file.
     
    <h3 class="h3Title">Create new item</h3>
    <form form="ngForm" novalidate="">
    <div class="form-group">
            <label for="name">Name:</label>
            <input type="text" class="form-control" id="name" required="" ngmodel="" model="" name="" name="name" name="ngModel" />
    <div hidden="" name="" valid="" name="" pristine="" class="alert alert-danger">
              Name is required.
    </div>
    </div>
    <div class="form-group">
            <label for="number">Number:</label>
            <input type="text" class="form-control" id="number" required="" ngmodel="" model="" number="" maxlength="5" pattern="[1-9][0-9]{4}" name="number" number="ngModel" />
    <div hidden="" number="" valid="" number="" pristine="" class="alert alert-danger">
                Number is required. <i>Maxlength = 5 and first letter should be non-zero.</i>
    </div>
    </div>
        <button type="button" click="" submitform="" form="" value="" disabled="disabled" form="" form="" valid="" class="btn btn-default">Submit</button>
    </form>

    This way you can create components for update and delete operation.

  47. To implement routing Angular2 and to create Single Page Application, create new typescript file with name “app.routes.ts” in “app” folder. It will route components in angular application.
  48. Add the below code in the “app.routes.ts” file.
     
    import { Routes, RouterModule, provideRoutes } from '@angular/router';
    import { AppComponent } from './app.component';
    import { ViewComponent } from './viewComponent/view.component';
    import { CreateItem } from './createItem/create.item';
    import { DeleteComponent } from './deleteComponent/delete.component';
    import { UpdateComponent } from './updateComponent/update.component';
     
    export const routes: Routes = [
        { path: 'viewcomponent', component: ViewComponent },
        { path: '', redirectTo: '/viewcomponent', pathMatch: 'full' },
        { path: 'createitem', component: CreateItem },
        { path: 'updatecomponent', component: UpdateComponent },
        { path: 'deletecomponent', component: DeleteComponent }
    ];
    export const routing = RouterModule.forRoot(routes);
  49. Build the solution and publish the SharePoint app. Publish the web application.
  50. Right click on web application project click on “Open Folder in File Explorer”.
  51. File Explorer window will be opened. Find and copy the folder “node_modules” paste the folder in the published folder. We need to add this “node_modules” folder with the published code files in the hosting environment. As this folder contains all the typescript and JavaScript files dependencies.
  52. Output

    CRUD Operation using Angular 2
    CRUD Operation using Angular 2