it:ad:knockout.js:howto:clientside_view_markup

IT:AD:Knockout:HowTo:ClientSide View Markup

Summary

One of the value propositions of Knockout is that the binding is elegantly done using markup, rather than a whole bunch of js/jquery wiring.

It works by publishing a JS ViewModel (initially embedded/rendered in the page, subsequently updated by JSON and or binding from form values), and then binding that to DOM elements.

Once you have control over the ViewModel's shape you can control the UI layout precisely, only having to work out:

  • rendering display/edit values to conditionally switch back and forth
  • client side validation
  • data postback
  • server server validation

Use html markup to bind the properties of UI elements back to the ViewModel properties.

Use the data-bind attribute, containing the current element's property (text, value, background-color, etc), a colon, then the ViewModel's property:

//Binding the span's text property to the model's first property:
<p>First name: <span data-bind="text:first"/> </p>

//Or an `input` element's `value` property:
<p>First name: <input data-bind="value:first"/></p>

Changing the input's value is updating the ViewModel property – but unless the ViewModel property is a ko.objservable, it's just a string, and cannot re-broadcast the chanages back to the UI.

<p>First name: <input data-bind="value:first"/></p>
<p>Result: <span data-bind="value:first"/></p>

bound to:

var viewModel {
   ...
   first:ko.observable("smith")
}

causes changes to the input value to update the model, which in turn immediately broadcasts/updates the the span… Nice.

The data-bind property is parsed…so using dot syntax to get sub properties of the target viewModel property is valid as well:

    <span data-bind="text:firstName.length"/>

As usual with HTML, checkboxes are different, and you don't work with value, but checked:

    <input type="checkbox" data-bind="checked:isRich"/>

Note that changes set the viewModel to true/false (I don't see anything handing tri-state values).

You use Checked-Binding with Radio buttons as well, but instead of binding to a boolean, you bind to a string, that ties back to the radio element's value:

<input type="radio" name="SOM" data-bind="checked:stateOfMind" value="sober"/>
<input type="radio" name="SOM" data-bind="checked:stateOfMind" value="drunk"/>

Binding back to:

var ViewModel {
  isRich:false
  stateOfMind:ko.observable("drunk")
}

Note:

  • It's so easy to get frustrated by not recognizing that you are not setting checked to a boolean, but a string that matches the value on the input element.

Binding-Modifiers: valueUpdate

The basic binding syntax is data-bind:"value:first", and that updates by watching the input element's change event. To get it to update on every keystroke, use valueUpdate modifier:

<input type="text" data-bind="value:firstName, valueUpdate: 'afterkeydown'" />

Binding Modifiers: enable & disable

Another aspect of IT:AD:Knockout.JS that is very useful is enabling form elements due to other conditions.

The following only enables the input box when the checkbox is checked:

<p>
  <input type='checkbox' data-bind="checked: hasCellphone" />
  I have a cellphone
</p>
<p>
  Your cellphone number:
  <input type='text' data-bind="value: cellphoneNumber, enable: hasCellphone" />
</p>
<script type="text/javascript">
  var viewModel = {
    hasCellphone : ko.observable(false),
    cellphoneNumber: ""
  };
</script>

Binding Modifiers: visible

**Hugely Useful**

You can hide/show hidden fields by binding the visible keyword:

 <callout icon="true" type="data-bind="visible:shouldShowXtraFields">
    <input type="text" data-bind="enable:shouldShowXtraFields" data-bind="value:someField"/">
 </callout>

Or simpler, using the if keyword:

 <callout icon="true" type="data-bind="if:shouldShowXtraFields">
    <input type="text" data-bind="value:someField"/">
 </callout>

See: Markup

An important difference between the two approaches is that `if` removes the elements from the page, whereas visible just makes them not appear.

Binding-Modifiers: isSelected

Can be used to set focus to an element (eg. If 'Have Motorcycle?' is selected, can set focus to 'Have Babe as well?').

See http://knockoutjs.com/documentation/hasfocus-binding.html

Binding to Select Options

Binding to Options using data-bind:options is specific to Options (not the same 'foreach' described below)

//Binding to a simple array:
<select data-bind="options:transportOptions"/>

//Binding to a complex array for text/value:
<select data-bind="options:transportOptions, optionsText: 'name', optionsValue:'id'"/>

//Binding to a complex array, with a dummy prefix option:
<select data-bind="options:transportOptions, optionsText: 'name', optionsValue:'id', optionsCaption:'Pick us a winner...'"  />


//Binding to a complex array, setting a value, with a dummy prefix option:
<select data-bind="options:transportOptions, optionsText: 'name', optionsValue:'id',value:transport, optionsCaption:'Pick us a winner...', "  />

* Ref:ko:options-binding

Binding to Multiple Select Options

Different binding (data-bind:options rather than data-bind:option)

Binding to Arrays: foreach

<ul data-bind='foreach:vehicleTypes'>
  <li><span data-bind="text:$data"/></li>       
</ul>

Binding to:

var viewModel {
   vehicleType: ko.observable(['skateboard','bike','hoverboard','car','jet-fighter'])
}

* See: Markup

Events: click-binding

Binding to data, and updating the ViewModel's properties is all nice, but there's a time for Action…. Good news: it's very easy.

You can call methods in the ViewModel using click binding:

<button data-bind="click: incrementClickCounter">Click me</button>

* See: Markup

Events: submit-binding

<form data-bind="submit: submitByAjax">
   ....
   <button type="submit"/>
</form>

Note:

  • It intercepts and cancel's the default postback
    • that's good, as you generally want the form to update the ViewModel, not postback and lose the page.
    • If you do want to continue with postback, make your eventHandler return true.
    • Why not use click? Because Submit responds to form-specific keyboard events that one would have to emulate if using click.

Examples:

//Text:
<input type="text" data-bind="value:firstName" />
//adding 'valueUpdate:afterkeydown' makes it pick up more than the default 'change':
<input type="text" data-bind="value:firstName, valueUpdate: 'afterkeydown'" />

//Password:
<input type="password" data-bind="value:password" />

//TextArea:
<textarea type="text" data-bind="value:lifeStory"></textarea>

//Checkbox (note use checked, not value):
<input type="checkbox" data-bind="checked:isRich" />

//Radio (note: all have same 'name', and bind to a string value, even though using 'checked' keyword):
<input type="checkbox" name="SOM" data-bind="checked:stateOfMind" value="Sober"/>
<input type="checkbox" name="SOM" data-bind="checked:stateOfMind" value="Drunk"/>

//Select Options (binding to a complex array, with a dummy prefix option):
<select data-bind="options:transportOptions, optionsText: 'name', optionsValue:'id', optionsCaption:'Pick us a winner...'"  />

* Ref:KO:Checked-Binding

var viewModel {
  var first:ko.observable('John'),
  var last:ko.observable('Smith'),

  this.fullName = ko.computed(function() {
    return this.firstName() + " " + this.lastName();    
  }, this);
}
Note:

N

ote that the term is ko.computed, not ko.observable
…and – as usual – watch out for 'this' (replace with self)

If you want to pass arguments, you have to do it an alternate way:

        model.computedMe2 = function (name) {
            return model.FirstName() + " " + model.LastName() + name
        }.bind(model);
Noice the bind...see: [http://jsfiddle.net/2pB9Y/41/](http://jsfiddle.net/2pB9Y/41/)

YOu can even have read/write Computed Propertes. See http://knockoutjs.com/documentation/computedObservables.html

  • /home/skysigal/public_html/data/pages/it/ad/knockout.js/howto/clientside_view_markup.txt
  • Last modified: 2023/11/04 01:48
  • by 127.0.0.1