Closed nzamani closed 6 years ago
IMHO, this is normal behaviour.
Any control (or ManagedObject) will return undefined for getModel()
until it either gets a model assigned (setModel(oModel)
) or when it has a parent and that parent has a model. Views in that sense are normal Controls. The MVC lifecycle in UI5 calls the onInit
hook immediately after the view (and its controller) has been created. At that point in time, the view has not been attached to any parent, so it can't inherit a model from that parent.
It is possible to provide a model to controls / views upon construction (the mSettings parameter accepts a property models
), but the Router seems not to make use of it (nor does the configuration-based root view creation for UIComponents).
I can't argue why this is not the case, but please note that the two access paths that you mentioned for the model might not always return the same model (although they do in most straight forward apps): If a view is created as a subview of another view and if the place, where the subview is placed at, got a different model, then this.getView().getModel()
will be different from this.getOwnerComponent().getModel()
. So maybe the Router just wanted to leave it up to the standard control hierarchy to propagate the model. This is also consistent with "common practice" code for creating views (oSomeParent.addContent(sap.ui.view(...)
).
The other access path this.getOwnerComponent().getModel(
)is not based on the parent relationship but on the creation context. That context is defined earlier, e.g. during the call to 'UIComponent.createContent()
or while a View is created by the Router.
For sure, all this only can explain why it is like it is, not whether it should be like that ;-)
So currently (and in the scenario above), this means that as a developer I have to know that I mustn't use this.getView().getModel()
directly in onInit()
. Instead, I have to use this.getOwnerComponent().getModel()
. At the same time, anywhere else in the controller I'm allowed to use this.getView().getModel()
. I'm not very sure if this is very intuitive, a least it can be confusing.
Think of the following scenario:
You have a SplitApp with separate XMLViews/Controllers for master and detail page. In onInit() of the master page you want to listen for the metadataLoaded event (well, by using a promise...). Now, you're using the BaseController approach for all your Controllers. In the BaseController you have some easy to reuse methods, i.e. getModel(sName)
, which can be reused in the "sub" Controllers (see https://github.com/SAP/openui5/blob/master/src/sap.m/test/sap/m/demokit/tutorial/worklist/07/webapp/controller/BaseController.js#L16-L24). Of course, it's very tempting to call this.getModel().metadataLoaded().then(...)
in the sub controllers, even inside onInit()
. However, this will exactly lead to the issue described above. That's how I got tricked, in the debugger I could see then that the model is propagated after the onInit()
has finished and I understood... This also means to me that I should add a comment to getModel()
inside the BaseController, maybe something like this (to make sure nobody gets tricked):
Never use this method directly inside onInit() of your controller. Instead use this.getOwnerComponent().getModel() or call this method in a route matched handler which is typically registered in onInit(). Everywhere else in the sub controller this.getModel() can be used :-)
:laughing:
Well, that's a little weird :innocent:
Now I even wonder if it's just some luck that inside the route matched handlers this.getView().getModel()
works just fine - luckily, there the model propagation has already finished :blush:
Ok, well, how to proceed here now? I don't think the current behavior can be changed. If I got it right, when onInit is called, it's simply not known yet where in the UI the View will end up, so the result of getModel cannot be known.
What we should do of course is: documenting this clearly (where onInit is described).
Would that be ok with you, Nabi?
Cheers Andreas
Thank you for getting back... Yes, that would be ok I guess.
:-(
I have just lost one hour trying to figure it out.
Also, by the time it seems there is no documentation available on onInit of the Controller class nor inside Web IDE templates.
IMHO is very bad not to be allowed to use such method inside onInit (althought I have understood why that). Router handlers seem to be the best alternative for that.
One more reason to open source UI5 documentation as well.
@Shtilianova Why is this closed? What has been done to improve the documentation? Is there a link to it?
@boghyon , I closed it by mistake, thank you for the note. I've created a internal incident 1770244517. You can check its status on GitHub. Regards,
It's 2018 now, and last I checked, this documentation is still not done. onInit 😞
Like I said before,
One more reason to open source UI5 documentation as well.
@fabiopagoti actually, the API docs part of the demo kit is pretty much open source, too. I've just created a simple pull request that shall help improving the API docs and finally closing this issue. Feel free to add own improvements for the API documentation.
I'm sure sooner or later the other parts of the demo kit will become "open source" as well (i.e. the tutorials etc.). Most probably there is a challenge with the tooling that generates the whole demo kit. I guess that's also the reason why the "whole" demo kit is not part of this GitHub repository. For the time being, we can create pull requests for API docs or we can create issues asking SAP for improving other parts of the demo kit.
@akudev @codeworrior Would it be appropriate, also in terms of compatibility, to just return Component's model in such cases? Something like this in sap.ui.core.mvc.View
:
View.prototype.getModel = function(sName) {
var oModel = Control.prototype.getModel.apply(this, arguments);
if (oModel) {
return oModel;
}
var oController = this.getController();
if (!this.getParent() && oController && oController.getOwnerComponent()) {
return oController.getOwnerComponent().getModel(sName);
}
}
It does seem to confound quite a lot of people that this.getView().getModel()
doesn't return anything in onInit
. Getting the component model there would make developing UI5 apps a bit more intuitive I think.
Not sure... not every view is the root view of a component. And when it is not, any parent control/view can have a model which overrides the component model. This would mean that you do get the component model in onInit, but a different model later, once the view is in the UI tree. Sounds confusing to me (even though it might not happen in most straightforward cases).
@fabiopagoti actually, the API docs part of the demo kit is pretty much open source, too. I've just created a simple pull request that shall help improving the API docs and finally closing this issue. Feel free to add own improvements for the API documentation.
I'm sure sooner or later the other parts of the demo kit will become "open source" as well (i.e. the tutorials etc.). Most probably there is a challenge with the tooling that generates the whole demo kit. I guess that's also the reason why the "whole" demo kit is not part of this GitHub repository. For the time being, we can create pull requests for API docs or we can create issues asking SAP for improving other parts of the demo kit.
Finally!!
https://blogs.sap.com/2019/07/18/openui5-developer-guide-have-your-say/
Thanks a lot for the effort guys!
SAPUI Version: 1.30.0, 1.30.11, 1.32.0, 1.32.9, 1.34.2 Browsers: all Defect: Calling
this.getView().getModel()
inonInit()
to get the default model in any controller of a component based app returns undefined. Expected:this.getView().getModel()
should return the default model (v2.ODataModel) as instantiated via app descriptor. In other words:this.getView().getModel()
should have the same result as callingthis.getOwnerComponent().getModel()
inonInit()
To reproduce you can simply use any of the tutorials, i.e. the Walkthrough, Navigation& Routing, or any other tutorial. Let's try it with the Worklist tutorial:
onInit()
of the controller, i.e. via Chrome dev toolsthis.getOwnerComponent().getModel()
==> returns the modelthis.getView().getModel()
==> undefinedAs you can see, while the model is already on the component it is not visible in the onInit() of the controller.
Also, try the following in the
onInit()
while you are in the debugger (just execute in console):Then, after the
onInit()
has finished call on the console:This shows that the model is visible somewhen later, after
onInit()
has finished. So it seems there is a timing problem (the model is propagated too late). In the route matched handlersthis.getView().getModel();
works just fine.Hint: This issue is not a bug of the Worklist tutorial or of any other tutorial. I'm not sure if this is expected behavior or not. It feels confusing somehow and I did not find anything documenting this.