Day three is officially over. I got a little bit done tonight, but I was also watching a riveting Gerard Butler movie. Not the best way to be productive but I’ve also worked on another project at my actual job for about 6 hours today, so I’m not going to beat myself up over it too bad. Plus, the more I do, the longer I have to make these posts.
Today’s update is all about states and how I use the Knockoutjs visible data-bind to display a given ‘page’.
Managing States
As you can see, my components are appearing to load one at a time when the associated button is pressed. However, thanks to Knockoustj, there is only one server call to do all of this AND all the components are on the page at all times… sort of. Let’s look at the dashboard component template:
dashboard.html
<div class="ngts-panel ngts-sidebar ngts-content"> <div data-bind="component:{name:'dashboard-sidebar', params:states}"></div> <div> <div data-bind="visible:states.home"> <h2>Home</h2> </div> <div data-bind="visible:states.photos"> <div data-bind="component:'dashboard-photos'"></div> </div> <div data-bind="visible:states.albums"> <div data-bind="component:'dashboard-albums'"></div> </div> <div data-bind="visible:states.posts"> <div data-bind="component:'dashboard-posts'"></div> </div> </div> </div>
Using the visible data-bind, I can control which components are visible using a variable. If that variable evaluates to true, we show it. Otherwise, it’s hidden. This is also great for allowing a user to switch back forth between each ‘page’ and never lose their place or form data.
To handle the variables responsible for showing a page, I’m using a states object. It looks like this:
dashboard.js
self.states = {}; self.states.home = ko.observable(true); self.states.photos = ko.observable(false); self.states.albums = ko.observable(false); self.states.posts=ko.observable(false); self.states.currentState = ko.observable(self.states.home); self.states.changeState = function (state) { var currentState = self.states.currentState(); currentState(false); state(true); self.states.currentState(state); };
All of my states are defined as a knockout observable with a boolean value. My default state is home. I also have an object to keep track of the current state and a function that handles changing the current state.
What is an observable?
I’m glad you asked. Observables are what make the Knockoutjs world go round. Observables are designed to be updated and then tell everyone about it. So, if I want to update the state, I need the divs from dashboard.js to recheck the current state and act accordingly. There is also an observable array (ko.observableArray()) that we can use. It’s useful for binding a list of items to a select list and has other applications as well.
Because we can make our html elements change automatically, we have some real power with javascript and Knockoutjs.
State of the App
Now that we’ve defined the states of our dashboard, we need to be able to change them.
dashboard-sidebar.js
var koModel = function (params) { var self = this; self.title = "Dashboard Sidebar"; self.states = params; self.buttons = [ new link("Home","fas fa-home",self.states.home), new link("Photos", "fas fa-camera-retro", self.states.photos), new link("Albums", "fas fa-compact-disc", self.states.albums), new link("Posts", "far fa-comment-alt", self.states.posts) ]; function link (text, icon,state) { var self = this; self.text = text; self.icon = icon; self.state = state; return self; }; };
In my dashboard-sidebar component, I’ve established some buttons with some display info and assign each one of them a state. I’m also pulling the params object into a new states object. This is a way to share information between the main dashboard component and the dashboard-sidebar component.
dashboard-sidebar.html
<div> <h2 data-bind="text:title"></h2> <ul data-bind="foreach: buttons"> <li><button data-bind="click:function(){$component.states.changeState(state)}"><i data-bind="css:icon"></i><span data-bind="text:text"></span></button></li> </ul> </div>
I use the foreach binding to loop through my buttons and create an unordered list containing each one. Each button also has a click binding that calls the changeState function of the relative states object (pulled from the dashboard component). Because I assigned different states when creating the buttons, it automagically knows which state to change just by passing in the state variable.
Passing the states object
To make it all work, we just have to make sure we pass the states object from the dashboard component into the dashboard-sidebar component, like so:
dashboard.js
<div data-bind="component:{name:'dashboard-sidebar', params:states}">
The component binding syntax changes just a little bit, but as you can see, the states object is assigned to the params property. The easiest way to make sure objects are being passed is to simply console.log(params) in the component you’re trying to pass them to.
Done for the day
That’s about it for today. I’m looking forward to getting into some more CSS to make my sidebar look good. I plan on getting very carried away with it.