Reputation: 87
So I've got a section that updates based on a ko.observable
called toClicked
, see below:
<div id="longInfoWindow">
<div id="longInfo_goBack"><span class="fa fa-arrow-left"></span> Go Back</div>
<div id="location_mainInfo">
<h1 id="location_title" data-bind="text: toClicked.title">Title</h1>
<h2 id="location_address" data-bind="text: toClicked.address">Address</h2>
<h6 class="location_latlng">LAT: <span data-bind="text: toClicked.lat">LATITUDE</span></h6>
<h6 class="location_latlng">LNG: <span data-bind="text: toClicked.lng">LONGITUDE</span></h6>
<p id="location_description" data-bind="text: toClicked.content">
Empty
</p>
</div>
</div>
toClicked
is data-bound via a for-each
ul
that passes in bits of information from an observableArray
, so this data is constantly changing - here's what the click function looks like in the viewmodel.
var viewModel = {
// Nav open and close via knockoutjs
self : this,
userQuery : ko.observable(''),
toClicked : ko.observable({}),
logClick : function(clicked){
var toClicked = ko.observable({});
toClicked().title = clicked.title;
toClicked().lat = clicked.lat;
toClicked().lng = clicked.lng;
toClicked().placeID = clicked.placeID;
toClicked().address = clicked.address;
toClicked().content = clicked.content;
return toClicked();
}
};
// at the end of the document...
ko.applyBindings(viewModel);
For some reason, I can call any toClicked
parameter, like toClicked.title
, and I get the proper output. But I can't get anything to bind in the longInfoWindow
bit of code, it removes the filler text with empty strings. Is there something I'm missing here with Knockout that's keeping it from updating appropriately?
As a side note, I've tried setting the databinds to viewModel.toClicked.title
with no joy. Have also tried $root
, $parent
. either comes back as not defined or gives the same result.
Upvotes: 0
Views: 47
Reputation: 343
The more obvious way without having to use valueHasMutated would be to assign directly to the observable:
self.logClick = function(clicked) {
self.toClicked({
lat: clicked[0].lat,
lng: clicked[0].lng,
placeID: clicked[0].placeID,
adress: clicked[0].address,
content: clicked[0].content
});
};
You normally do not need to use valueHasMutated when using knockout. Also there is no need to return the observable from the click handler. In your bindings you need then to access the properties as already stated like this:
<h1 id="location_title" data-bind="text: toClicked().title">Title</h1>
Knockout will automatically update the heading, whenever toClicked changed.
Upvotes: 0
Reputation: 14561
You need to change the way toClicked
is accessed. Given that it is an observable, it must access the properties using syntax like toClicked().property
. Another problem is that you should specify toClicked
as an object, before setting properties on it.
Also, since clicked
is an array, it should be accessed by index, like clicked[0].title
.
Note the use of self.toClicked.valueHasMutated();
in function logClick
. It tells the view model that observable variable toClicked
has some non-observable properties that might have changed. As a result the view model is updated. You should avoid using it excessively.
var viewModel = function() {
// Nav open and close via knockoutjs
var self = this;
self.test = ko.observable('text');
self.userQuery = ko.observable('');
self.toClicked = ko.observable({});
self.markers = ko.observableArray([
{ title: 'Eagle River Airport', lat: 45.934099, lng: -89.261834, placeID: 'ChIJdSZITVA2VE0RDqqRxn-Kjgw', content: 'This is the Eagle River Airport. Visit us for fly-ins!' }
]);
self.logClick = function(clicked) {
// var toClicked = ko.observable({});
self.toClicked().title = clicked[0].title;
self.toClicked().lat = clicked[0].lat;
self.toClicked().lng = clicked[0].lng;
self.toClicked().placeID = clicked[0].placeID;
self.toClicked().address = clicked[0].address;
self.toClicked().content = clicked[0].content;
self.toClicked.valueHasMutated();
return self.toClicked();
};
};
// at the end of the document...
var vm = new viewModel();
ko.applyBindings(vm);
var markers = vm.markers();
vm.logClick(markers);
Your view model must also change slightly. Note the ()
brackets after toClicked
, they are used to access the properties of an observable.
<div id="longInfoWindow">
<div id="longInfo_goBack"><span class="fa fa-arrow-left"></span> Go Back</div>
<div id="location_mainInfo">
<h1 id="location_title" data-bind="text: toClicked().title">Title</h1>
<h2 id="location_address" data-bind="text: toClicked().address">Address</h2>
<h6 class="location_latlng">LAT: <span data-bind="text: toClicked().lat">LATITUDE</span></h6>
<h6 class="location_latlng">LNG: <span data-bind="text: toClicked().lng">LONGITUDE</span></h6>
<p id="location_description" data-bind="text: toClicked().content">
Empty
</p>
</div>
I'd also suggest that instead of accessing toClicked
directly within logClick
you use something like self.toClicked
to avoid ambiguity. See this.
Here's the working fiddle: https://jsfiddle.net/Nisarg0/hx0q6tt6/13/
Upvotes: 1