There is an almost unlimited amount of useful or interesting controls you could create with jide.js. This time, we’ll create a page layout that has a collapsible sidebar. This type of control is extremely common for mobile applications, where screen space is a limited resource.
As always, you can find the finished control in my jidejs-extra repository.
Now let’s get to work.
What do we need?
This is the very first question you should ask yourself when creating a new control. What kind of properties does it need? How much does the view model (a.k.a. the Skin) need to do? For this control, we need the following:
- content: The content of the page
- sidebar: The sidebar that should be shown
- title: A title that should be shown at the top of the page
Our Skin will probably need to know the width of the sidebar (to transform the content position) and it should know whether or not the sidebar should be visible.
The Control and its Skin
[cc lang=”javascript”]define([
‘jidejs-extra/Class’,
‘jidejs/base/Observable’,
‘jidejs/base/DOM’,
‘jidejs/ui/Control’,
‘jidejs/ui/Skin’,
‘text!./SidebarPage.html’
], function(
Class, Observable, DOM,
Control, Skin,
SidebarPageTemplate
) {
var Property = Class.Property;
var SidebarPage = Class({ // we’re using jidejs-extra/Class
$extends: Control,
$init: function(config) {
Control.call(this, config || {});
this.classList.add(‘jide-extra-sidebar-page’);
},
sidebar: Property,
content: Property,
title: Property
});
SidebarPage.Skin = Skin.create(Skin, {
template: SidebarPageTemplate,
isSidebarVisibleProperty: false,
install: function() {
// store the toggled state here so we can use it in the template
this.isSidebarVisibleProperty = Observable(false);
Skin.prototype.install.call(this);
},
get sidebarWidth() { // calculate the offset of the content
return this.isSidebarVisible ? DOM.measure(this[‘x-sidebar’]).width : 0;
},
// just to make the template more readable, it’d have been shorter to use .get() but anyway…
get isSidebarVisible() {
return this.isSidebarVisibleProperty.get();
},
set isSidebarVisible(value) {
this.isSidebarVisibleProperty.set(value);
},
toggleSidebarVisibility: function() {
this.isSidebarVisible = !this.isSidebarVisible;
}
});
return SidebarPage;
});[/cc]
The above code is quite simple. If you’ve got any questions, just leave a comment and I’ll clearify.
The Template
[cc lang=”xml”]
[/cc]
Okay, so this is slightly more complicated. As you can see, we’re using an inline SVG icon for the toggle “button” as well as a couple of binding expressions.
The advantage of using binding expressions is that they update automatically whenever a property that they rely on is changed. So, when we use the Skins sidebarWidth
property with a style
binding, the styles will be updated whenever the sidebarWidth
property changes. Since sidebarWidth
uses the isSidebarVisible
property, it will be updated whenver the sidebars visibility is toggled.
The CSS/LESS
[cc lang=”css”]html, body {
margin: 0;
padding: 0;
}
.jide-extra-sidebar-page {
width: 100%;
& > .x-sidebar {
position: absolute;
top: 0;
left: 0;
height: 100%;
#padding > .large();
.box-shadow(inset -1.5em 0 1.5em -0.75em rgba(0, 0, 0, 0.25));
&.is-visible {
.transform(translate3d(0%, 0, 0));
}
.transform(translate3d(-100%, 0, 0));
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
-o-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transition: -webkit-transform 500ms ease;
-moz-transition: -moz-transform 500ms ease;
-o-transition: -o-transform 500ms ease;
transition: transform 500ms ease;
}
& > .x-main {
-webkit-transition: -webkit-transform 500ms ease;
-moz-transition: -moz-transform 500ms ease;
-o-transition: -o-transform 500ms ease;
transition: transform 500ms ease;
& > .x-header {
width: 100%;
#padding > .large();
& > .x-toggle, & > h1 {
vertical-align: middle;
display: inline-block;
margin: 0 (@unit*2);
}
}
& > .x-content {
#padding > .large();
}
}
& > .x-sidebar, & > .x-main > .x-header {
#background > #solid > .inverse();
}
& > .x-main > .x-header > .x-toggle {
& > circle, & > rect {
fill: @button-text;
}
&:hover {
& > circle, & > rect {
fill: fade(@button-text, 75%);
}
}
}
}[/cc]
Okay. That’s a lot of styling but it’s not that bad, right? We use a transition on the transform property to create an animation and we use the transform property to move the sidebar off-screen and back when we don’t need it.
Putting it all together
Now let’s create a simple example application using this new control.
[cc lang=”javascript”]require([
‘jidejs/ui/control/Label’,
‘jidejs-extra/control/SidebarPage’
], function(Label, SidebarPage) {
document.body.appendChild(new SidebarPage({
sidebar: new Label({ text: ‘Sidebar’ }),
content: new Label({ text: ‘Content’ }),
title: ‘Sidebar Page Demo’
}).element);
});[/cc]
Note that since we’ve used the content
binding in our template, the value of each of the properties (sidebar
, content
and title
) could be either a string, jide.js control or HTML element. I’ve chosen to use a label here, but it’d of course make more sense to create a navigation control and bind it’s currently active page to the content. The Yeoman Quickstart contains an example of how to do something like that. Don’t forgot to add custom styling to your ListView, though.