MS Team and SharePoint Online Site Association via The MS Team Tab

Last Updated on Nov 30, 2020

SharePoint Framework (SPFx) is an excellent platform for SharePoint developers allowing them to create client-side applications. From release version 1.8, SPFx has added a beautiful feature in which SPFx Web Parts can be utilized in MS Teams as a tab. So the same Web Part can be used in SharePoint sites as well as in MS Teams for accurate SharePoint development services.

The steps to create such an SPFx Web Part are already described in our blog. This blog is written to show how to redeploy the existing Web Part and utilize the updated Web Part in MS Teams. Also, this will portray how the site collection’s list and libraries can be used by performing the CRUD operation.

Let’s first implement CRUD operation with the SharePoint list in the SPFx Web Part or MS Teams tab Web Part.

Implementing CRUD operation to list

Implementing CRUD operation to the list will connect your Web Part to the list of any site collection of your tenant. This Web Part will be consumed in the MS Teams tab, and hence a connection will be established between MS Teams and SharePoint site collection.

Below are the steps to implement CRUD operation to the SharePoint list.

  • Here, PNP js is used by SharePoint developers to implement CRUD operation. The first step is to install PnP js libraries. Enter npm install sp-pnp-js –save in command prompt. Make sure you are inside the project directory.
  • Import the added library in the .ts file of your Web Part.
    This will allow us to implement CRUD using PnP js.Note: It is not necessary that you use PnP js. If it is not consumed, then no need to install its library.
  • Next step is to add the textboxes and buttons for implementing the operations.
    <br></br>
                  <div>
                    <input id="LanguageName" placeholder="Enter any language"></input>
                    <input id="LanguageId" placeholder="Enter any language id"></input>
                  </div>
                  <br></br>
                  <div>
                    <button class="create-Button"><span>Create Item</span></button>
                    <button class="retrieve-Button"><span>Retrieve Item</span></button>
                    <button class="update-Button"><span>Update Item</span></button>
                    <button class="delete-Button"><span>Delete Item</span></button>
                  </div>
                  <div>
                    <table id="tblLanguages" class="table-responsive">
                    <thead>
                      <td>	
                        <tr>ID</tr>
                        <tr>Name</tr>
                      </td>
                    </thead>
                    <tbody id="bodyTableLang">
                    </tbody>
                    </table>
                  </div>

    <br></br>
    <div>
    <input id=”LanguageName” placeholder=”Enter any language”></input>
    <input id=”LanguageId” placeholder=”Enter any language id”></input>
    </div>
    <br></br>
    <div>
    <button class=”create-Button”><span>Create Item</span></button>
    <button class=”retrieve-Button”><span>Retrieve Item</span></button>
    <button class=”update-Button”><span>Update Item</span></button>
    <button class=”delete-Button”><span>Delete Item</span></button>
    </div>
    <div>
    <table id=”tblLanguages” class=”table-responsive”>
    <thead>
    <td>
    <tr>ID</tr>
    <tr>Name</tr>
    </td>
    </thead>
    <tbody id=”bodyTableLang”>
    </tbody>
    </table>
    </div>

    Here two textboxes, four buttons and one table are added. The above code is added inside the render() method.

  • After rendering the HTML part, two methods are called as below.
    this.setButtonEventHandlers();
    this.RenderLanguagesEntries();

    this.setButtonEventHandlers();
    this.RenderLanguagesEntries();

    this.setButtonEventHandlers() method will bind the methods to the buttons.

    private setButtonEventHandlers(): void
      {
        const webpart: TeamsTabWebPart = this;
     
        this.domElement.querySelector('button.create-Button').addEventListener('click', () => {webpart.createItem();});
        this.domElement.querySelector('button.retrieve-Button').addEventListener('click', () => {webpart.retrieveItem();});
        this.domElement.querySelector('button.update-Button').addEventListener('click', () => {webpart.updateItem();});
        this.domElement.querySelector('button.delete-Button').addEventListener('click', () => {webpart.deleteItem();});
      }

    private setButtonEventHandlers(): void
    {
    const webpart: TeamsTabWebPart = this;

    this.domElement.querySelector(‘button.create-Button’).addEventListener(‘click’, () => {webpart.createItem();});
    this.domElement.querySelector(‘button.retrieve-Button’).addEventListener(‘click’, () => {webpart.retrieveItem();});
    this.domElement.querySelector(‘button.update-Button’).addEventListener(‘click’, () => {webpart.updateItem();});
    this.domElement.querySelector(‘button.delete-Button’).addEventListener(‘click’, () => {webpart.deleteItem();});
    }

    this.RenderLanguagesEntries() will bind the default table by fetching the data from Language list.

    private RenderLanguagesEntries(): void
    {
      this.table =  <HTMLTableElement> document.getElementById("bodyTableLang");
      this.table.innerHTML = "";
      pnp.sp.web.lists.getByTitle('Language').items.get().then((items) => {    
        for(var i=0; i< items.length; i++)
        {
          var id = items[i].ID;
          var langName = items[i].Title;
     
          var row = this.table.insertRow(i);
          var cell1 = row.insertCell(0);
          cell1.innerHTML = id;
          var cell2 = row.insertCell(1);
          cell2.innerHTML = langName;
        }
     
      }).catch((error) => {
        alert("Something went wrong " + error);
      });
    }

    private RenderLanguagesEntries(): void
    {
    this.table = <HTMLTableElement> document.getElementById(“bodyTableLang”);
    this.table.innerHTML = “”;
    pnp.sp.web.lists.getByTitle(‘Language’).items.get().then((items) => {
    for(var i=0; i< items.length; i++)
    {
    var id = items[i].ID;
    var langName = items[i].Title;

    var row = this.table.insertRow(i);
    var cell1 = row.insertCell(0);
    cell1.innerHTML = id;
    var cell2 = row.insertCell(1);
    cell2.innerHTML = langName;
    }

    }).catch((error) => {
    alert(“Something went wrong ” + error);
    });
    }

    Here, the “table” variable is already defined globally inside the main class.

    The output of the Web Part will be displayed, as shown in the below image.

  • New items can be added to the list by entering the language name inside the textbox. Here, consider a new language, “French,” to be added.
  • After entering the item, clicking on the Create Item button will prompt the user with a successful addition message.
    The language will be added to the list, and the below table will be updated.
    The code to add items is provided below.
    private createItem(): void
    {
      let langName: string = document.getElementById('LanguageName')["value"];
      let web = new Web(this.context.pageContext.web.absoluteUrl);
     
      pnp.sp.web.lists.getByTitle('Language').items.add({
        Title: langName
      }).then(() =>{
          document.getElementById('LanguageName')["value"] = "";
          document.getElementById('LanguageId')["value"] = "";
          alert("Item added successfully");
          this.RenderLanguagesEntries();
      }).catch((error) =>{
        alert("Something went wrong" + error);
        document.getElementById('LanguageName')["value"] = "";
        document.getElementById('LanguageId')["value"] = "";
      });
    }

    private createItem(): void
    {
    let langName: string = document.getElementById(‘LanguageName’)[“value”];
    let web = new Web(this.context.pageContext.web.absoluteUrl);

    pnp.sp.web.lists.getByTitle(‘Language’).items.add({
    Title: langName
    }).then(() =>{
    document.getElementById(‘LanguageName’)[“value”] = “”;
    document.getElementById(‘LanguageId’)[“value”] = “”;
    alert(“Item added successfully”);
    this.RenderLanguagesEntries();
    }).catch((error) =>{
    alert(“Something went wrong” + error);
    document.getElementById(‘LanguageName’)[“value”] = “”;
    document.getElementById(‘LanguageId’)[“value”] = “”;
    });
    }

    Note: If any error occurs while adding the language, the SharePoint developer will be prompted with the error message.

  • To retrieve the language, enter the id for which you want the details. Here, id 6 is added in the textbox and clicking the Retrieve Item button will prompt the user with the language name.
    Code to retrieve items is provided below.
    private retrieveItem(): void{
      let langID = document.getElementById('LanguageId')["value"];
        let web = new Web(this.context.pageContext.web.absoluteUrl);
     
        pnp.sp.web.lists.getByTitle('Language').items.getById(langID).get().then((result) =>{
          alert("Retrieved Item: "+ result.Title);
          document.getElementById('LanguageName')["value"] = "";
          document.getElementById('LanguageId')["value"] = "";
          this.RenderLanguagesEntries();
        }).catch((error) => {
          alert("Something went wrong" + error);
          document.getElementById('LanguageName')["value"] = "";
          document.getElementById('LanguageId')["value"] = "";
        });
    }

    private retrieveItem(): void{
    let langID = document.getElementById(‘LanguageId’)[“value”];
    let web = new Web(this.context.pageContext.web.absoluteUrl);

    pnp.sp.web.lists.getByTitle(‘Language’).items.getById(langID).get().then((result) =>{
    alert(“Retrieved Item: “+ result.Title);
    document.getElementById(‘LanguageName’)[“value”] = “”;
    document.getElementById(‘LanguageId’)[“value”] = “”;
    this.RenderLanguagesEntries();
    }).catch((error) => {
    alert(“Something went wrong” + error);
    document.getElementById(‘LanguageName’)[“value”] = “”;
    document.getElementById(‘LanguageId’)[“value”] = “”;
    });
    }

  • To update the language, SharePoint developers need to enter the new language name and the id of the language for which the language is to be updated.
  • Here, consider updating Bengali to Croatian.
  • Users will be prompted with a message of successful language updates. Clicking on OK will reflect the change in the table.
    The code to update items is provided below.
    private updateItem(): void
    {
      let langID = document.getElementById('LanguageId')["value"];
      let langName: string = document.getElementById('LanguageName')["value"];
      let web = new Web(this.context.pageContext.web.absoluteUrl);
     
      pnp.sp.web.lists.getByTitle('Language').items.getById(langID).update({
        Title: langName
      }).then(() =>{
        alert("Item updated successfully");
        document.getElementById('LanguageName')["value"] = "";
        document.getElementById('LanguageId')["value"] = "";
        this.RenderLanguagesEntries();
      }).catch((error) => {
        alert("Something went wrong" + error);
        document.getElementById('LanguageName')["value"] = "";
        document.getElementById('LanguageId')["value"] = "";
      });
    }

    private updateItem(): void
    {
    let langID = document.getElementById(‘LanguageId’)[“value”];
    let langName: string = document.getElementById(‘LanguageName’)[“value”];
    let web = new Web(this.context.pageContext.web.absoluteUrl);

    pnp.sp.web.lists.getByTitle(‘Language’).items.getById(langID).update({
    Title: langName
    }).then(() =>{
    alert(“Item updated successfully”);
    document.getElementById(‘LanguageName’)[“value”] = “”;
    document.getElementById(‘LanguageId’)[“value”] = “”;
    this.RenderLanguagesEntries();
    }).catch((error) => {
    alert(“Something went wrong” + error);
    document.getElementById(‘LanguageName’)[“value”] = “”;
    document.getElementById(‘LanguageId’)[“value”] = “”;
    });
    }

  • To delete the item, the id for the language to be deleted should be entered. Suppose, here the newly added language “French” is deleted.
  • Entering the id of the language and clicking the “Delete Item” button will prompt the user for confirmation.
  • Clicking OK will delete the language, and the table will be updated.
    The code to delete items is provided below.
    private deleteItem(): void
    {
      let boolDelete: boolean = confirm("Are you sure you want to delete item?");
        if(boolDelete)
        {
          let langID = document.getElementById('LanguageId')["value"];
          let web = new Web(this.context.pageContext.web.absoluteUrl);
     
          pnp.sp.web.lists.getByTitle('Language').items.getById(langID).delete().then(() =>{
            alert("Item deleted successfully");
            document.getElementById('LanguageName')["value"] = "";
            document.getElementById('LanguageId')["value"] = "";
            this.RenderLanguagesEntries();
          }).catch((error) => {
            alert("Something went wrong" + error);
            document.getElementById('LanguageName')["value"] = "";
            document.getElementById('LanguageId')["value"] = "";
            this.RenderLanguagesEntries();
          });
        }
        else{
          return;
        }
    }

    private deleteItem(): void
    {
    let boolDelete: boolean = confirm(“Are you sure you want to delete item?”);
    if(boolDelete)
    {
    let langID = document.getElementById(‘LanguageId’)[“value”];
    let web = new Web(this.context.pageContext.web.absoluteUrl);

    pnp.sp.web.lists.getByTitle(‘Language’).items.getById(langID).delete().then(() =>{
    alert(“Item deleted successfully”);
    document.getElementById(‘LanguageName’)[“value”] = “”;
    document.getElementById(‘LanguageId’)[“value”] = “”;
    this.RenderLanguagesEntries();
    }).catch((error) => {
    alert(“Something went wrong” + error);
    document.getElementById(‘LanguageName’)[“value”] = “”;
    document.getElementById(‘LanguageId’)[“value”] = “”;
    this.RenderLanguagesEntries();
    });
    }
    else{
    return;
    }
    }

Redeploy webpart in MS Teams

Let us see how to make changes to Web Part’s code and redeploy the Web Part to Teams. Few steps will be followed to get those updates in the already existing Web Part in MS Teams.

Note that we are not changing any version number here. We are just updating the .ts file code.

Follow the below steps after making changes to the code:

  • Generate a GUID and change “libraryId” property value in .yo-rc.json file to newly generated GUID.
  • Change the id property value to the newly generated GUID.
  • Enter gulp build in command prompt. Make sure you are inside the project directory.
  • Then enter the gulp bundle –ship in the command prompt.
  • Then enter gulp package-solution –ship in the command prompt. These steps will update the .sppkg file, which resides in the solution folder.
  • Upload the package in the Apps for SharePoint list of the App Catalog site, which will prompt for replacing an already existing package.
  • Click on the replace option.
  • Click on the Deploy option. 
    Now, selecting the solution and then clicking the “Sync to Teams” option will throw an error as “Failed to sync solution to teams” as a Web Part already existing in MS Teams having the same name.
    We first need to uninstall and delete it in MS Teams and then again upload the updated solution.
  • Navigate to Teams, and remove the tab having Web Part by selecting the remove option.
  • Click on the Remove button. Now, again if we try to Sync the updated package in the Apps for SharePoint list, it will throw the same error as we have just removed the tab. We need to uninstall the package from Teams.
  • Navigate to Apps in Teams
  • Click on the delete icon for the Web Part.
  • Click on the uninstall button.
    This will remove the Web Part from the Apps tab.After successfully deleting it, again navigating to the Apps for SharePoint list and trying to sync the package will again throw an error. This appears because even though we have removed the Web Part from Apps, still, the Web Part exists in the MS Teams store of our tenant.
  • Navigate to Store by clicking the Store option available in the bottom left corner in Teams.
  • The Web Part deployed will be found under the tenant name. 
  • Click on the Delete option available for the Web Part.
  • Then click on the Delete app button.
    After successfully deleting the Web Part, again navigate to the App Catalog site of the tenant and try to sync the updated package.
    The Web Part will be successfully synced to Teams. To view the updated Web Part in Teams, just add the Web Part by clicking the “+” sign in tabs in any of the teams created and selecting the Web Part that is updated (No need to manually deploy the Web Part to Teams if ‘Synced To Teams” option is fully developed).
  • The updated changes will be reflected in Teams.
    Note: To remove the Web Part from Teams, Sharepoint consultants can directly remove it from the store. No need to remove it from tabs and Apps.The CRUD operation will work after integrating the Web Part to Teams. Make sure you have created the list in the site collection where the team is created.

Conclusion

From this blog, one can get an idea to utilize the MS Teams more efficiently. With the help of the MS Teams tab, one can carry out the different operations of SharePoint Online using a single user interface. SharePoint developers can get a basic idea of performing CRUD operation via PnP JS through your MS Team tab and also about updating your existing MS Team Tab. Based upon the requirement, one can develop the SPFx Web Part and integrate it into MS Teams to use it effectively as a tab.

Comments


Your comment is awaiting moderation.