How to Work Offline with PowerApps

In this post I will show you step by step how to work offline with PowerApps. To make your app work offline there are essentially three processes you must solve for. Saving data to device when online for offline use. Saving data to device when working offline and sync data up when your back online. In the following steps I will use actual samples of an app I created with offline capabilities, so excuse the length. For your app you just substitute with your data. Continue reading and you too will become an Office Power User!

How-To-Work-Offline-With-PowerApps

Preparing AppData on Start Up

First thing you need to decide is which parts of your app will function offline and which will function only online. Once you have decided you load all your offline content into collections and then save them on your device.

  • App On Start
    • OnStart:
      Set(
      varUser,
      varOfficeUser.Email
      );
      Set(
      varClientID,
      72
      );
      //We check if we are connected and if so we collect the data we need for the app into collections
      If(
      Connection.Connected,
      Concurrent(
      ClearCollect(
      colUserPref,
      Filter(
      ‘[dbo].[tblWPO_preferences]’,
      TheUser = varUser
      )
      ),
      ClearCollect(
      colOUs,
      Filter(
      ‘[dbo].[tblQltyOUs]’,
      ClientID = varClientID
      )
      ),
      ClearCollect(
      colLocations,
      Filter(
      ‘[dbo].[tblQltyLocations]’,
      ClientID = varClientID
      )
      ),
      ClearCollect(
      colTeams,
      ‘[dbo].[tblWPO_Teams]’
      ),
      ClearCollect(
      colTeamsDepartments,
      ‘[dbo].[tblWPO_TeamDepartments]’
      ),
      ClearCollect(
      colSafetyAreas,
      ‘[dbo].[tblWPO_SafetyAreas]’
      ),
      ClearCollect(
      colWPOItems,
      ‘[dbo].[tblWPO_Items]’
      ),
      ClearCollect(
      colTranslations,
      Filter(
      ‘[dbo].[tblWPOTranslations]’,
      ClientID = varClientID
      )
      )
      );
      // Below I have a table that may have more than 2K records.
      If(
      CountRows(colTranslations) = 2000,
      Set(
      varIDForNextTransRun,
      Max(
      colTranslations,
      ID
      )
      );
      Collect(
      colTranslations,
      Filter(
      ‘[dbo].[tblWPOTranslations]’,
      ClientID = varClientID && ID > varIDForNextTransRun
      )
      )

      );
      If(
      CountRows(colTranslations) = 4000,
      Set(
      varIDForNextTransRun,
      Max(
      colTranslations,
      ID
      )
      );
      Collect(
      colTranslations,
      Filter(
      ‘[dbo].[tblWPOTranslations]’,
      ClientID = varClientID && ID > varIDForNextTransRun
      )
      )
      );
      // Now that we have the data in collections we save them to device for offline use.
      SaveData(
      colOUs,
      “LocalcolOUs”
      );
      SaveData(
      colLocations,
      “LocalcolLocations”
      );
      SaveData(
      colTeams,
      “LocalcolTeams”
      );
      SaveData(
      colTeamsDepartments,
      “LocalcolTeamsDepartments”
      );
      SaveData(
      colSafetyAreas,
      “LocalcolSafetyAreas”
      );
      SaveData(
      colWPOItems,
      “LocalcolWPOItems”
      );
      SaveData(
      colTranslations,
      “LocalcolTranslations”
      );
      SaveData(
      colUserPref,
      “LocalcolUserPref”
      );
      // Here we will load data from device that has not been uploaded yet from previous offline use and upload while online.
      LoadData(
      coltblWPO_Header,
      “LocalcoltblWPO_Header”,
      true
      );
      LoadData(
      coltblWPO_Details,
      “LocalcoltblWPO_Details”,
      true
      );
      Set(
      varUserPicture,
      Office365Users.UserPhoto(varUser)
      );
      If(
      CountRows(coltblWPO_Header) > 0,
      ForAll(
      coltblWPO_Header,
      With(
      Patch(
      ‘[dbo].[tblWPO_Header]’,
      Defaults(‘[dbo].[tblWPO_Header]’),
      {
      CheckDT: CheckDT,
      CompletedBY: CompletedBY,
      HeaderID: HeaderTempID,
      LocationID: LocationID,
      Note: Note,
      OUid: OUid,
      TeamID: TeamID
      }
      ),
      ForAll(
      Filter(
      coltblWPO_Details,
      Text(TempHeaderID) = Text(HeaderTempID)
      ),
      Patch(
      ‘[dbo].[tblWPO_Details]’,
      Defaults(‘[dbo].[tblWPO_Details]’),
      {
      HeaderID: ID,
      CheckDT: CheckDT,
      ItemID: ItemID,
      Status: Status
      }
      )
      )
      )
      );
      // Now that the data has been captured we clear the collections and write the empty collection back to the device.
      Clear(coltblWPO_Header);
      Clear(coltblWPO_Details);
      SaveData(
      coltblWPO_Header,
      “LocalcoltblWPO_Header”
      );
      SaveData(
      coltblWPO_Details,
      “LocalcoltblWPO_Details”
      ),
      “”
      ),
      // If we are not online then we load app data into collections from device.
      Set(
      varUserPicture,
      GreyTeamDepartment
      );
      LoadData(
      colOUs,
      “LocalcolOUs”,
      true
      );
      LoadData(
      colLocations,
      “LocalcolLocations”,
      true
      );
      LoadData(
      colTeams,
      “LocalcolTeams”,
      true
      );
      LoadData(
      colTeamsDepartments,
      “LocalcolTeamsDepartments”,
      true
      );
      LoadData(
      colSafetyAreas,
      “LocalcolSafetyAreas”,
      true
      );
      LoadData(
      colWPOItems,
      “LocalcolWPOItems”,
      true
      );
      LoadData(
      colTranslations,
      “LocalcolTranslations”,
      true
      );
      LoadData(
      colUserPref,
      “LocalcolUserPref”,
      true
      );
      LoadData(
      coltblWPO_Header,
      “LocalcoltblWPO_Header”,
      true
      );
      LoadData(
      coltblWPO_Details,
      “LocalcoltblWPO_Details”,
      true
      );

      )

