How To: Component Reuse Part 2 - Sharing Data Between Apps

This is the second part of my blog series about component reuse. If you haven’t read my first one, please have a read here.

In the last blog I explained how we can incorporate a separate app inside a component container to be used in a parent application. This is really useful in a modular architecture.

While this is great, it starts becoming really cool when we can actually use that to work on the same data. An example could be a custom app as a search help, which can then retrieve a resultset and pass the selected option back to the parent app.

Currently, I see four different ways of doing this;

  1. Using the Window object

  2. Using the eventBus

  3. Using a core model

  4. Using a propogated model

I am fully aware that there is do’s and don’ts on the above options, but this blog is just to show you the options.

Alright - down to business!

The first example is quite simple. You can store objects in the window object, which is a representation of the open window on the browser. You can simply store variables here similar to storing in the 'this' object by writing window.<your variable> = <the value>. While it is really simple to use, it is generally discouraged as any function in will have access to the variable and can change it.

In my example I create my text in the component.js file of the parent app.

 

window.windowText = “Window”;

In the onInit function of my view controller in the child app, I declare a local json model and fetch the text and set it into the model

onInit: function(){
   var windowText = window.windowText,
   jsonModel = new JSONModel({
           windowText : windowText
  });

this.getView().setModel(jsonModel, "myModel");
},

In the view itself, it is bound like this

<Text text="{myModel>/windowText}"/>

 

Remember to deploy to see your changes.

A drawback of this, is that if you change the variable stored in the window object, it doesn’t change the binding in the child app, leaving you with a rather static option.

The next option is to use the EventBus which was used in the early days of SAPUI5 for navigation, but obviously routing has taken over here. However, it is still used occasionally for handling events.

The Eventbus works on a subsribe and publish basis. You need to declare the channel and the event you want to subscribe to, then use the same for when you want to publish data in the event.

In the onInit function of the child controller we add the following code to handle the event.

 

sap.ui.getCore().getEventBus().subscribe("exchange",
"data", function(channel, event, oEventData){
that.getView().byId("EventBusText").setText(oEventData);
}, this);

 

In the view itself we create a Text control with the id EventBusText.

 

<Text id="EventBusText"/>


I have added an input field in the parent app and in the change event of that field we use the following code to publish an event.

 

sap.ui.getCore().getEventBus().publish("exchange",
"data", oEvent.getParameter("newValue"));

 

That is it for the second example. This allows you to share data between the apps, so when you change in the parent app, you see it in the child.

mvVRy_Yk8b4IgDbiSYMEiZsJ9uueYm267T_DwoTF

The drawback here is that you need to unsubscribe to the events or at least only use the method subscribeOnce in the eventbus.

You can obviously also use a more model based approach and use a jsonModel that you store in the core of SAPUI5. This model can then be address in the child app by accessing the core.

We use the existing jsonModel used in the parent app. The following code adds the data to the json model and then save that into the core.

 

var oModel = this.getModel(),
oJsonData = {
MyNumber: 100000.1234,
MyText: "Hello World",
coreText: "Core",
propagateModelText: "propagateModelText"
};

oModel.setData(oJsonData);

sap.ui.getCore().setModel(oModel, "coreModel");

 

Now in the child apps onInit controller again we add the following:

 

var oData = sap.ui.getCore().getModel("coreModel").getData();

//Now merge the two objects and store it again to the child apps model
var newData = Object.assign(jsonModel.getData(), oData);
jsonModel.setData(newData);

In the view we add the Text to see the new change.

<Text text="{myModel>/coreText}"/>

 

The drawback here is now that your model is stored in the core and can again be accessed via other apps and you need to handle that accordingly.

Last and best option is to use the propogatedModel when we declare the componentContainer. As the documentation says; if you want to share data with the inner component, you can use property propagateModel on the ComponentContainer to forward models and binding contexts to the inner component.

So basically, we can forward our models from the parent app into the child app.

 

<core:ComponentContainer width="100%"
name="bourneMyChildApp"
component="bourneMyChildApp"
propagateModel="true"
    />

 

Back to the onInit controller again in the child app and add the following to the code. I’ve added the timeout here, because the component is initiated before the component container and because of the small footprint, the propogatedmodel isn’t added when we load this, but with the timeout that is fixed.

 

var that = this;
setTimeout(function(){
//Get the propogated model from the component. It is called undefined as we
// havent named the model in the parentApp
var oModel = that.getOwnerComponent()._getPropertiesToPropagate().oModels.undefined;
//Create a new model in the view called parentModel
       that.getView().setModel(oModel, "parentModel");
}, 1000)

 

This is the end result that you should get:

VeLkazvKrbwl29iYxWM-84sc_6Zco1wJaZt7UUv9

When you use the propogated model it is important to have a look at the lifecycle of the component container. Read the Using and Nesting Components

the reason for this is that once you initiate your child app inside the container and you then relaunch the app, then your child app is already initiated and will cause you problems. More on that in my next blog.

My next blog will be about how we can leverage the manifest.json file a bit more and thereby remove the jquery dependencies in the parent app component.js file that we wrote in the first blog. Also, I will show a little snippet on how you can handle component reuse once, that then will work both on premise and in the cloud.

You can find the source files here.

As always, please reach out to me on twitter on @uxkjaer

By Jakob Kjær

SAP Technical Architect