Reputation: 695
I've been learning KO but only know have I really took my time to create a small project with it from scratch.
I'm having trouble comprehending my issue, I'll briefly explain the logic:
You have pages, and those pages can have pages (children).
/* Defines a Page */
var page = function(ID, alias, body, connections) {
this.ID = ko.observable(ID);
this.alias = ko.observable(alias);
this.body = ko.observable(body);
this.connections = ko.observableArray(connections);
};
var dummyPages = [
new page(1, 'Alias #1', 'Body #1', [5]),
new page(2, 'Alias #2', 'Body #2', []),
new page(3, 'Alias #3', 'Body #3', [2,3]),
new page(4, 'Alias #4', 'Body #4', [5]),
new page(5, 'Alias #5', 'Body #5', [6]),
new page(6, 'Alias #6', 'Body #6', [7]),
new page(7, 'Alias #7', 'Body #7', [1, 4])
];
What I'm trying to do here is use a computed function what will be placed on a foreach html element.
<tbody data-bind="foreach: foreachConnectionAliases" style="text-align: left">
What it will do is basically get the children info of a page.
Here's my code:
/* Return the pages that are connected to the clicked one */
this.foreachConnectionAliases = ko.computed(function(){
alert(this.chPages);
if(typeof this.chPages === "undefined")
return null;
var filtered = ko.utils.arrayFilter(this.chPages(), function(page) {
return this.filterByThisPage(page.ID());
});
debugger;
return filtered;
}).bind(this);//, { deferEvaluation: true });
/* Finds out if the activeConnection exists for the page we want */
this.filterByThisPage = function(pageID){
alert('filterByThisPage');
ko.utils.arrayForEach(getPageConnections(), function(id) {
if(id === pageID) return true;
});
return false;
}.bind(this);
/* Receive a page ID and get its connections array */
this.getPageConnections = function(){
alert('getPageConnections');
var getConnections = ko.utils.arrayFirst(this.chPages(), function(page){
return this.activeConnection() === page.ID();
});
return getConnections.connections();
}
Somewhere along the road I've placed many alerts as you can see. The alert in the computed function only fires once and I think its due to the return null.
An important thing to notice is that supposively I want this to fire as we change the value of this.activeConnection() which is an observable variable that holds the ID of the page we clicked on (to see the children).
Any ideas on fixing the code as well as in making it more clean is very appreciated as I believe I am over complicating this.
EDIT:
I also tried deferEvaluation: true and in that case I always get a undefined error on my foreach data-binding.
EDIT 2:
http://jsfiddle.net/g1q99jr8/6/
This briefly explains my situation. There might be a few mistakes on the HTML part.
Upvotes: 0
Views: 529
Reputation: 6045
well you are trying to filter out based on connection ID which is entered in textbox based on click function .
First point to note here is there is no need to use a computed
here click function might me more than enough and can be done in very simple way
View Model :
var viewModel = function () {
var self = this;
var page = function (ID, alias, body, connections) {
this.ID = ko.observable(ID);
this.alias = ko.observable(alias);
this.body = ko.observable(body);
this.connections = ko.observableArray(connections);
};
var dummyPages = [
new page(1, 'Alias #1', 'Body #1', [5]),
new page(2, 'Alias #2', 'Body #2', []),
new page(3, 'Alias #3', 'Body #3', [2, 3]),
new page(4, 'Alias #4', 'Body #4', [5]),
new page(5, 'Alias #5', 'Body #5', [6]),
new page(6, 'Alias #6', 'Body #6', [7]),
new page(7, 'Alias #7', 'Body #7', [1, 4])];
self.chPages = ko.observableArray(dummyPages);
self.activeConnection = ko.observable();
self.foreachConnectionAliases = ko.observableArray();
/* Return the pages that are connected to the clicked one */
self.changeActiveConnection = function () {
self.foreachConnectionAliases([]);
var conValue = self.activeConnection();
if (typeof self.chPages === "undefined") return null;
var filter = ko.utils.arrayFirst(self.chPages(), function (page) {
if (page.ID() == conValue) return true;
else return false;
});
if(! filter) return true;
ko.utils.arrayForEach(filter.connections(), function (id) {
ko.utils.arrayFilter(self.chPages(), function (page) {
if (page.ID() == id) {
self.foreachConnectionAliases.push(page);
return true;
} else {
return false;
}
});
});
}
};
ko.applyBindings(new viewModel());
working fiddle here
Any issue just in case let us know
Upvotes: 1
Reputation: 7149
Using the Fiddle you provided, I've changed your code to achieve what I think you want to achieve. For array searching, I've used jQuery.
Here's the HTML:
<input type="text" placeholder="Write a number, please" id="number" />
<button type="submit" data-bind="click: changeActiveConnection">
Click me!
</button>
<div style="margin-bottom: 10px"></div>
<div data-bind="foreach:foreachConnectionAliases">
<input type="text" data-bind="value:alias" />
<br />
</div>
And JavaScript:
var viewModel = function () {
var self = this;
var page = function (ID, alias, body, connections) {
this.ID = ko.observable(ID);
this.alias = ko.observable(alias);
this.body = ko.observable(body);
this.connections = ko.observableArray(connections);
};
var dummyPages = [
new page(1, 'Alias #1', 'Body #1', [5]),
new page(2, 'Alias #2', 'Body #2', []),
new page(3, 'Alias #3', 'Body #3', [2, 3]),
new page(4, 'Alias #4', 'Body #4', [5]),
new page(5, 'Alias #5', 'Body #5', [6]),
new page(6, 'Alias #6', 'Body #6', [7]),
new page(7, 'Alias #7', 'Body #7', [1, 4])];
self.chPages = ko.observableArray(dummyPages);
self.activePage = ko.observable();
self.changeActiveConnection = function() {
var number = +$('#number').val();
// Find the selected page
var match = $.grep(self.chPages(), function (e, i) {
return e.ID() == number;
});
if (match.length < 1) // No element found
return;
self.activePage(match[0]);
};
/* Return the pages that are connected to the clicked one */
self.foreachConnectionAliases = ko.computed(function() {
var _page = self.activePage();
if (_page == null || _page.connections().length < 1)
return [];
var aliases = [];
// Loop through the connections of the current page
_page.connections().forEach(function (e, i) {
// Find the page again
var connection = $.grep(self.chPages(), function (el, ix) {
return el.ID() == e;
})[0];
aliases.push(connection);
});
return aliases;
});
};
ko.applyBindings(new viewModel());
And a working Fiddle.
Upvotes: 1