Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Giving initial value to observable from the HTML markup

Tags:

I'm trying to create an HtmlHelper extension that outputs some HTML to the view. In this HTML I'm wiring up some KnockoutJS binding. I'm new to KO so I'm still struggling in getting some things done. Anyway, what I'm trying to do is generate input fields (in the server-side code) bound to observables on my client-side code, then set the initial values of the observables through the value of the hidden fields. Unfortunately, that is not working for me. So I'm wondering if there any way I could get this done (even if I have to do it completely different).

Here's what I'm basically doing:

In my client side view model I have the following:

self.dataSource = ko.observable(); self.pageSize = ko.observable(); 

And my extension method outputs the following:

<input type="hidden" value="/Employee/Get" data-bind="value: dataSource" /> <input type="hidden" value="30" data-bind="value: pageSize" /> 

But when the page renders, when I inspect the elements I notice that the value of the input fields is being set to an empty string, which I believe is because of the way observables are being declared. But is there a way to override this behavior or something?

like image 711
Kassem Avatar asked Aug 25 '12 19:08

Kassem


People also ask

When to use observables?

Use A Observable An Observable is ideal for situations where the data changes during its lifetime. Real-time data from a WebSocket, for example. Think about dashboards, chat messages, notifications, video subtitles, sound visualizations. Or actions that are performed very often by a user.

How do you assign a value to observable knockout?

To create an observable, assign the ko. observable function to the variable. A default value can be specified in the constructor of the call. Knockout then converts your variable into a function and tracks when the value changes, in order to notify the UI elements associated with the variable.


1 Answers

A little late here. I wasn't actually satisfied with RP's answer, because it breaks the declarative nature of Knockout. Specifically, if you use valueWithInit to define your property, you can't use it in an earlier binding. Here's a fork of his jsfiddle to demonstrate.

You use it the same way, yet it's still document-wide declarative under the hood:

<input data-bind="valueWithInit: firstName" value="Joe" /> 

Extending on the idea, you can also use this to separate the initialization and the binding:

<input data-bind="initValue: lastName, value: lastName" value="Smith" /> 

This is a little redundant, but becomes useful when you're using a plugin instead of the built-in bindings:

<input data-bind="initValue: lastName, myPlugin: lastName" value="Smith" /> 

Expanding a little more, I also needed a way to initialize checkboxes:

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

And here are the handlers:

ko.bindingHandlers.initValue = {     init: function(element, valueAccessor) {         var value = valueAccessor();         if (!ko.isWriteableObservable(value)) {             throw new Error('Knockout "initValue" binding expects an observable.');         }         value(element.value);     } };  ko.bindingHandlers.initChecked = {     init: function(element, valueAccessor) {         var value = valueAccessor();         if (!ko.isWriteableObservable(value)) {             throw new Error('Knockout "initChecked" binding expects an observable.');         }         value(element.checked);     } };  ko.bindingHandlers.valueWithInit = {     init: function(element, valueAccessor, allBindings, data, context) {         ko.applyBindingsToNode(element, { initValue: valueAccessor() }, context);         ko.applyBindingsToNode(element, { value: valueAccessor() }, context);     } };  ko.bindingHandlers.checkedWithInit = {     init: function(element, valueAccessor, allBindings, data, context) {         ko.applyBindingsToNode(element, { initChecked: valueAccessor() }, context);         ko.applyBindingsToNode(element, { checked: valueAccessor() }, context);     } }; 

Notice valueWithInit simply uses initValue under the hood.

See it in action on jsfiddle.

like image 129
Joe Avatar answered Sep 21 '22 14:09

Joe