Skip to main content

Implementing Offline Capability In Your App

Do you want to build offline capabilities in your PowerApps app because your app users need to access some data or save some data even when they don't have the internet connection? This blog provides an example of building these offline capabilities in your PowerApps app. This article assumes that you already know the basic concepts of PowerApps like screens, controls, events, attributes, navigation etc. We'll will use all these concepts in this tutorial.
 

Note

The offline feature area is still under development and is not optimized for every offline scenario today. The functions to SaveData() to a local device and LoadData() from that device work best in their current implementation over relatively small quantities of data (e.g., dozens of text records in a table) that generally do not exceed 2MB. This is useful for some basic “offline” scenarios as well as to increase the startup performance of canvas apps by caching data locally. However, using this feature to save large amounts of data (e.g., saving thousands of rows in a table, or caching large images or videos) may cause errors or unexpected behavior with the current implementation and should be avoided. Also, the functions do not automatically resolve merge conflicts when a device returns to connectivity from offline – configuration on what data is saved and how to handle reconnection is up to the maker when writing expressions. We are working to expand the capabilities of offline apps to increase stability and size limits, and in the future to automatically handle decisions about what to save and how to handle conflicts. Stay tuned here and on the PowerApps blog for updates when they become available. 

 

Offline Requirements Of An Example Issue Reporting App

For this tutorial, let’s assume we have to build a simple Issue Reporting App with the following requirements:

  • Show the list of reported issues (show latest data from the database or offline cache when the internet connection is not available)
  • Capture new issues even when the internet connection is not available and save them to the database when the internet connection becomes available

 

image

 

Note:

  • For this blog, I’ll not get into conflict resolution scenarios e.g. allow offline editing of existing records and resolve conflicts with the edits done by other users on the same record. Implementing conflict resolution needs more work- e.g. you have to not only detect conflicts but also come up with a policy to resolve the conflict (auto resolution or user intervention). Conflict Resolution implementation would be easier to grasp, once you fully understand the offline capabilities described in this article. If there is enough interest, I’ll write another article covering the conflict resolution aspect as well.
     
  • You can find finished version of the example app over here (msapp file is here and exported package along with CDS is here). For this app, I used CDS (Common Data Service) as the data source. However same concepts will apply to any other data source like SharePoint, SQL etc.

 

Part 1:  Build Offline Cache of the Issue List: Show Online or Offline List Depending On the Internet Connection Availability

 

High Level Approach for accomplishing this is:

  • On start of the app or on click of a button, check if the internet connection is available
  • If internet connection is available, fetch the data from the the database and put that in a collection (table in memory). Also, save this collection data to local  storage of your device (local cache) so that we can use this cached data next time when the internet connection is not available (see next bullet).
  • If internet connection is not available, fetch data from local storage of your device and use that to populate the collection.

 

For this app, I created a very simple custom entity “Issue List” in CDS (Common Data Service) to capture issues with “Title” and “Description” as 2 custom fields.
Note- I used CDS as the data source for my app. You can also use any other data source like SQL, SharePoint Online etc for creating similar table. Offline implementation concepts will be same.

 

image

 

First screen in this sample app is a cover page kind of screen. On the click of “Let’s Go” button, we’ll check the internet connection via an object exposed by PowerApps called “Connection”. If internet connection is available (i.e. Connection.Connected is true), populate the local collection “IssueCollection” directly from the entity “Issue List” in the CDS database. Also, save it to the local storage (local cache) as “issuesInLocalStorage” so that we can use it as local cache when the internet connection is not available. If internet connection is not available, populate “IssueCollection” from this local cache. Finally, put the formula to navigate to the next screen where we’ll be using the “IssueCollection” collection as the data source (Items property) for the gallery to show all the issues.

 

Following is the formula to be written on OnSelect event of the  button “Let’s Go”:

If(Connection.Connected,

ClearCollect(IssueCollection, 'Issue List');

SaveData(IssueCollection,"issuesInLocalStorage"),
LoadData(IssueCollection,"issuesInLocalStorage", true)

);

Navigate(IssueListScreen,ScreenTransition.Cover)

 

Note- I chose the option to do all this work in the OnSelect event of a button. You are free to use a different approach like doing all this work in the OnStart event of the app or OnVisible event of the screen.

 

image

 

Now, on the next screen (“IssueListScreen”), insert a gallery and set the Items property of that gallery to “IssueCollection”. Show the Title and Description fields in the gallery. That’s it for the first requirement. Your app is now ready to show data directly from the data source or local cache depending on the internet connection availability.

 

Test it by first opening the app and seeing the gallery data with the internet connection on your phone. Close the app and now turn the phone in the airplane mode. Open this app again and hit “Let’s Go”. You should see the issue list coming from Local Cache.

Important Note- As of now, you can’t test the LoadData and SaveData in browser. You must use your mobile device to test that part. In the web editor, you might see the error for LoadData and SaveData. Please ignore that.

 

image

 

Part 2: Capture new issues even when internet connection is not available and save to the database when the internet connection becomes available

