Building Apps with Webix Jet
Configuring app and views
Links
Docs
Big demos
Starter
Samples
Prerequisites
- nodeJS
- used for toolchain
- https://nodejs.org/en/
- yarn
- same as npm but a bit better
- https://yarnpkg.com/en/docs/install
First Start
clone the demo app
git clone https://github.com/webix-hub/jet-startinstall toolchain and start the app
cd jet-start
yarn install
yarn startopen app in the browser
http://localhost:8080cd jet-start
npm install
npm startTools
check code quality
yarn lintget files for deploy
yarn buildWebpack's Magic
- Automatic app updates
- Check console for build errors
npm run lintnpm run buildThe App!

Codebase
/sources/myapp.js
/ sources/views
/sources/models
/sources/locales
/sources/styles
- app's config
- UI chunks
- data and data related logic
- localization
- css, images, etc.
App Configuration
import {JetApp, EmptyRouter, HashRouter } from "webix-jet";
export default class MyApp extends JetApp{
constructor(config){
const defaults = {
id : APPNAME,
version : VERSION,
router : BUILD_AS_MODULE ? EmptyRouter : HashRouter,
debug : !PRODUCTION,
start : "/top/start"
};
super({ ...defaults, ...config });
}
}
if (!BUILD_AS_MODULE){
webix.ready(() => new MyApp().render() );
}- JetApp instance
- start point
- .render()
Views
some.com#!/top/start

Views
some.com/#!/top/start
some.com/#!/top/data
views
- top.js
- start.js
- data.js
- details
- form.js
- template.js
some.com/#!/top/details.form
some.com/#!/details.template
File structure
App URLs
models
Defining Views
export default {
template:"Start page"
};
import {JetView} from "webix-jet";
export default class TopView extends JetView {
config(){
return {
cols:[
{ view:"menu" },
{ template:"Something here"}
]
};
}
}/views/start.js
/views/top.js
Objects
Classes
Defining Views
import {JetView} from "webix-jet";
import {data} from "models/records";
export default class DataView extends JetView {
config(){
return { rows:[
{ view:"toolbar" },
{ view:"datatable", autoConfig:true }
]};
}
init(view){
view.queryView("datatable").parse(data);
}
}/views/data.js
Import modules
Why views are necessary
Composable blocks
Error resistant
Code reusage
Classes
Objects
VS
Simple
Lifetime handlers
Custom methods
Local variables
Extending
Brief
Classes: Providing Handlers
import {JetView} from "webix-jet";
import {data} from "models/menu";
export default class TopView extends JetView {
config(){
return {
cols:[
{ view:"menu" },
{ template:"Something here"}
]
};
}
init(view){
view.queryView("menu").parse(data);
}
}/views/top.js
- config
- init
- urlChange
- ready
- destroy
Classes: Extending
import Toolbar from "views/toolbar";
export default class Bottombar extends Toolbar {
init(view){
view.queryView("label").hide();
}
} import {JetView} from "webix-jet";
export default class Toolbar extends JetView {
config(){
return {
view:"toolbar", height:50, elements:[
{ view:"label", label:"My First App!"},
{ },
{ view:"button", autowidth:true, value:"Click me"}
]
};
}
}/views/toolbar.js
/views/bottombar.js
Classes: Methods and Properties
import {JetView} from "webix-jet";
export default class Toolbar extends JetView {
config(){
return {
view:"toolbar", height:50, elements:[
{ view:"button", autowidth:true, value:"Click me",
click:() => this.doClick("Clicked")
}
]
};
}
init(){
//custom properties
this._counter = 0;
}
//custom methods
doClick(message){
this._counter++;
webix.message(message+" "+this._counter);
}
}* this points to Toolbar class here
Classes: Access to App
import {JetView} from "webix-jet";
export default class Toolbar extends JetView {
config(){
return {
view:"toolbar", height:50, elements:[
{ view:"button", autowidth:true, value:"Show some",
click:() => this.app.show("/top/data");
}
]
};
}
}- this points to Toolbar class
- this.app points to app instance
- this.app.show renders UI according to the URL
Views - Composition
import {JetView} from "webix-jet";
export default class Toolbar extends JetView {
config(){
return { view:"toolbar", elements:[ ... ]};
}
} import Toolbar from "views/toolbar";
export default class TopView extends JetView {
config(){
return { rows:[
Toolbar,
{ cols:[
{ view:"menu" }, {}
]}
]};
}
}/views/toolbar.js
/views/top.js
Static subviews:Class or Object
Views - Composition
/views/toolbar.js
/views/top.js
Static subviews: Extra properties
import {JetView} from "webix-jet";
export default class Toolbar extends JetView {
config(){
return { view:"toolbar", elements:[ ... ]};
}
} import Toolbar from "views/toolbar";
export default class TopView extends JetView {
config(){
return { rows:[
{ $subview: Toolbar}, // id, name, etc.
{ cols:[
{ view:"menu" }, {}
]}
]};
}
}Views - Composition
/views/toolbar.js
/views/top.js
Static subviews: Extra Properties
import {JetView} from "webix-jet";
export default class Toolbar extends JetView {
config(){
return { view:"toolbar", elements:[ ... ]};
}
} export default class TopView extends JetView {
config(){
return { rows:[
{ $subview: "toolbar"}, // "views/toolbar" will be loaded
{ cols:[
{ view:"menu" }, {}
]}
]};
}
}Views - Composition
export default {
template:"Start page"
};
/views/start.js
/views/top.js
Dynamic subviews
/views/data.js
export default {
template:"Data page"
};
import Toolbar from "views/toolbar";
export default class TopView extends JetView {
config(){
return { rows:[
Toolbar,
{ cols:[
{ view:"menu" },
{ $subview:true}
]}
]};
}
}Views - Routing
export default {
template:"Start page"
};
/views/start.js
/views/top.js
some.com/#!/top/start
some.com/#!/top/data
export default {
template:"Data page"
};
/views/data.js
import Toolbar from "views/toolbar";
export default class TopView extends JetView {
config(){
return { rows:[
Toolbar,
{ cols:[
{ view:"menu" },
{ $subview:true}
]}
]};
}
}
Views - Routing
some.com/#!/top/data
some.com/#!/top/top/data
some.com/#!/data
some.com/#!/top




