SAP / openui5

OpenUI5 lets you build enterprise-ready web applications, responsive to all devices, running on almost any browser of your choice.
http://openui5.org
Apache License 2.0
2.96k stars 1.24k forks source link

Async Module loading results in a warning, afterwards I am not able to retrieve i18n model anymore #2561

Closed cjohn001 closed 1 year ago

cjohn001 commented 5 years ago

OpenUI5 version: 1.65.4 and 1.67.1

Browser/version (+device/version): Chrome

sap-ui-core.js:166 2019-06-21 12:39:36.639860 Sync request triggered for 'sap/ui/layout/GridData.js' while async request was already pending. Loading a module twice might cause issues and should be avoided by fully migrating to async APIs. - sap.ui.ModuleSystem c @ sap-ui-core.js:166 L.warning @ sap-ui-core.js:158 warning @ sap-ui-core.js:170 requireModule @ sap-ui-core.js:94 requireSync @ sap-ui-core.js:105 H @ library-preload.js:832 J @ library-preload.js:832 I @ library-preload.js:832 l1 @ library-preload.js:832 s @ library-preload.js:823 l1 @ library-preload.js:832 s @ library-preload.js:823 K @ library-preload.js:832 J @ library-preload.js:832 I @ library-preload.js:832 l1 @ library-preload.js:832 s @ library-preload.js:823 l1 @ library-preload.js:832 s @ library-preload.js:823 K @ library-preload.js:832 J @ library-preload.js:832 I @ library-preload.js:832 l1 @ library-preload.js:832 s @ library-preload.js:823 l1 @ library-preload.js:832 s @ library-preload.js:823 K @ library-preload.js:832 J @ library-preload.js:832 I @ library-preload.js:832 l1 @ library-preload.js:832 s @ library-preload.js:823 K @ library-preload.js:832 J @ library-preload.js:832 I @ library-preload.js:832 l1 @ library-preload.js:832 s @ library-preload.js:823 K @ library-preload.js:832 J @ library-preload.js:832 I @ library-preload.js:832 l1 @ library-preload.js:832 s @ library-preload.js:823 K @ library-preload.js:832 J @ library-preload.js:832 (anonymous) @ library-preload.js:832 (anonymous) @ sap-ui-core.js:569 c @ sap-ui-core.js:564 S @ sap-ui-core.js:566 S.then @ sap-ui-core.js:569 F @ library-preload.js:832 G @ library-preload.js:832 h @ library-preload.js:832 X.parseTemplatePromise @ library-preload.js:831 k.onControllerConnected @ library-preload.js:1377 F @ library-preload.js:1326 r @ sap-ui-core.js:597 o.runAsOwner @ sap-ui-core.js:611 P @ library-preload.js:1326 (anonymous) @ library-preload.js:1326 Promise.then (async) e._initCompositeSupport @ library-preload.js:1326 (anonymous) @ sap-ui-core.js:327 constructor @ sap-ui-core.js:327 constructor @ sap-ui-core.js:958 constructor @ sap-ui-core.js:780 f @ sap-ui-core.js:549 f @ sap-ui-core.js:549 u @ library-preload.js:1350 v @ library-preload.js:1348 sap.ui.view @ library-preload.js:1347 c @ library-preload.js:1631 r @ sap-ui-core.js:597 o.runAsOwner @ sap-ui-core.js:611 _getObjectWithGlobalId @ library-preload.js:1631 _getViewWithGlobalId @ library-preload.js:1631 _getView @ library-preload.js:1590 _get @ library-preload.js:1589 _place @ library-preload.js:1630 _place @ library-preload.js:7599 _display @ library-preload.js:1630 _displaySingleTarget @ library-preload.js:1632 _displaySingleTarget @ library-preload.js:7600 (anonymous) @ library-preload.js:1632 _display @ library-preload.js:1632 _display @ library-preload.js:7600 _routeMatched @ library-preload.js:1629 (anonymous) @ library-preload.js:1471 execute @ library-preload.js:4374 dispatch @ library-preload.js:4377 dispatch @ library-preload.js:4376 parse @ library-preload.js:4384 parse @ library-preload.js:1493 fnHashChanged @ library-preload.js:1494 b.fireEvent @ sap-ui-core.js:314 R.fireHashChanged @ library-preload.js:1546 a._onHashChangedForRouterHashChanger @ library-preload.js:1425 b.fireEvent @ sap-ui-core.js:314 a.fireHashChanged @ library-preload.js:1421 execute @ library-preload.js:4374 dispatch @ library-preload.js:4377 dispatch @ library-preload.js:4376 (anonymous) @ library-preload.js:4364 setHash @ library-preload.js:4364 a.setHash @ library-preload.js:1431 a._setSubHash @ library-preload.js:1427 a._onHashModified @ library-preload.js:1426 b.fireEvent @ sap-ui-core.js:314 R.setHash @ library-preload.js:1551 navTo @ library-preload.js:1509 onAddCustomProduct @ SearchProduct.controller.js:133 b.fireEvent @ sap-ui-core.js:314 b.fireEvent @ sap-ui-core.js:981 (anonymous) @ sap-ui-core.js:465 d.ontap @ library-preload.js:868 b._handleEvent @ sap-ui-core.js:963 U._handleEvent @ sap-ui-core.js:1230 dispatch @ sap-ui-core.js:2136 g @ sap-ui-core.js:2155 r @ sap-ui-core.js:2155 dispatch @ sap-ui-core.js:2136 c3.handle @ sap-ui-core.js:2136 trigger @ sap-ui-core.js:2136 (anonymous) @ sap-ui-core.js:2136 each @ sap-ui-core.js:2125 each @ sap-ui-core.js:2125 trigger @ sap-ui-core.js:2136 P @ sap-ui-core.js:2155 V @ sap-ui-core.js:2155 dispatch @ sap-ui-core.js:2136 c3.handle @ sap-ui-core.js:2136 Show 98 more frames sap-ui-core.js:166 2019-06-21 12:39:36.687689 Repeated module execution skipped after async/sync conflict for sap/ui/layout/GridData.js - sap.ui.ModuleSystem

