Reputation: 19425
I'm trying to understand Knockout JS. What bothers me is that the data I bind gets blanked out. It's annoying because I want to show the data I retrieve from the server.
An example:
Name: <span class="name"><?php echo $data->name; ?></span>
The result is: Name: John B
Now if I data-bind this with Knockout to this:
Name: <span data-bind="text: name" class="name"><?php echo $data->name; ?></span>
The result is: Name:
The JS will be something like:
var viewModel = {
name: ko.observable() // Initially blank <--- this is the culprit
};
ko.applyBindings(viewModel);
So what do I need to do in order to show / keep the data?
Can't Knockout somehow keep the data like Angular JS does?
Note I'm using Yii MVC framework to handle a lot of server side stuff. Using that to load data on page load, saves me from writing a lot of JS Ajax code. I wanted to use Knockout to reduce the amount of jQuery code I have, not add to it :)
Upvotes: 1
Views: 544
Reputation: 8053
Here are two workaround you can try to avoid declaring your data twice (note that they do not directly provide a way to keep your data in your html file) :
Create a php file with:
var defaultVm = {
name: '<?php echo $data->name; ?>',
anyVariable: '<?php echo $data->anyVariable; ?>'
}
Then you include this php file as a js file and init your viewmodel with it:
var viewModel = {
name: ko.observable(defaultVm.name);
anyVariable: ko.observable(defaultVm.anyVariable);
};
ko.applyBindings(viewModel);
Create a php file with:
{
"name": "<?php echo $data->name; ?>",
"anyVariable": "<?php echo $data->anyVariable; ?>"
}
Then in your js, you can use the ko.mapping plugin:
var viewModel = function (data) {
ko.mapping.fromJS(data, {}, this);
};
ko.applyBindings(new viewModel(getYourPhpFileTheWayYoulike));
This allows you to get your data asynchronously (if you want) with something like:
$.getJSON("yourphpmodelurl", function (data) {
ViewModelInstance = new viewModel(data);
ko.applyBindings(ViewModelInstance);
}
Upvotes: 2
Reputation: 3722
Another alternative is to construct your viewmodel supplying your value from the server directly into the observable.
<span data-bind="text: name"></span>
var viewModel = {
name: ko.observable(<?php echo $data->name; ?>);
};
ko.applyBindings();
Trying to initialise an observable's value from the HTML is dangerous as there are many ways that the observable's value will be reset, specifically if an element is contained within a parent binding that uses a explicit/implicit template, like an if
binding.
<div data-bind="if: someFlag">
<span data-bind="text: name">John Doe</span>
<div>
In the above example, everytime the someFlag
value changes from false to true, the text binding on the span element will be re-initialised.
Upvotes: 2
Reputation: 28737
You can create a custom binding handler to do this:
ko.bindingHandlers.textInitialized= {
init: function (element, valueAccessor) {
valueAccessor()(element.innerHTML); // get the current value and update the observable
},
update: function (element, valueAccessor) {
var value = valueAccessor();
element.innerHTML = ko.utils.unwrapObservable(value);
}
};
And then you can bind to your viewmodel like this:
Name: <span data-bind="textInitialized: name" class="name">John B</span>
EDIT after jsFiddle:
You have created a completely different thing in the jsFiddle. A few things:
element.value
instead of element.innerHTML
. I have modified the fiddle with these changes: http://jsfiddle.net/P8N77/24/
Upvotes: 1