Windows and Popups
import {JetView} from "webix-jet";
export default class WindowsView extends JetView {
config(){
return {
view:"button", width:200, value:"Popup",
click:() => this._webixPopup.show()
}};
}
init(){
this._webixPopup = webix.ui({
view:"window"
});
}
destroy(){
this._webixPopup.close();
}
}Create with webix.ui()
- you need to destroy it!
Not recommended way
import {JetView} from "webix-jet";
import PopupView from "views/windows/popup";
export default class WindowsView extends JetView {
config(){
return {
view:"button", width:200, value:"Popup",
click:() => this._jetPopup.showWindow()
};
}
init(){
this._jetPopup = this.ui(PopupView);
}
}Windows and Popups
Create with JetView.ui()
Recommended way
Windows and Popups
import {JetView} from "webix-jet";
export default class PopupView extends JetView {
config(){
return { view:"window" };
}
showWindow() {
this.getRoot().show();
}
}/views/windows/popup.js
/views/toolbar.js
import {JetView} from "webix-jet";
import PopupView from "views/windows/popup";
export default class ToolbarView extends JetView {
config(){
return {
view:"button", width:200, value:"Show popup",
click:() => this._jetPopup.showWindow()
};
}
init(){
this._jetPopup = this.ui(PopupView);
}
}*JetView.getRoot() - access to a top Webix view within the module
JetView Constructor
/views/griddata.js
import {JetView} from "webix-jet";
import GridView from "views/gridview";
import data1 from "models/data1";
import data2 from "models/data2";
export default class GridData extends JetView {
config(){
return {
rows:[
//embed directly
new GridView(this.app,"", data1),
//or wrap in { $subview: }
{ $subview: new GridView(this.app,"", data2) }
]
}
}
}Re-use modules with
- similar configuration
- specific parameters
JetView Constructor
import {JetView} from "webix-jet";
export default class GridView extends JetView {
constructor(app, name, data){
super(app, name); //call parent constructor
this._gridData = data; //define specific parameters
}
config(){
//reuse config
return {
rows:[ toolbar, datatable ]
};
}
init(view) {
//parse specific data
view.queryView("datatable").parse(this._gridData);
}
}/views/gridview.js
Re-use modules with
- similar configuration
- specific parameters
Referencing Jet Views
export default class Toolbar extends JetView {
config(){
return {
view:"button", value:"Click me",
click:() => this.doClick("Clicked")
};
}
doClick(message){
webix.message(message);
}
} export default class Toolbar extends JetView {
config(){
return {
view:"button", value:"Click me", click:function(){
this.$scope.doClick("Clicked");
}
};
}
doClick(message){
webix.message(message);
}
}this
this.$scope
Referencing Jet Views
//views/toolbar.js
export default class Toolbar extends JetView {
config(){
return { view:"toolbar" };
}
init(){
console.log(this.getParentView());
}
} //views/top.js
import Toolbar from "views/toolbar";
export default class TopView extends JetView {
config(){
return { rows:[
{ $subview:Toolbar, name:"top-toolbar"}
]};
}
ready(view){
console.log(this.getSubView("top-toolbar"));
}
}.getParentView()
.getSubView()
Don't overuse these methods: module logic should be encapsulated!
Referencing Webix views
import Toolbar from "views/toolbar";
import Bottombar from "views/bottombar";
import {data} from "models/menu";
export default class TopView extends JetView {
config(){
return { rows:[
Toolbar,
{ cols:[
{ view:"menu", localId:"top:menu"} //or id:"top:menu"
]},
Bottombar
]};
}
init(view){
//searching for views
view.queryView("menu").parse(data);
view.queryView("button", "all").forEach((obj) => {
obj.hide();
});
//accessing particular view
this.$$("top:menu").parse(data);
}
doClick(){
// access to top Webix view within the module
this.getRoot()
}
}Configuring the App
import "./styles/app.less"; //! stylesheets
import "webix/appbutton"; //! custom widgets
import {JetApp, plugins, HashRouter } from "webix-jet";
export default class MyApp extends JetApp{
constructor(config){
const defaults = {
id : APPNAME, version : VERSION,
router : HashRouter,
debug : !PRODUCTION,
start : "/top/start"
};
super({ ...defaults, ...config });
}
}
webix.ready(() => {
if (webix.CustomScroll && !webix.env.touch) //! App-level Webix logic
webix.CustomScroll.init();
const app = new MyApp();
app.use(plugins.Locale); //! App-level Jet plugins
app.render();
- stylesheets
- custom widgets
Include:
Use:
- App-level Webix logic
- App-level Jet plugins
Error Handling
export default class MyApp extends JetApp{
constructor(config){
const defaults = {
id: APPNAME, version: VERSION,
start: "/top/start"
debug: true // console.log and debugger on error
};
super({ ...defaults, ...config });
}
}
const app = new MyApp();
app.render();
app.attachEvent("app:error:resolve", function(err, url) {
webix.delay(() => app.show("/top/start"));
});- app:error
- app:error:resolve
- app:error:render
- app:error:initview
Events:
Dev Guidelines
- include webix.js
- include debug:true to app config
- handle “app:error:resolve” event
- npm run lint before each commit
-
reuse similar views
-
don’t address views from other modules by ids
-
ensure that data is loaded before working with it
Safe developing
Wise developing
Links
Task for practice:
Demo:
Follow-up text: click here
3-1. Webix Jet. Intro
By ihelga
3-1. Webix Jet. Intro
Preparing the environment and configuring the app. Providing and composing UI chunks.
- 735