How to set ID of a XML-View in a component environment? - sapui5

I want to access a view's controller from a custom module with some utility functions. Basically you can do this that way:
var oController = sap.ui.getCore().byId("__xmlview1").getController();
The problem is that the above coding will not work in a real environment because __xmlview1is dynamically created by the framework. So I tried to find a possibility to set the ID of the view during instantiation. The problem is - I could not find one:
Trying to give the view an ID in the view.xml file does not work:
<mvc:View
controllerName="dividendgrowthtools.view.dividendcompare"
id="testID"
xmlns="sap.m"
...
Trying to set the ID in the router configuration of the component does not work either:
...
name: "Dividend Compare",
viewId: "test",
pattern: "Dividend-Compare",
target: "dividendcompare"
...
The problem is that I do not have direct control over the instantiation of the XML view - the component respectively the router does it.
So, is there a solution for that problem? Or at least a save way to get the view ID by providing the name of the view?

You should have a look at the SAPUI5 EventBus.
I am pretty sure, you want to let the controller to do something with the dividentcompare view. With the SAPUI5 Eventbus, you can publish actions from one controller to another witout braking MVC patterns.
In your dividendcompare.controller.js:
onInit : function() {
var oEventBus = sap.ui.getCore().getEventBus();
oEventBus.subscribe("MyChannel", "doStuff", this.handleDoStuff, this);
[...]
},
handleDoStuff : function (oEvent) {
var oView = this.getView();
[...]
}
Now, in your anothercontroller.controller.js:
onTriggerDividendStuff : function (oEvent){
var oEventBus = sap.ui.getCore().getEventBus();
oEventBus.publish("MyChannel", "doStuff", { [optional Params] });
}
You are now able to get the view from the dividentcontroller in every case from every other controller of your app. You dont access the view directly, this would brake MVC patterns, but can pass options to its controller and do the handling there.

Related

Passing Data Between Controllers While Navigating

I want to pass data between two controllers (in addition to routing parameters) and I would like to know the correct way to do this.
For example: when I navigate to pattern /order/{id}, I do this in the view controller:
this.getRouter().navTo("order", {
id: sOrderId
});
I want to pass additional JSON object which I don't want to be part of routing parameter.
What should I do in this case?
--edit
Wanted to add what I like to achieve with this
I want pass data from master to detail. Both master and detail page has individual routing patterns assigned. So user can land on master or detail directly. When they land on master - user can choose bunch of detail items, and navigate to first detail item, and from there navigate to other items he/she selected earlier on master. So what I want to pass is this selection from master controller to detail controller.
Note: If the intention is to pass selected keys from the main view to the detail view, see https://stackoverflow.com/a/48870579/5846045 instead.
Using a client-side model
Usually, data are stored separately in models instead of assigned to local variables and passing them around. Model data can be then shared with anything that can access the model (e.g. View for data binding).
Here is an example with a client-side model (JSONModel):
Create a JSONModel which is set on a parent ManagedObject. E.g. on the Component via manifest.json:
"sap.ui5": {
"models": {
"myModel": {
"type": "sap.ui.model.json.JSONModel"
}
}
}
In the controller A, set the object to pass before navigating:
const dataToPass = /*...*/
this.getOwnerComponent().getModel("myModel").setProperty("/data", dataToPass, null, true);
In the controller B, do something with the passed data. E.g. on patternMatched handler:
onInit: function() {
const orderRoute = this.getOwnerComponent().getRouter().getRoute("order");
orderRoute.attachPatternMatched(this.onPatternMatched, this);
},
onPatternMatched: function() {
/*Do something with:*/this.getOwnerComponent().getModel("myModel").getProperty("/data");
},
Using NavContainer(Child) events
There are several navigation-related events such as navigate,
BeforeHide, BeforeShow, etc. which contain both views - the source view (from) and the target view (to).
You can make use of the API data to pass the data.
Here is an example:
In the controller A:
onInit: function() {
this.getView().addEventDelegate({
onBeforeHide: function(event) {
const targetView = event.to;
const dataToPass = /*...*/
targetView.data("data", dataToPass);
}
}, this);
},
In the controller B:
onInit: function() {
this.getView().addEventDelegate({
onBeforeShow: function(event) {
/*Do something with:*/this.getView().data("data");
}
}, this);
},
See also the related documentation topic: Passing Data when Navigating
You can create a local model (usually a JSONModel) and set it to inside your app Component.
// inside Component.js
var model = new sap.ui.model.json.JSONModel({ foo: “bar”});
this.setModel(model);
Inside each controller you can use
var model = this.getOwnerComponent().getModel();
console.log(model.getProperty(“/foo”));

How can I set the owner component a view?

If I create a view and its controller in run time how can I connect it to a component while when I call getOwnerComponent it returns the component.
I can not found any setOwnerComponent for the controller or view.
You can do this by running the code that creates the new view inside a "runAsOwner" call:
var oView = oComponent.runAsOwner(function() {
return sap.ui.xmlview("myView", {
// view info
});
});
You can see more information about the runAsOwner function here. I have also made a small fiddle to demonstrate this: https://jsfiddle.net/93mx0yvt/21/.

Initializing input data

Where, and how do I clear out the input date on a view....
E.g. when the data is saved, and I access my page from the menu, the old data is still displayed in the input boxes.
I've tried the onInit() function but that only fires the first time into the view.
The navto call is in the BaseController which calls the defaultTimes page (view/controller).
onNavToDefaultTimes : function(oEvent) {
this.getRouter().navTo("defaultTimes");
}
My clear code was in the _onRouteMatched function of detaultTimes.....
_onRouteMatched : function(oEvent) {
var view = this.getView();
view.byId("shopInput").setValue("");
view.byId("effectiveDateFrom").setValue("");
view.byId("shop24Hrs").setSelected(false);
view.byId("shopClosed").setSelected(false);
},
The problem is though, _onRouteMatched is also callled from navBack of the page following default times. And I don't want to clear the fields in this case.
How do I implement the clear from the onNavToDefaultTimes function of the base Controller only?
Can you give an example.
Let's say the name of the view in which your input field is created is test.js, then whenever you are navigating to the view or navigating from the view, you can use invalidate view like below
sap.ui.getCore().byId("test").invalidate();
this makes the view to be rendered again when you are coming back to the view and onBeforeRendering() is triggered
You can choose one of the following options, and put one of them, after the code to save is executed:
Option 1:
var yourInput = this.getView().byId("yourInputID");
yourInput.setValue("");
Options 2 (Try someone):
var yourInput = this.getView().byId("yourInputID");
yourInput.unbindValue();
yourInput.unbindElement();
yourInput.unbindObject();
Or put the code in the following method, which is executed every time the view is displayed:
onAfterRendering: function(){
//Option choosed
}

Link to route without additional JS code

I'm a beginner to OpenUI5 and have written a menu like below:
view:
<NavigationList id="navigationList" width="12rem">
<NavigationListItem text="People" icon="sap-icon://card" select="goToRoute"></NavigationListItem>
</NavigationList>
controller:
goToRoute: function() {
this.getRouter().navTo("peoplelist");
}
That works, but it's bad, as I have a couple of menu items and JS events for each of them.
I wish I had something like this below, without any JS behind, but couldn't find anything in documentation and examples.
view:
<NavigationList id="navigationList" width="12rem">
<NavigationListItem text="People" icon="sap-icon://card" linkToRoute="peoplelist"></NavigationListItem>
</NavigationList>
Anyone knows?
You can build a generic event handler which derives the target route from the corresponding item. To achieve this you can make use of custom data which you can add to controls in a declarative way. For this add the following line to your opening View tag:
xmlns:custom="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1"
Adopt your navigation list:
<NavigationList id="navigationList" width="12rem">
<NavigationListItem text="People" icon="sap-icon://card" select="onItemSelect" custom:route="peopleList"/>
</NavigationList>
And your controller:
onItemSelect : function(event) {
var item = event.getSource();
var route = item.data("route");
this.getRouter().navTo(route);
}
Here you find further details.

How to get the reference to the another view control within some view?

ViewA created by "ViewA.view.js" is bound to a JSONModel. From within a view called ViewB, I would like to get the data in the JSONModel to which ViewA is bound.
How can I possibly get the reference to ViewA within "ViewB.view.js"?
You can do by using viewData property of a view.
Suppos you have a model : oModel in ViewA.
When you call a new view (ViewB) inside ViewA just do the followings.
var oViewB = sap.ui.view({
viewName: "myApp.ViewA",
type: sap.ui.core.mvc.ViewType.<type>,
viewData: oModel.getData()
});
inside ViewB's createContent:
createContent: function(oController) {
var oDataFromViewA = this.getViewData();
....
....
....
}
In general it's not a best practice to tightly couple views to share model data. A better approach is to use a global model which is available in all your views. You do this by calling sap.ui.getCore().setModel(modelInstance, modelName).