Outline 2 How To 3
Outline 2 How To 3
Table of Contents
Outline 2
How to 3
Offline Interaction and Role Checking 3
Changing the Network Status 14
Average Rating 19
User Rating - Synchronization Revisited 28
1
Outline
In this exercise, we will prepare the OSMDb Mobile application to properly work offline. So far,
we created the local storage data model and the synchronization algorithm, but there are still
some situations in the app that only work when the device is online:
● Check Roles
● Calculate the Average Rating
● AddCastAndCrew Screen
When the device becomes offline, the application throws communication errors, since all the
Screens have Data Actions used to check roles and the MovieDetail Screen has the average
rating.
First, we will use the J avaScript API to check the OSMDbAdmin Role offline (client-side) on
Screens, instead of the Data Actions. This guarantees that the role is verified either when the
app is online or offline.
Then, we want to make sure that despite the Role, the movie and person information cannot be
edited while offline, with the exception of the user movie rating in the MovieDetail Screen. Also,
the access to the AddCastAndCrew Screen can only be done when the application is online.
To support that, it is important that the application distinguishes when the app gets offline or
online, on the application Screens. That can be done using the NetworkStatusChanged Block of
the OutSystems UI Framework. This Block has an Event that is triggered when the network
status changes.
Then, on the MovieDetail Screen, we have a Database Aggregate that calculates the Average
Rating for the movie. Since that functionality will only continue to work online, we need to make
sure that the average rating only appears, and is calculated, when the app is online.
Finally, the user will be able to rate movies, even when offline. This means that when the app is
offline, the ratings will only be saved locally. However, when the network gets back online, the
new ratings should be synchronized with the server and the information should be updated in
the Database as well.
2
How to
In this section, we’ll describe, step by step, the exercise 5.4 - Offline.
In the first part of this exercise, we will replace the Data Actions by a different way of role
checking, which works client-side, using a J avaScript API. However, it is important to mention
that this API should only be used to help designing the UI. Being a client-side only verification, it
does not provide the same security strength as a server-side verification, since the device can
be more easily tampered. With that in mind, all business validations should be done on
server-side, right before a critical operation is done, on Server Actions. In the
OSMDb_Core_Mobile module, we have a couple of Server Actions that do exactly that, before
any operation in the database is made.
Then, besides the role restrictions, we want to make sure that no information from movies or
people are modified when the user is offline, except for the movie rating.
1. Create a Client Action, CheckOSMDbAdminRole. This Action will check if the logged in user
has the OSMDbAdmin Role. This Action should use the JavaScript API to accomplish this.
3
c. Drag a JavaScript n
ode and drop it on the Action flow. Set its N
ame t o
CheckOSMDbAdminJS.
4
d. Double-click the JavaScript node to open it. Here, we will check if a user has the
OSMDbAdmin Role. So, let’s first add an Output Parameter to the JavaScript node
by right-clicking on the Parameters f older and selecting the respective option.
f. Add an Output Parameter to the Client Action, set its Name t o HasRole a
nd its
Data Type to Boolean.
$parameters.HasRole = $public.Security.checkIfCurrentUserHasRole($roles.OSMDbAdmin);
5
h. Drag an Assign n
ode and drop it after the JavaScript. Set the Assignment to be:
HasRole = CheckOSMDbAdminJS.HasRole
2. In the Movies S
creen, the Data Action is used to help us display the option to create a
new movie only when the user has the OSMDbAdmin Role. Let’s delete the Data Action
and use the CheckOSMDbAdminRole A
ction to control that behavior. The
CheckOSMDbAdmin Action should be used on the O
n Initialize Event, to check the Role
before the Screen is rendered. Also, a user should only be able to create a new movie if
the application is online.
a. In the OSMDb_Mobile module, switch to the Interface tab and expand the M
ovies
Screen.
b. Delete the C
heckAdminRole Data Action.
6
This should lead to an error, since the Data Action was used in an If widget, to
hide the Create New Movie option on the top right corner of the Screen.
c. Select the Movies Screen, expand the Event area and select the On Initialize
Event.
7
d. Switch to the Logic tab and drag the CheckOSMDbAdminRole Action to the
OnInitialize Action flow.
e. Now, we need to save the value of the Output Parameter from the
CheckOSMDbAdminRole in a Local Variable. Right-click on the Movies Screen and
select Add Local Variable.
g. Drag an Assign a
nd drop it after the CheckOSMDbAdminRole Action call in the
OnInitialize Action flow.
8
HasAdminRole = CheckOSMDbAdminRole.HasRole
j. Open the Movies Screen, select the If that is causing the error and set its
Condition to
This guarantees that the icon only appears when the two scenarios are true.
However, there’s still some logic necessary to control the online / offline scenario,
which will be done later in this exercise.
3. In the People S
creen, the Data Action is also used to help us display the option to create
a new person in the database only when the user has the OSMDbAdmin Role. Let’s apply
in this Screen the same logic used in the Movies Screen.
4. In the MovieDetail S
creen, we have two Data Actions, one to check the OSMDbAdmin
Role and another one to check the Registered Role. To replace the one about the
OSMDbAdmin Role, we can use the same strategy used in the previous two Screens. For
the Registered Role, we can just check if the User Identifier is different from
NullIdentifier(), using the GetUserId() system function. Finally, we want to make sure that
9
besides the existing Role verifications, we only want to be able to edit and save the
movie information if we are online, except for the movie rating.
a. Expand the MovieDetail Screen and delete the two existing Data Actions. This
will raise several errors in the application.
b. Add two L
ocal Variables to the MovieDetail Screen: HasAdminRole (Boolean) and
IsOnline (Boolean).
d. Define the O
nInitialize Action just like in the previous Screens
10
f. Notice that all the input fields in the Form have an error. Fix those errors by
setting their Enabled p
roperty to
11
5. Apply the same logic as in the above scenarios to the PersonDetail Screen.
a. Open the StarClickedHandler Action, drag an If node and drop it before the
UserMovieRatingCreateOrUpdate Action call.
12
c. Drag an Assign a
nd drop it to the right of the If. Create the T
rue b
ranch between
the If and the Assign.
GetMovieById.List.Current.LocalMovie.Rating = SelectedStar
NOTE: The rating was already being saved in the Assign that already existed in
the Action flow (the one right after the Server Action). The problem is that Assign
will only run now when the app is online, so we need to make sure that the rating
is still saved when the app is offline.
e. Right-click on the If and select Swap Connectors to make sure that the Server
Action is called only when the app is online.
13
14
know when the network status changes, while the user is interacting with the Screen.
The I sOnline L
ocal Variable will save the current status of the network.
b. Drag a Run Client Action node to the flow and drop it before the
CheckOSMDbAdminRole Action.
15
IsOnline = GetNetworkStatus.IsOnline
16
h. Drag an Assign n
ode and drop it on the NetworkStatusChangedHandler Action
flow. Set the Assignment to
IsOnline = IsNetworkOnline
17
2. Use the same strategy on the remaining Screens: MovieDetail, People and PersonDetail.
4. Open the application on the device. Login with a user with the OSMDbAdmin Role.
5. Confirm that in the Movies Screen, the option to create a new movie appears.
6. Turn off the network connection to make the application work offline. Notice that the
option to create a new movie disappears.
7. Open the People Screen and notice that no error is thrown and the Screen works as
expected.
8. Turn on the network connection again and confirm that the option to add a new person
appears on the top of the Screen.
9. Now turn off the network connection again and go back to the Movies Screen. Select any
movie on the list to navigate to the MovieDetail Screen. An error is thrown indicating
that there was a request failed with an error. This happens because the
GetAverageRating is a Database Aggregate, which is trying to be executed when the
Screen is initializing. In the next section of the exercise, we will fix this problem.
18
Average Rating
To solve the problem that was identified in the previous section, we need to define a new Block.
This Block will have the G
etAverageRating in it, as well as the S
tarDisplay Block as the only
element in its UI.
On the MovieDetail Screen, the new Block should only be displayed when the Screen is online,
which can be controlled by the Local Variable IsOnline. When a user rates a movie, the average
rating should be calculated again, if the app is online. The same applies when the network
status changes from offline to online, while we are interacting with the Screen.
1. Create a new Block called AverageRating, with the GetAverageRating Aggregate and the
StarDisplay Block in its UI.
19
f. Set the values for the Input Parameters of the StarDisplay Block to be:
Rating: GetAverageRating.List.Current.RatingAvg
AllowClicking: False
20
g. Drag a Label a
nd drop it before the StarDisplay Block. Set the T
ext to Average
Rating.
21
c. Set the MovieId Input Parameter value to MovieId ( the Input Parameter of the
MovieDetail Screen).
22
3. At this point, Service Studio has an error. When the user rates a movie, the
GetAverageRating Aggregate is re-executed (in the StarClickedHandler Action). Since
the Aggregate is not available on the Screen that Refresh Data node should be deleted.
4. Publish the module and access the MovieDetail Screen offline. No error should be
thrown at this point.
5. Rate a movie. Did the Average Rating change? It shouldn’t! This means that we are not
done yet! The reason behind this is that the Average Rating is now inside a Block,
including the Aggregate. So, since the only Input Parameter is the MovieId, and since
that does not change with a new rating, we need to somehow trigger the rendering of
the Block, which will in turn run the Aggregate again to calculate the average rating.
6. Add an Input Parameter to the AverageRating Block, called UserRated, which is
controlled by a L
ocal Variable on the MovieDetail Screen with the same name.
Whenever the user rated a movie, that variable changes the value, thus changing the
Input Parameter of the Block.
a. Add a new L
ocal Variable to the MovieDetail Screen, called U
serRated, with D
ata
Type set to B
oolean.
23
b. On the S
tarClickedHandler A
ction, drag an Assign node and drop it right after
the LocalMovieCreateOrUpdate Action call
This guarantees that the value of the variable changes every time the user rates
the movie, which is what will cause the Block’s Input Parameter to change as well.
24
25
b. Drag the Refresh Data node and drop it on the Action flow
d. This re-execution of the GetAverageRating should be done only when the app is
online. Since the Block does not have access to the scope of the Screen, add a
new Input Parameter to the Block, call it IsOnline a
nd set the D
ata Type is set to
Boolean. This will create an error that will be solved in the next steps.
e. Drag an If n
ode and drop it above the Refresh Data node. Set the C
ondition to
IsOnline. Drag an E
nd node and drop it to the right of the If and connect the two
26
NOTE: Despite not being used, the UserRated Input Parameter triggers the On
Parameters Changed event, every time a user rates a movie, due to the last
Assign we added in the StarClickedHandler Action. This is enough to trigger the
Event, run the Action Handler and re-execute the Aggregate if the app is online.
The Block itself will also render on the Screen.
f. In the MovieDetail Screen, select the instance of the AverageRating Block and set
the value of the IsOnline I nput Parameter to the Local Variable I sOnline. This will
solve the error caused two steps ago.
27
8. Publish the module and test the app. The average rating should work properly at this
point.
● Set the Local Storage to save which ratings were modified, since the last time the app
was online. That can be done with the help of an extra attribute, that is set to T rue
whenever a new rating is added while offline.
● Modify the synchronization logic to send to the server the movie ratings changed since
the last time the app was online.
● Define a new SyncUnit to define this new synchronization moment, leveraging the
existing Static Entity.
● Trigger the synchronization, with the new SyncUnit, whenever the app gets back online.
28
2. In the synchronization logic for the movies and local movies, make sure that we send to
the server the movies that were modified with new ratings, and update that information
in the database.
b. Drag an Aggregate a
nd drop it right before the SyncMovies Action call.
LocalMovie.IsModified = True
29
f. Now, we need to send this list to the server. Add an I nput Parameter to the
SyncMovies Server Action, set its Name t o ModifiedLocalMovies and its D
ata Type
to LocalMovie List.
This creates an error, since now the SyncMovies Action expects a value for the
new Input Parameter in the SyncLocalMovies Action.
g. Select the SyncMovies Action node in the SyncLocalMovies Action flow and set
the ModifiedLocalMovies v
alue to G
etModifiedLocalMovies.List.
30
i. Drag a Run Server Action and drop it to the right of the For Each.
k. Connect the For Each with the CreateOrUpdateUserMovieRating Action and the
Action to the For Each to create a loop.
31
Id = RatingId
UserId = GetUserId()
MovieId = Id
Rating = Rating
The I d of the UserMovieRating record is stored in the R
atingId attribute of the
LocalMovie, as well as the Rating. The UserId c an be easily set with the user
function G
etUserId(). The M
ovieId attribute is set to the I d of the LocalMovie
record.
32
4. In the OSMDb_Mobile module, refresh the dependencies to include the latest changes
published in the Core module.
5. In the MovieDetail Screen, we can rate a movie while offline. So, we need to mark the
movie that was rated as modified, while offline, using the IsModified attribute. Select the
Assign node to the right of the IsOnline? If and add the following assignment
GetMovieById.List.Current.LocalMovie.IsModified = True
6. To finish, we just need to trigger the synchronization procedure when the app gets
online. Make sure that the only data synchronized at this point should be the movie
ratings.
33
c. Drag an If n
ode and drop it to the right of the existing If.
e. Drag a Run Client Action and drop it below the most recently added If
34
h. Drag an End n
ode and drop it below the SyncRatings Action. Connect the two
nodes.
35
c. Drag a Run Client Action and drop it to the right of the If node.
e. Connect the If to the Action to create the True branch and then the Action to the
End node.
f. Repeat the exact same process for the People, MovieDetail and PersonDetail
Screens.
8. Test the application in the device and guarantee that it works as expected.
36