Tuesday, April 24, 2012

Knockout and Click-to-Edit

Knockout is lots of fun to work with.  It uses the MVVM pattern to drastically simplify javascript - you no longer have to mess around with finding elements and updating them or retrieving values from elements.  All you have to do is work with a viewmodel and the DOM is kept in sync automatically.  Here is a small example of one of the fun things I made with knockout recently.

I needed to implement click-to-edit for an element on a page that is bound to a Knockout viewmodel. The idea with click-to-edit is that you see text on a webpage, and when you click it, you are able to edit it, then when you click away, the edit box goes away.  You can see it in action on the Result tab below:



So what's going on here?  There isn't really that much code.  Here's the relevant HTML:

    <div data-bind="text: text, visible: !editingText(), click: textClick"><div>    
    <input data-bind="value: text, visible: editingText, hasfocus: editingText" type='text' class="span3"></input>


And this is the viewmodel:

var clickToEditViewModel function(text{
    var self this;

    self.editingText ko.observable(false);
    self.text ko.observable(text);
    self.textClick function({
        self.editingText(true);
    };
};

The text property on the viewmodel is where our actual data is stored.  Both the div and the input have their value bound to the text property, so knockout ensures that they always have the same value as each other.

The default value of editingText is false, so when knockout applies the bindings (seen in the javascript tab in the demo above), the div is visible and the input box is hidden because their visible properties are bound to !editingText() and editingText, respectively.

The div, being visible, can be clicked.  Its click event is bound to the textClick method on the viewmodel.  Here's where it gets fun.  When the div is clicked, the textClick method is run, which sets  editingText to true on the ViewModel.  This, in turn, hides the  div and displays the  input, because their visible properties are bound to  !editingText()  and editingText, respectively.  It also sets hasfocus on the input box to true, which causes the focus / cursor to be in the input box.

Next, as the user, you can change the value of the property by typing in the input box.  When you are done, click somewhere else on the page.  That's when the second interesting sequence of events occurs: when you click away from the input box, it loses focus.  Because the input's hasfocus property is bound to editingText, the input box losing focus causes editingText to be set to false.  This, in turn, causes the the div to be visible and the input box to be hidden because their visible properties are bound to  !editingText()  and editingText, respectively.

The click-to-edit behavior is primarily driven by the knockout bindings, so I don't have to go around hiding and showing elements - it just happens.

Have you done anything fun with Knockout before?  Let me know in the comments.

P.S.  Yes, I know you can also see this on the knockout documentation page for hasfocus, but I found it to be so interesting I thought it deserved its own post here.

No comments: