如何防止用户导航离开?

Ale*_*rtz 5 url-routing sapui5

在我的 SAPUI5 应用程序中,我使用 sap.tnt.Toolpage 作为主布局容器。SideNavigation 显示应用程序链接列表,并且 mainContents 使用 sap.ui.core.routing.Router 动态加载。

导航到我正在使用的详细信息页面

var router = sap.ui.core.UIComponent.getRouterFor(this);
router.navTo("MyDetailRoute", {
    detailItemId: oItem.getBindingContext("oDataSourceName").getProperty("DETAILID")
});
Run Code Online (Sandbox Code Playgroud)

这将加载一个详细信息视图,然后将其控件绑定到我的数据源中的数据。

当我试图记住用户将他的更改保存回服务器时,问题就出现了。我基本上想中断导航以询问用户是否愿意 a) 取消他的更改,b) 保存他的更改或 c) 留在详细信息页面上。虽然 a) 和 b) 很容易实现,但我不知道如何防止导航发生。

到目前为止,我已经通过订阅 onBeforeHide 来尝试我的观点:

var view = this.getView();
var that = this;
view.addEventDelegate({
    onBeforeHide: function (evt) {
        var oModel = that.getModel("oDataSourceName");
        if (oModel.hasPendingChanges()) {
            // How to prevent leaving the page?
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

我尝试过但不起作用的事情:

  1. evt.preventDefault();
  2. evt.stopPropagation();
  3. 扔“东西”;

选项 3) 实际上会阻止导航,但会导致以后出现问题,因为 URL 仍然会更改...

有没有人有想法?

编辑:多亏了 cschuff 的回答,我才能让它工作。对于将来遇到同样问题的任何人:

// In onInit: Subscribe to onBeforeHide in order to un-register event handler for hashchange

onInit: function () {        
    this.getRouter().getRoute("MyDetailRoute").attachPatternMatched(this.onNavigated, this);

    var view = this.getView();
    var that = this;

    view.addEventDelegate({
        onBeforeHide: function (evt) {
            $(window).off('hashchange');
        }
    });
}


// Then in onNavigate stoppen the router, saving the current window location and subscribing to hashchange (only once)
// In hashchange use helper variable m_bSelfURLSetting to prevent the function from running when triggered by URL restore (above)
// In the handler checking for pending changes and either resore the old URL or starting the router again if the user wants to quit or if there are no changes

onNavigated: function (oEvent) {            

    this.getRouter().stop();
    this.m_strHref = window.location.href;
    var that = this;

    $(window).off('hashchange').on('hashchange', function (e) {
        if (that.m_bSelfURLSetting) {
            that.m_bSelfURLSetting = false;
            return;
        }

        var oModel = that.getModel("oDataSourceName");
        if (oModel.hasPendingChanges()) {
            var leave = confirm('There are unsaved changes.\r\n\r\nDo you really want to leave the page?');
            if (!leave) {
                // re-set the URL
                that.m_bSelfURLSetting = true;
                window.location.href = that.m_strHref;
            }
            else {
                that.getRouter().initialize(false); 
                oModel.resetChanges();
            }
        } else {
            that.getRouter().initialize(false);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

这绝对不是人们引以为豪的那种代码......

csc*_*uff 5

解决方案 #1:您可以使用 Router 方法stop和来暂时完全停用路由initialize。这将停止侦听 url 哈希中的更改,从而忽略所有路由触发器。

从您的控制器:

var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.stop();

// later
// passing true will interpret and navigate to the current hash (since 1.48.0)
oRouter.initialize(true); 
Run Code Online (Sandbox Code Playgroud)

解决方案#2:使用sap.ui.core.routing.HashChanger事件中断路由本身。hashChanged并由hashReplacedRouter 内部使用。您也可以尝试是否可以取消(文档没有给出任何提示)。sap.ui.core.routing.Router routeMatchedbeforeRouteMatched

解决方案#3:限制较少的解决方案是中断从该特定视图触发路由的所有操作。请注意,浏览器返回或手动更改 url-hash 在这里仍然有效(本机 JS 事件beforeunload可能hashchange会有所帮助)。

克里斯先生