I am spending hours trying to get a simple event call working correctly in my durandal/knockout app.
Context
I have a list of languages that that the user can select from a select-box:
<select class="form-control select2"
data-bind="event: { change: app.languageChanged }, options:languages,
optionsText:'label',
optionsValue:'code',
value:app.selectedLanguage"></select>
The property app.selectedLanguage is a ko.observable. I know that this works because the correct item gets pre-selected.
this.selectedLanguage = ko.observable(options.defaultLanguage);
I also have an event-handler which listens for changes on that select box, so that I can send a message to other parts of the application that need to be informed:
languageChanged : function(data, event) {
console.log(data);
console.log(event);
console.log(this.selectedLanguage());
app.trigger('language:change', this.selectedLanguage());
},
The problem
- the first parameter 'data' does not contain the selected item, but instead contains all items (actually, it seems to be the complete current view-model).
- If 1. does not work, then it would be an alternative to at least get hold of the new value from the observable 'selectedLanguage'. Unfortunately that always seems to have the old value. So whenever I change the selectbox option, I always get the previously selected value.
Question
So the question is: what could I be doing wrong? I am sure that this normally works correctly and I must be missing something somewhere.
I thought I had finally understood how knockout works, but now I have come across the next issue. I would be very grateful if someone could help me on this.
EDIT [SOLVED]
Thanks to xdumaine, here is the (nice and simple) solution:
In my html template, I removed the change-event:
<select class="form-control select2"
data-bind="options:languages,
optionsText:'label',
optionsValue:'code',
value:app.selectedLanguage"></select>
In my App view-model (that I require everywhere), I now subscribe to the ko.observable instead of listening to the event-handler:
define([ 'durandal/app', 'underscore', 'knockout', 'myapp/myapp' ], function(app, _, ko, myapp) {
"use strict";
function App(options) {
if (!(this instanceof App)) {
throw new TypeError("App constructor cannot be called as a function.");
}
this.options = options || {};
// Set the initial language.
this.selectedLanguage = ko.observable(options.defaultLanguage);
// *** Subscribes to the observable ***
this.selectedLanguage.subscribe(function(newValue) {
console.log(newValue);
app.trigger('language:change', newValue);
});
_.bindAll(this, 'getSelectedLanguage');
}
App.prototype = {
constructor : App,
getSelectedLanguage : function() {
return this.selectedLanguage();
}
}
return App;
});
This code has therefore been removed and is no longer needed:
languageChanged : function(data, event) {
console.log(data);
console.log(event);
console.log(this.selectedLanguage());
app.trigger('language:change', this.selectedLanguage());
},
Best regards, Michael
app
is in your code. Is that a durandal thing or is that your viewModel? – xdumaine