Saving Data During Run Time

When saving data in your app you must look for the online status and update collections and offline data appropriately. We are almost there. Soon you will know to work offline with PowerApps!

  • Save Record
    • OnSelect:
      UpdateContext({varShowSpinner: true}); // See link below to learn how to create a spinner component.
      UpdateContext({varHeaderID: Text(GUID())});
      Collect(
      // We collect the header informtion.
      coltblWPO_Header,
      {
      CheckDT: Today(),
      Note: txtNote.Text,
      CompletedBY: varUser,
      OUid: varOU,
      LocationID: varLocation,
      TeamID: varTeam,
      HeaderTempID: varHeaderID
      }
      );
      Reset(txtNote);
      Clear(colDetails);
      // We load the data from the gallery “colCheckList” collection into this temp “colDetails” collection.
      ForAll(
      colCheckList,
      Collect(
      colDetails,
      {
      HeaderID: 0,
      ItemID: ID,
      Status: CheckStat,
      CheckDT: Today()
      }
      )
      );
      Collect(
      coltblWPO_Details,
      AddColumns(
      colDetails,
      “TempHeaderID”,
      varHeaderID
      )
      );
      If(
      Connection.Connected, //
      ForAll(
      coltblWPO_Header,
      With(
      Patch(
      ‘[dbo].[tblWPO_Header]’,
      Defaults(‘[dbo].[tblWPO_Header]’),
      {
      CheckDT: CheckDT,
      CompletedBY: CompletedBY,
      HeaderID: HeaderTempID,
      LocationID: LocationID,
      Note: Note,
      OUid: OUid,
      TeamID: TeamID
      }
      ),
      ForAll(
      Filter(
      coltblWPO_Details,
      Text(TempHeaderID) = Text(HeaderTempID)
      ),
      Patch(
      ‘[dbo].[tblWPO_Details]’,
      Defaults(‘[dbo].[tblWPO_Details]’),
      {
      HeaderID: ID,
      CheckDT: CheckDT,
      ItemID: ItemID,
      Status: Status
      }
      )
      )
      )
      );
      Clear(coltblWPO_Header);
      Clear(coltblWPO_Details);
      SaveData(
      // Save empty collection back to device.
      coltblWPO_Header,
      “LocalcoltblWPO_Header”
      );
      SaveData(
      coltblWPO_Details,
      “LocalcoltblWPO_Details”
      ),
      // If we are not online then we save collection with data to device for later uploading.
      SaveData(
      coltblWPO_Header,
      “LocalcoltblWPO_Header”
      );
      SaveData(
      coltblWPO_Details,
      “LocalcoltblWPO_Details”
      )
      );
      UpdateContext({varShowSpinner: false})

Managing Unsaved Data During Run Time

Lastly we will use a timer control to check if device is online and if there are unsaved records and when true you save unsaved data back to data source, clear your collections and write updated data back to collections and save to device again for when you are offline.

  • Save unsaved data when back online.
    • OnTimerEnd:
      If(
      CountRows(coltblWPO_Header) > 0,
      // Check if records need saving.
      If(
      Connection.Connected,
      // If online then save the records.
      UpdateContext({varShowSpinner: true});
      ForAll(
      coltblWPO_Header,
      With(
      Patch(
      ‘[dbo].[tblWPO_Header]’,
      Defaults(‘[dbo].[tblWPO_Header]’),
      {
      CheckDT: CheckDT,
      CompletedBY: CompletedBY,
      HeaderID: HeaderTempID,
      LocationID: LocationID,
      Note: Note,
      OUid: OUid,
      TeamID: TeamID
      }
      ),
      ForAll(
      Filter(
      coltblWPO_Details,
      Text(TempHeaderID) = Text(HeaderTempID)
      ),
      Patch(
      ‘[dbo].[tblWPO_Details]’,
      Defaults(‘[dbo].[tblWPO_Details]’),
      {
      HeaderID: ID,
      CheckDT: CheckDT,
      ItemID: ItemID,
      Status: Status
      }
      )
      )
      )
      );
      Clear(coltblWPO_Header);
      Clear(coltblWPO_Details);
      SaveData(
      // Save empty collections to device.
      coltblWPO_Header,
      “LocalcoltblWPO_Header”
      );
      SaveData(
      coltblWPO_Details,
      “LocalcoltblWPO_Details”
      );
      Set(
      varSyncWarning,
      false
      );
      UpdateContext({varShowSpinner: false});
      ,
      “”
      )
      )

Now you know how to work offline with PowerApps! Please leave your feedback. I hope this article has been helpful for you so bookmark this blog as new articles are be posted regularly. 

Additional Resources

Do It For Me
how-to-create-a-spinner-component-in-powerapps
how-to-create-a-popup-confirmation-in-powerapps

Share the knowledge!

Paul Rodrigues

Business Analyst with 20 years of IT experience creating practical solutions. I love to automate business processes through the use of technology while making the end users work easier. My current favorite tools are PowerApps, Power BI and Power Automate. #PowerAddict

You may also like...

1 Response

  1. November 4, 2019

    […] Do It For MeSee it in a real world example how-to-work-offline-with-powerapps […]

Leave a Reply

Your email address will not be published. Required fields are marked *