For adding new issues, add a new screen “NewIssueScreen” and insert an EditForm control in that screen. Navigate to this screen on the press of plus sign from the "IssueListScreen”. Our high level approach for save new data (new issue for our app) will be as follows:
 

  • If the internet connection is available,
    • Submit the form so that new issue is directly saved to the database.
    • Refresh the “Issue List” data source and repopulate the collection “IssueCollection” with the latest data from “Issue List” data source (so that your local collection gets the last record added in the table).
    • Save “Issue Collection” collection in the local storage as “issuesInLocalStorage” – this ensures that the newly added record is available in local cache to be used next time when the app is opened in offline mode (without internet connection)
  • If the internet connection is not available,
    • Add the offline issues to be added to a local collection called “IssuesToBeAdded”. In a later step, using a timer, we’ll keep checking the internet connection availability. As soon as the internet becomes available, we’ll try saving this local collection to the database and clear the local collection.
    • Also save this local collection of offline “IssuesToBeAdded” to local storage as “newIssuesInLocalStorage”. This will be useful if the app is closed with some offline new issues to be saved. We’ll retrieve it from the local storage next time when the app is opened.
       

Following is the formula to be used on the “OnSelect” event of a save button:

If(Connection.Connected,SubmitForm(EditForm1); Refresh('Issue List'); ClearCollect(IssueCollection,'Issue List');
SaveData(IssueCollection,"issuesInLocalStorage")
,
Collect(IssuesToBeAdded,{Title:TitleDatacard.Text,Description:DescriptionDatacard.Text} ); SaveData(IssuesToBeAdded, "newIssuesInLocalStorage"));

Navigate(IssueListScreen,ScreenTransition.Cover)

 

image

 

  • Add a new screen to show these offline issues to be added (I call it “UnSavedIssuesScreen”). Add a gallery control and set the “Items” property of the gallery control to “IssuesToBeAdded”.
     
  • On the “IssueListScreen”,
    • Add a label at the bottom to show how many offline issues are to be save to database (or, if all of them are saved, indicate so). This is done by checking the count or rows in the collection “IssuesToBeAdded”. Text formula for this label should be:

            If(CountRows(IssuesToBeAdded) >0,CountRows(IssuesToBeAdded) & " offline issues to be added", "0 offline issues. All caught up.”)
           

    • Add a timer that checks every 30 seconds for the internet connection availability (using the same Connection object we used earlier). If the Connection is connected and there are some pending offline issues to be saved,:
      • Save the “IssuesToBeAdded” collection to the database 
      • Clear the collection “IssuesToBeAdded” (because they are all saved to the database now)
      • Get the latest list of issues from the database (by using Refresh method on “Issue List” and repopulating the collection “IssueCollection”)
      • Update the local cache “issuesInLocalStorage” with this repopulated collection “IssueCollection”. This will ensure that app can get the updated issue list from the local cache if it is opened next time in offline mode (without internet connection)

                 Below is the formula for OnTimerEnd event of the timer:

                  If(Connection.Connected && CountRows(IssuesToBeAdded) >0,

                     Collect('Issue List',IssuesToBeAdded);

                     Clear(IssuesToBeAdded);

                     SaveData(IssuesToBeAdded,"newIssuesInLocalStorage");

                     Refresh('Issue List');

                     ClearCollect(IssueCollection, 'Issue List');

                     SaveData(IssueCollection,"issuesInLocalStorage"))

 

             With this, we are all set with saving the offline issues to database as soon as the connection is available and also getting a label to tell us how many issues are offline issues to be saved.

image
 

  • Last thing we need to do is go back to the first screen and on the click of “Let’s Go” button, update the formula to check offline issues from the local cache. This will ensure that if the app was closed last time with some offline issues to be saved, app will retrieve them from local storage and keep trying to save it on internet connection availability (on the IssueListScreen) . So, update the formula of OnSelect event of the button “Let’s Go” to (bolded part is the new addition in the earlier formula):

If(Connection.Connected, ClearCollect(IssueCollection, 'Issue List');SaveData(IssueCollection,"issuesInLocalStorage"),
LoadData(IssueCollection,"issuesInLocalStorage", true));

LoadData(IssuesToBeAdded,"newIssuesInLocalStorage", true); Navigate(IssueListScreen,ScreenTransition.Cover)

 

Side note- Caching data is a good strategy for your app performance as well. You can learn more about performance tips for your apps in this blog.

 

 image

 

With this, we are done with building basic offline capabilities in your app. Without internet connection, your user can see the issues cached last time and even add new issues offline (to be synced later on internet connection availability). Keep in mind that your user has to open this app at least once and tap on “Let’s Go” once to ensure “Issue List” is cached once.

 

Conclusion

 

Building offline capabilities makes your app even more compelling for your users (esp. mobile users traveling to places with spotty internet connections). Hopefully this tutorial provided you necessary guidance to build these offline capabilities in your PowerApps app. We excluded Conflict Resolution requirements from the scope of this blog to make this article easily digestible. Most of the customer scenarios we heard don’t even need conflict resolution. However if many of you need help implementing conflict resolution requirements, let us know. We’ll be happy to do another blog on that topic. Happy App Building!