In this part, I’m going to implement the following features by using Reactive Programming:
Make a row in the skill table read-only as soon as the name and score is filled in.
Add an empty line
Automatically update the model in case the person object changes.
The BaseState is being used as a base for any State object. Now, for using reactive programming and enable this for each state, I have added a small generic piece of code in the BaseState. This logic will determines any changes in the JSONModel, which is part of the State, by using the eventhandler “attachPropertyChange”. This eventhandler contains all the information of the property that has been changed in the UI. Based on this information, I’m going to search (in the “data” object of the state) for a function in the object that’s being changed with the name of the property being changed followed with “Changed”. For example: if the property “Score” of the object “Skill” changes in the UI, the code will look for the function “ScoreChanged” in the Skill object.
In case of a nested object, the code will also check for a “Changed” function of the parent object. For example: the property “Score” is part of the “Skill” object which is again an entry of the “Skills” array of the “Person” object. So the code will check for a function “SkillsChanged” in the “Person” object. This is because of “Skills” is the parent property of the Skill object and it’s part of the “Person” object.
Last but not least, the code will also look for a “Changed” function in the state itself. Sometimes, it can be useful to have the changed function of a property in the state. This can be in case that you need to have access to other variables that are defined in the state or because you are maybe not using seperate objects. For example if “Score” changes in the UI, it will look for the function “ScoreChanged” in the state itself.
This magic is done by the following piece of code added in the constructor of the “BaseState”:
If I now added the following functions to the “Skill” object, it will change the UI as soon as the “SkillName” or “Score” is filled in. When one of the fields is filled in, the “delete” button will be visible. When both fields are filled in, it will change to display mode:
As soon as there is no empty line anymore, we need to add an empty line. Therefor, I’ve added a function “SkillsChanged” to the Person object. “Skills” is a property of the “Person” object and the parent of the “Skill” object. As soon as one field in one of the Skill rows changes, it will call this function and add an emtpy line:
Last step, getting rid of the manual refresh of the model with the “updateModel” function. Personally, I do not have a problem triggering this manual because this gives you more control on the refresh behavior. But I’m also aware of other developers that just don’t want to think of it and take care about it. For them, I’m going to make the “Person” object in the state observable to automatically update the model on each change.
To do this, I added the “observable-slim” library to my project:
In the state, I use this library to make the “data” object observable. With this library, I’m able to assign an eventhandler to the “data” object for every change in it. In this eventhandler I update the model and automatically it will be executed on every change in the “data” object. This means that I only need to define “updateModel” once:
Now the app is able to view Persons with their skills and also create a new person together with multiple skills. The app is even able to automatically switch a skill row from edit to display, adding a new empty line and only writing the “updateModel” once.
There is only one functionality left that’s not yet working, the “delete skill” button.
For this, I added a “deletePersonSkill” function in the “PersonState”. This will delete a skill, based on the index, from the current “Person” object. Thanks to observable library, I don’t need to update the model 🙂
I added the following function in the “BaseController” which I’m going to use to determine selected row index based on the source of the control:
In the controller of the “detail” view, I created an eventhandler for the delete button which will use the “getIndexFromPath” function to determine the selected row and pass it to the “deletePersonSkill” function in the “PersonState”