cjohn001 commented 5 years ago

The formatter tutorial under

https://openui5.hana.ondemand.com/#/topic/0f8626ed7b7542ffaa44601828db20de

should be adapted. When loading modules asynchronously it seems to be not guaranteed anymore, that one can load models via the view, i.e. var resourceBundle = this.getView().getModel("i18n").getResourceBundle();

Instead it only seems to be save to go via the component

var oResourceBundle = this.getOwnerComponent().getModel("i18n").getResourceBundle();

stephania87 commented 5 years ago

Please post URL to an example, or the view and the controller which can be used for recreating the case Thanks

cjohn001 commented 5 years ago

Hello Stephania, I cannot give you access to my sources. Like mentioned this seems to be a async runtime behavior topic. I will not start to construct examples that might run in this issue as this might heavily depend on the order and amount of data that are loaded in parallel. I think someone with a better understanding of the async behavior requirements of openui5 should investigate this.

stephania87 commented 5 years ago

As a minimum check what controls are loaded on the page and when you try to retrieve the i18n model. This may hint someone from the community what happens

In parallel, the question is forwarded to dev team via #1970280719

cjohn001 commented 5 years ago

Hello Stephania, you can now find an example under the following URL:

https://ecubed-solutions.ddnss.de/#/Input/AddCustomFood

The login credentials are user: sap password: sap

The relevant code section is given in line 50 of controller/BaseController.js

Please let me now as soon as I can take the example offline, as I would like to reuse it to show some other bugs to your colleagues.

Best regards, Christoph

domianer commented 5 years ago

Hi Christoph,

thank you for the example. However, I don't get such a logging when I run the code. I checked whether line 50 of controller/BaserController.js is passed, and it is.

Do I need to do something special to get the logging?

Thank you in advance and best, Dominik

cjohn001 commented 5 years ago

Hello Dominik, I yesterday removed the bug from the code, as I needed to showcase something different. I will reintroduce the bug till monday and give you feedback once included again

