I have this View-Model structure:
function PluginViewModel(name, code) {
var self = this;
self.name = ko.observable(name);
self.code = ko.observable(code);
}
function item() {
var self = this;
self.id = ko.observable();
self.listIndex = ko.observable();
self.value = ko.observable();
self.label = ko.observable();
self.tabPos = ko.observable();
self.plugins = ko.observableArray();
};
function TableViewModel() {
var self = this;
self.columns = ko.observableArray();
self.filteredColumns = ko.observableArray();
// To bind View Fields List
self.selectedColumn = ko.observable();
self.selectColumn = function (p) {
self.selectedColumn(p);
}
// To bind Table Columns List
self.tmpColSelected = ko.observable();
self.tmpColSelect = function (p) {
self.tmpColSelected(p);
}
// Plugin selected
self.selectedPlugin = ko.observable();
self.selectPlugin = function (p) {
self.selectedPlugin(p);
}
// New Plugin
self.newPlugin = ko.observable();
self.addPlugin = function () {
self.selectedColumn().plugins.push(self.newPlugin());
$('#dialogAddPlugin').wijdialog('close');
}
}
function SchemaViewModel() {
var self = this;
self.name = ko.observable();
self.tables = ko.observableArray();
self.selectedTable = ko.observable();
self.selectTable = function (p) {
self.selectedTable(p);
}
}
Then this is binding code:
schema = new SchemaViewModel();
ko.applyBindings(schema);
There is a Master-Detail scenario where an unordered html list is binded with selectedColumn field of tableViewModel.
When a list item is selected, in Detail view I can add plugins with an Add button that shows a Wijmo dialog.
This is the code of dialog:
<div id="dialogAddPlugin" title="Plugin editor" data-bind="with: newPlugin">
<textarea data-bind="value: code, valueUpdate: 'input'"></textarea>
<div>
Name: <input data-bind="value: name, valueUpdate: 'input'" />
<button id="btnSaveNewPlugin" data-bind="click: $parent.addPlugin">Save</button>
</div>
</div>
The problem is that addPlugin method is never called even if view model appears to be correctly setted.
What's wrong?
Thank you
Related
I have the below model
var CountryScopeVM = function (data, root) {
CountryScopeVM.call(this, data);
var self = this;
this.isSelected = ko.observable();
this.centralImpLowHeadCount = ko.observable();
this.load(data);
}
};
this.countryScopes = ko.observableList(CountryScopeVM, data.countryScopes, this);
And I have the below code which gets called when a checkbox is selected. What I am trying to do here is have all the centralImpLowHeadCount inside the countryscope array get updated when the main checkbox is checked but it is not updating and I don't see the change in the UI.
selectAllLOWImplementation: function (data, event) {
var select = $(event.target).is(':checked');
ko.utils.arrayForEach(model.countryScopes() || [], function (countryScope) {
countryScope().centralImpLowHeadCount == select;
});
return true;
}
HTML
<input type="checkbox" data-bind="checked: hasSelectedLOWImplementation, click: selectAllLOWImplementation" />
<td><input type="checkbox" data-bind="checked: centralImpLowHeadCount, enable: isOn" /></td>
I continue learning knockout and continue facing weird issues I don't know how to overcome.
I have the following html page and js script:
HTML:
<div data-bind="debug: $data, foreach: objects">
<span hidden="hidden" data-bind="value: type.id"></span>
<input type="text" data-bind="value: type.title" />
<button type="button" data-bind="click: $parent.removeObject">- </button>
</div>
<div class="control-group form-inline">
<select data-bind="options: availableTypes, optionsValue: function(item) {return item;},
optionsText: function(item) {return item.title;}, value: itemToAdd.type,
optionsCaption: 'Select types...'"></select>
<button type="button" data-bind="click: addObject">+</button>
</div>
</div>
JS:
function model() {
var self = this;
var types = [new Type("1"), new Type("2"), new Type("3")];
var objects = [new Object("1")];
self.objects = ko.observableArray(objects);
self.usedTypes = ko.computed(function() {
return types.filter(function(type) {
for (var j = 0; j < self.objects().length; j++) {
if (self.objects()[j].type.id === type.id) {
return true;
}
}
return false;
});
}, self);
self.availableTypes = ko.computed(function() {
return types.filter(function(type) {
for (var j = 0; j < self.usedTypes().length; j++) {
if (self.usedTypes()[j].id === type.id) {
return false;
}
}
return true;
});
}, self);
self.itemToAdd = new Object();
self.addObject = function() {
self.objects.push(self.itemToAdd);
self.itemToAdd = new Object();
};
self.removeObject = function(object) {
self.objects.remove(object);
};
};
function Object(type) {
var self = this;
self.type = new Type(type);
}
function Type(id) {
var self = this;
self.id = id;
self.title = id;
}
ko.applyBindings(new model());
I simplified model to show the error. The thing is that knockout claims it is illegal to call do this:
<span hidden="hidden" data-bind="value: type.id"></span>
Because it can't find property id in context. As far as I can see it is there and everything ok with it.
Could, please, anybody point me at my mistakes?
p.s. Here is a JsFiddle
ADDITION
Thanks to #Daryl's help I was able to localize the issue. If I replace
self.itemToAdd = new Object();
self.addObject = function() {
self.objects.push(self.itemToAdd);
self.itemToAdd = new Object();
};
with:
self.itemToAdd = new Object();
self.addObject = function() {
self.objects.push(new Object(1));
self.itemToAdd = new Object();
};
though, the following code still doesn't work:
self.itemToAdd = new Object("1");
self.addObject = function() {
self.objects.push(self.itemToAdd);
self.itemToAdd = new Object();
};
It seems itemToAdd objects is populated incorrectly from html elements it's binded to. But I still don't know what exactly is wrong.
You've allowed your type dropdown to be unset. When knockout shows the caption, it clears the actual value. This means that, by rendering the UI, your itemToAdd.type is cleared.
Your second approach solves this by not using the data-bound instance.
Furthermore:
I wouldn't overwrite the Object constructor if I were you... Find a different name.
Make sure your itemToAdd has observable properties if you want to do two-way binding to the UI.
I want to write a computed so I can choose between text input and text from a select drop down, but somewhere down the route I´m stuck.
I have an '' collecting my text string
From a '' I can choose among 'Projects'.
Then I have a checkbox which decides whether the text from the selected project should override my input-textstring.
If the is empty. the selected project.title should set it.
This is my code:
HTML:
<input data-bind="textInput: $root.toDo" placeholder="What to do?" /><br/><br/>
<select data-bind="options: $root.Projects, optionsCaption: '< choose project >', optionsText: 'title', value: $root.selected"></select><br/>
<input id="useProjectTitle" type="checkbox" value="toDoUseProjectTitle" data-bind="checked: $root.toDoUseProjectTitle" />
<label for="useProjectTitle">Use project title as action</label>
<div data-bind="with: $root.toDo">
<label>I prefer:</label>
<ul >
<li >
Project: <span data-bind="text: $root.toDoProjectAction"></span><br/> <!-- Project title-->
To do: <span data-bind="text: $root.toDo"></span> <!-- toDo -->
</li>
</ul>
</div>
And my javascript:
Project = function(data){
var self = this;
self.id = data.id;
self.title = ko.observable(data.title);
};
var viewModel = function () {
var self = this;
self.Projects = ko.observableArray();
// data
self.Projects.push(new Project({
id: 1,
title: 'Friday night live'
}));
self.Projects.push(new Project({
id: 2,
title: 'Saturday morning gym'
}));
self.selected = ko.observable();
self.toDoUseProjectTitle = ko.observable(false);
self.toDoProjectAction = ko.computed(function () {
var title;
var project = self.selected();
if (project) {
title = project.title();
}
return title;
});
self.toDo = ko.computed({
read: function (value) {
if (self.selected()) { // not 'undefined' or null
if (self.toDoUseProjectTitle() || value === null) {
value = self.selected().title();
}
}
return value;
},
write: function (value) {
return value;
},
owner: self
});
};
ko.applyBindings(new viewModel());
Fiddle: http://jsfiddle.net/AsleG/srwr37k0/
Where do I go wrong?
I'm not sure I fully understand your desired behavior, but I have modified your Fiddle to use an extra variable and to correct your writable computed. It could be rearranged to work without a writable, but I didn't. :)
self.handEntered = ko.observable('');
self.toDo = ko.computed({
read: function () {
var value = self.handEntered();
if (self.selected()) { // not 'undefined' or null
if (self.toDoUseProjectTitle() || value === null) {
value = self.selected().title();
}
}
return value;
},
write: function (value) {
self.handEntered(value);
},
owner: self
});
http://jsfiddle.net/srwr37k0/14/
I'm trying to clear and reset my input and select fields using knockoutJS. below is a snippet on how it kinda works but edited for brevity.
Javascript Code
view = (function()
{
var self = this;
self.anItem = ko.observable(new AnItem());
ko.applyBindings(self)
self.addItem = function()
{
self.somewhere.push(this);
self.anItem = new AnItem(); /////this doesn't clear the form
}
})();
function AnItem()
{
this.Name= "";
this.Type= 1
}
Html Code
<tfoot data-bind="with: anItem">
<tr>
<td><input type="text" data-bind="value= Name" /></td>
<td><select data-bind="options: pretendThisIsPopulated, optionsValue:'Value', optionsText:'Text', value:Type" /></td>
<td>add</td>
</tr>
</tfoot>
self.anItem(new AnItem()); //should say instead
You can clear those like this.
Edited
view = (function()
{
var self = this;
var AnItem = function (name,type)
{
var $this = this;
this.Name = ko.observable(name | "");
this.Type = ko.observable(type | 1);
};
self.anItem = ko.observable(new AnItem("Name",1));
ko.applyBindings(self)
self.addItem = function()
{
self.somewhere.push(this);
self.anItem = new AnItem("",1);
};
})();
Use self.addItem(); to clear the data where you want.
I have a knockout array that I use to populate a table. I also have inputs that I use to data-bind to a variable in Filtered Array. . .I need to use these inputs to filter my array and only display that array....how can I do this in my FilteredAray below where the ? is.
<td><input data-bind="value: First, valueUpdate: 'afterkeydown'" /></td>
<td><input data-bind="value: Second, valueUpdate: 'afterkeydown'"/></td>
<td><input data-bind="value: Third, valueUpdate: 'afterkeydown'" /></td>
<td><input data-bind="value: Fourth, valueUpdate: 'afterkeydown'"/></td>
Knockout View Model:
self.First = ko.observable('');
self.Second = ko.observable('');
self.Third = ko.observable('');
self.Fourth = ko.observable('');
self.FilteredArray = ko.computed(function () {
var First = self.First();
var Second = self.Second();
var Third = self.Third();
var Fourth = self.Fourth();
? Filter self.PeopleArray()
}, self);
I am trying to filter an observable array PeopleArray() based on the inputs
You're looking for array filter. It returns you a new array with only the results that return true form the callback.
self.array = ko.obserableArray();
self.filter1 = ko.observable();
self.filter2 = ko.observable();
self.filter3 = ko.observable();
self.filter4 = ko.observable();
self.array = ko.observableArray();
self.filteredArray = ko.computed(function () {
return ko.utils.arrayFilter(self.array(), function (item) {
//logic for filter1
//logic for filter2
//logic for filter3
//logic for filter4
//if result matches the filter for return true, if not test next filter
});
});
});