1. HashRouter
some.com/#!/top/data
2. UrlRouter
some.com/top/data
3. StoreRouter
4. EmptyRouter
default
import {JetApp, UrlRouter} from "webix-jet";
export default class MyApp extends JetApp{
constructor(config){
const defaults = {
router : UrlRouter,
start : "/top/start"
};
super({ ...defaults, ...config });
}
}
webix.ready(() => {
new JetApp().render();
});some.com/top/data
//webpack.config.js
module.exports = function(env) {
return {
...
devServer:{
historyApiFallback:{
index : "index.html"
}
}
};
}URL Router
Tune redirects on production server as well
export default {
template:'<a href="#!/top/data">Details</a>'
} export default {
template:'<a route="/top/data">Details</a>'
}HTML Links:
Jet Links:
<a> tag only
any HTML tag
//top.js
{
view:"button", click:() => this.show("./data")
}
//start.js
{
view:"button", click:() => this.show("../data")
}JetApp .show()
JetView .show()
{
view:"button", click:() => this.app.show("/top/data")
}
top.js
config(){
return { rows:[
toolbar,
{ cols:[
{ $subview:true, name:"left" },
{ $subview:true, name:"right" }
]}
]};
}
init(){
this.show("./settings", {target:"left"});
this.show("./data", {target:"right"});
}
One dynamic subview
Several dynamic subviews: target
config(){
return { rows:[
toolbar, { $subview:true }
]};
}
init(){
this.show("./data");
}
Independent
URL changes
const app = new JetApp({
start: "/top/start",
views: {
"hi" : "start",
"admin" :"settings"
}
});const app = new JetApp({
start: "/top/start",
routes:{
"/hi" : "/top/start",
"/admin" : "/top/settings"
}
});
#!/top/start
#!/top/hi
#!/hi
Both valid:
Redirects to:
class StartView extends JetView {
config () {
return { template:"Start page"};
}
}
class TopView extends JetView {
rows:[
{ $subview:true }
]
}
const app = new JetApp({
start: "/top/start",
views:{
top: TopView,
start:StartView
}
}); //views/start.js
export default class StartView extends JetView {
config(){
return {
rows:[
{ view:"button", click:() => {
this.show("../data?id=1");
}}
]
};
}
}); //views/data.js
export default class Dataview extends JetView {
config(){
...
}
urlChange(view){
const table = this.$$("table");
const id = this.getParam("id");
if (id && table.exists(id)){
table.select(id);
}
}
});Get and use
Pass to view
!#/top/data?id=1
//views/start.js
{ view:"button", click:() => {
this.show("../top?state=2/data?id=1");
}}
//views/data.js
urlChange(view){
console.log(this.getParam("id")); //1
console.log(this.getParam("state")); //undefined
console.log(this.getParam("state"), true); //2
}
Get parent param?
Yes!
Pass to view
!#/top?state=2/data?id=1
//views/top.js
urlChange(view){
console.log(this.getParam("state")); //2
console.log(this.getParam("id")); //undefined
}Get child param?
No!
//views/data.js
import {JetView} from "webix-jet";
export default class DataView extends JetView {
config(){ return {}; }
init(view, url){
const id = url[0].params.id;
}
urlChange(view, url){
const id = url[0].params.id;
}
}#!/top/data?id=1
[
{
page:"data",
params:{ id:1 },
index:2
}
]
#!/top?state=2/data?id=1
//views/top.js
import {JetView} from "webix-jet";
export default class DataView extends JetView {
config(){ return {}; }
urlChange(view, url){
const state = url[0].params.state;
const id = url[1].params.id;
}
}[
{
page:"top",
params:{ state:2 },
index:1
},
{
page:"data",
params:{ id:1 },
index:2
}
]
Child
params
jetView.getParam()
handler argument
export default class DataView extends JetView {
config(){
return {
view:"datatable", id:"table"
};
}
init(view){
this.on(this.app, "onDataEditStop", (data) => {
if(data){
this.$$("table").add(data);
});
}
}); export default class FormView extends JetView {
config(){
return { view:"form", elements:[
{ view:"text", label:"Title" },
{ view:"button", value:"Save", click:() => {
const data = this.getRoot().getValues();
this.app.callEvent("onDataEditStop", [data]);
}}
]};
}
});Dispatch event
Listen to event
export default class DataView extends JetView {
config(){
return {
view:"datatable", id:"table"
};
}
init(view){
this.on(view, "onAfterSelect", (id) => {
if(view.exists(id)){
//do something
}
});
}
});Listen to event
* only for views within one module
app.attachEvent("app:error", function(err){
alert("Error");
});
app.attachEvent("app:error:resolve", function(err, url) {
webix.delay(() => app.show("/some"));
});Bad events
Good events
app.attachEvent("app:render", function(view,url,result){
if (result.ui.view === "button")
result.ui.disabled = true;
});
app.attachEvent("app:route", function(url1, url2, ...){
if(url2)
webix.ajax(url2);
});
app.attachEvent("app:guard", function(url, view, nav){
if (url.indexOf("/admin") !== -1){
nav.redirect = "/top/start";
}
}); export default class DataView extends JetView {
config(){
return { rows:[
{ view:"button", value:"Add new", click:() => {
if(!this.app.getService("state").getState())
//show window with form
}
}
]};
}
}); export default class Toolbar extends JetView {
config(){
view:"toolbar", elements:[
{ view:"checkbox", label:"Readonly", on:{
onChange:(value) =>{
this.app.getService("state").setState(value);
}
}}
]
}
init(){
this.app.setService("state", {
getState:() => { return this.state; },
setState:(state) => { this.state = state; }
});
}
});Define service
Use service
//any view
{ view:"button", value:"Add new", click:() => {
if(!this.app.getService("state").getState())
//show window with form
}}
//helpers/state.js
export function State(app){
const service = {
getState(){
return this.state;
},
setState(state){
this.state = state;
},
state:0
};
app.setService("state", service);
}Define service
Use service
//myapp.js
import {state} from "helpers/state.js";
app.render();
app.use(state); //any view
{ view:"button", value:"Add new", click:() => {
if(!this.app.getService("state").getState())
//show window with form
}}
//helpers/state.js
export default class State {
constructor(app){
this.app = app;
this.state = 0;
}
getState(){
return this.state;
}
setState(state){
this.state = state;
}
}Define service
Use service
//myapp.js
import State from "helpers/state.js";
app.render();
app.setService("state", new State(app));Initialization
Data loading
Actions
Multiple receivers
State requests
Global helper
import {JetView, plugins} from "webix-jet";
export default class TopView extends JetView {
init(){
this.use(plugins.Menu, "top:menu");
}
}View-level plugins
App-level plugins
import {JetApp, plugins} from "webix-jet";
const app = new JetApp({ ... });
app.render();
app.use(plugins.Locale); import {JetView, plugins} from "webix-jet";
export default class TopView extends JetView {
config(){
return {
cols:[
{ view:"menu", id:"top:menu", data:[
{ id:"start", value:"Start page"},
{ id:"data", value:"Data page"}
]},
{}
]
}
}
init(){
this.use(plugins.Menu, "top:menu");
}
} //view.js
export default class SettingsView extends JetView {
config(){
const _ = this.app.getService("locale")._;
return {
rows:[
{ label:_("Language"), view:"segmented" }
]
};
}
}
//app.js
import {JetApp, plugins} from "webix-jet";
const app = new JetApp();
app.use(plugins.Locale);
app.render();
Enabled on app level
Used in each view
Demo:
Task for practice:
Follow-up text: click here