I'm new in knockout and I'm having problems using observables in modules loaded with requirejs.
The code is very simple and it was working using a viewmodel declared in the html. When I load the viewmodel using require, the observables variables behaves like a function, so I have to use parentheses to access the variable. But when I try to change the value using an input nothings happen. Also when I add values to the observable array from a callback funcion, the UI doesn't update.
There is a way to load the module and keep using the varibles without the parentheses?.
I tryed using a constructor function and a shared object instance but the issue remains.
index.html
<div data-bind="component: 'cmp'"></div>
<script>
(document).ready(function () {
ko.components.register('cmp', {require: '../Models/cmp'});
ko.applyBindings();
});
<script>
/Models/cmp.js
define(['knockout-3.4.0'], function (ko) {
function MyComponentViewModel(params) {
self = this;
self.firstName = ko.observable("John");
self.lastName = ko.observable("Doe");
self.sel = ko.observableArray(['France', 'Germany', 'Spain']);
}
return {
viewModel: MyComponentViewModel,
template: { require: 'text!../Models/cmp.html' }
};
});
/Models/cmp.html
<p>First name: <strong data-bind="text: firstName">todo</strong></p>
<p>Last name: <strong data-bind="text: lastName()">todo</strong></p>
<select data-bind="options: sel()" class="form-control" id="sel"></select>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName()" /></p>
resullt:
First name: function c(){if(0 ....
Last name: Doe
I'm guessing you are loading require.js and knockout.js in the index.html file. ko is used in your index.html, so it must be in the global scope. If that is the case, knockout would be loaded twice, and could be causing similar issues to what you describe.
Anyway, I would use a require entry point in your index.html file, and inject ko as a dependency.
<html>
<head>
<title>test</title>
</head>
<body>
<script src="require.js"></script>
<div data-bind="component: 'cmp'"></div>
<script>
require(["knockout-3.4.0"], function(ko) {
ko.components.register('cmp', {require: 'Models/cmp'});
ko.applyBindings();
});
</script>
</body>
</html>
cmp.js (note the path change for the html file)
define(['knockout-3.4.0'], function (ko) {
function MyComponentViewModel(params) {
self = this;
self.firstName = ko.observable("John");
self.lastName = ko.observable("Doe");
self.sel = ko.observableArray(['France', 'Germany', 'Spain']);
}
return {
viewModel: MyComponentViewModel,
template: { require: 'text!Models/cmp.html' }
};
});
cmp.html
<p>First name: <strong data-bind="text: firstName">todo</strong></p>
<p>Last name: <strong data-bind="text: lastName">todo</strong></p>
<select data-bind="options: sel()" class="form-control" id="sel"></select>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
At the root of the project, I have index.html, knockout-3.4.0.js, require.js, and text.js. I included cmp.js and cmp.html in a "Models" subfolder (rootDir\Models).
One last note, if you are using knockout.js heavily, it may be easier to just load knockout.js in the global scope (script tag) and not use it as a dependency in each javascript module.