如何防止用户离开?

How to prevent user from navigating away?

在我的 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")
});

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

当我试图记住用户以将他的更改保存回服务器时出现问题。我基本上想中断导航以询问用户是否愿意 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?
        }
    }
});

我尝试过但不起作用的方法:

  1. evt.preventDefault();
  2. evt.stopPropagation();
  3. 抛出'something';

选项 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);
        }
    });
}

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

在 window 对象上尝试“onBeforeUnload”事件。

解决方案 #1:您可以使用路由器方法 stop and 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); 

解决方案 #2:中断路由本身使用 sap.ui.core.routing.HashChanger events. hashChanged and hashReplaced are internally used by Router. You could also try if sap.ui.core.routing.Router routeMatchedbeforeRouteMatched 是可取消的(文档没有给出任何提示)。

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

BR 克里斯

我刚刚解决了同样的问题,我发现有一个 API 可以解决这个问题。 然而,只有当应用程序在 Fiori Launchpad 中为 运行 时它才有效。

sap.ushell.Container.setDirtyFlag(bFlag);

这里bFlag是一个布尔值。如果是 true,用户将必须确认导航离开。将其设置为 false 以允许在没有此消息的情况下进行导航。

只要哈希值发生变化,导航就会中断,因此这包括

  • 在您的应用内路由
  • 更改浏览器地址栏中的哈希值
  • 在 Fiori Launchpad 中导航
  • 导航到另一个站点

来源:Implementing Data Loss Protection