Global values for Webix Jet application

I’m trying to add a modal to ask if you want to save unsaved changes when you try to navigate to another page.

I see there is an “app:guard” event, which is great, but I am wondering if there is a way to set a global flag.

I want to set a property on the JetApp instance from a view and use it in the “app:guard” event handler.

you can use some intermediate module to pass values between views

Where do you store values for a single view? Right now I am using a form and adding values to the form.

intermediate.ts
export const storage = {};
someview.ts
import {storage} from "intermediate";

export default class extends JetView {
    someMethod: ()=> {
        storage.someFlag = value;        
    }
}
otherview.ts
import {storage} from "intermediate";

export default class extends JetView {
    someMethod: ()=> {
        if(storage.someFlag == value) {
            ...
        }
    }
}

also you can use webix.storage.session to interchange data.
https://docs.webix.com/api__refs__storage.session.html

Thanks that works great!

In the app:guard event how do you stop navigation?

AFAIK you can return false or set confirm to reject obj.confirm = Promise.reject();

Returning false doesn’t work. The event handler takes function(url, view, nav). What is obj?

nav.confirm = Promise.reject(); seems to work.

How do you continue after you have stopped navigation? This is what I have now.

app.attachEvent("app:guard", function(url, view, nav){
  if (shared.storage.unsavedChanges){
    // Cancel navigation
    nav.confirm = Promise.reject();
    var unsavedModal = webix.ui({
      view: "window",
      height: 250,
      width: 300,
      left: 50,
      top: 50,
      move: true,
      head: "You have unsaved changes",
      body: {cols: [
        {view: "button", value: "Continue", click: function(){
          // nav.redirect = "/#!" + url;
          // nav.confirm = Promise.resolve();
          window.open("/#!" + url, "_self");
        }},
        {view: "button", value: "Cancel", click: function(){
          unsavedModal.hide();
        }},
      ]}
    });
    unsavedModal.show();
  }
});

Okay doing all three seems to be working.

nav.redirect = "/#!" + url;
nav.confirm = Promise.resolve();
window.open("/#!" + url, "_self");

@cody

app.attachEvent("app:guard", function (url, view, nav) {
    if (shared.storage.unsavedChanges) {
        // Cancel navigation
        nav.confirm = nav.confirm.then(function () {
            return new Promise(function (resolve, reject) {
                var unsavedModal = webix.ui({
                    view: "window",
                    height: 250,
                    width: 300,
                    left: 50,
                    top: 50,
                    move: true,
                    head: "You have unsaved changes",
                    body: {
                        cols: [
                            {
                                view: "button", value: "Continue", click: function () {
                                    // nav.redirect = "/#!" + url;
                                    // nav.confirm = Promise.resolve();
                                    //window.open("/#!" + url, "_self");
                                    unsavedModal.close();
                                    resolve(true);
                                }
                            },
                            {
                                view: "button", value: "Cancel", click: function () {
                                    unsavedModal.close();
                                    reject();
                                }
                            },
                        ]
                    }
                });
                unsavedModal.show();
            })
        })
    }
});

Seems to be generic functionality, how could we integrate this in a modular way in every form?

@mdissel

you can implement some view level service

export function saveGuardService(app, view, config) {
    view.on(app, "app:guard", function (url, view, nav) {
        if (view.getRoot().isDirty()) {
            nav.confirm = nav.confirm.then(function () {
                return new Promise(resolve, reject){
                    //show confirmation
                }
            })
        }
    })    
}
{
    init: function(){
        this.use(saveGuardService, {});
    }
}

Thanks, having storage in a model works. I tried to have a this.storage on the view but I couldn’t figure it out.

@integral Can you please extend the sample with the optimal way of showing a confirmation window?

@mdissel

return new Promise(resolve, reject){
    webix.confirm({
        title: "Close",
        text: "Data is unsaved!<br/>Do you want to continue?",
        type:"confirm-error",
        callback:function(result){
            if (result) resolve();
            else reject();
        }
    });
}