cjohn001 commented 5 years ago

Hello Dominik, the bug is back in. Best regards, Christoph

domianer commented 5 years ago

Hi Christoph, thank you. However, the application does not run properly: Uncaught (in promise) TypeError: Cannot read property 'getResourceBundle' of undefined. This is happening in line 51 of BaseController.js when trying to access the i18n model, which seems to be not existing.

Could you please have a look again? Maybe there went something wrong while reintroducing the bug ;-)

Best & thank you in advance, Dominik

codeworrior commented 5 years ago

Hi Dominik,

please check Christoph's 2nd comment. That's exactly one of the problems he reported as a consequence of switching to async.

I only took a short look into this issue some days ago, but from another issue I remember that manifest defined models are not waited for in case of async component instantiation. In theory, this could explain the issue, but it doesn't match Christoph's other observation that access via the owner component works. A difference between access via view and access via owner component suggests that this has something to do with the point in time.

From the failing code location and context, it becomes apparent that model propagation did not happen yet, but a formatter is called (during a setModel call in onInit). IMO this can happen easily as onInit is called when the view is ready but before it is attached to the control tree.

Could be a side effect of using the async View.create in the router. Before, the view was added hollow to the control tree before onInit was called, now it is only added after it has been fully initialized. If this proves to be true, then Christoph is right and this aspect needs to be mentioned in the documentation. In general, controllers should not rely on context (parent) data in their onInit. I'm quite sure this is already mentioned somewhere, but maybe it should be emphasized that it plays a bigger role again when switching to async loading.

cjohn001 commented 5 years ago

Hello Dominik and Frank, Frank is right, the behavior is exactly what I tried to show with the example. Hence, the app should not run :)

@codeworrior: Regarding your comments, I am not sure now, if I have fixed the bug with my solution or If I currently only do not see the next bug I am running into

If this proves to be true, then Christoph is right and this aspect needs to be mentioned in the documentation. In general, controllers should not rely on context (parent) data in their onInit

I am not sure what you mean with this and what your recommandation would be to deal with the issue. As a matter of principle, the translateText() method I am using is called when the view is setup to get the language translation. Hence, I need to have the i18n model in place at that point in time.

My bugfix is based on the documentation of oninit in the controller:

https://sapui5.hana.ondemand.com/#/api/sap.ui.core.mvc.Controller

From documentation:

Note: In component-based apps this.getOwnerComponent().getModel() should be used inside onInit() to get a model assigned to the component instead of using this.getView().getModel(). The latter call might return undefined because the view might not have been attached to a parent yet (i.e. the component), and thus the view can't inherit a model from that parent. You could also attach to the modelContextChange event. The event is fired when either the context or the model changes for the control.

I mean, the situation here is different, as the relevant translateText() function is called from the instantiation of the view and not from oninit(). Hence according to docs this should work. However, now back to your comment. Is my approach via getOwnerComponent() save? Alternatively, what would be the recommended approach?

Thanks for your help!

Best regards, Christoph

codeworrior commented 5 years ago

The documentation section that you mentioned exactly describes what I assume to be the problem in your (faulty) version: accessing the resource model from a view's onInit hook might fail as long as the view hasn't been added to the UI tree yet. Accessing the model via getOwnerComponent() should be safe (assuming the view has been crated via the router and therefore knows its owner).

cjohn001 commented 5 years ago

ok, then as far as I understand my assumption was correct, and the tutorial needs a polish. Thanks for clarification. Can I then take my example offline or might there be further need for it? Best regards, Christoph

devtomtom commented 1 year ago

Hi @cjohn001, We had a closer look at the tutorial again. The problem that you described in the issue does not affect the tutorial as it is written. Therefore, I am going to close the issue. However, as in your case, the situation can arise that models from the owner component have not yet been propagated to the view during the execution of the onInit hook (for the reasons already mentioned). The recommendation is therefore to access the models via the component via "getOwnerComponent().getModel()". We are currently in the process of updating the tutorial.