I'm running into a problem with removing objects in an observable array. I have a removeItemFromQueue function that should remove the selected object from a queue.
This example shows that if you add a bunch the items to the queue and then remove one, it removes all of them:
<h3>Items:</h3>
<ul data-bind="template: {name:'itemsTemplate', foreach: items}"></ul>
<h3>Queue:</h3>
<ul data-bind="template: {name:'queueTemplate', foreach: queue}"></ul>
<script id="itemsTemplate" type="text/x-jquery-tmpl">
<li>
<a href="#">${$data.title}</a> by <a href="#">${$data.description}</a>
<button data-bind="click: function() {viewModel.removeItemFromPage($data);}">Remove From Page</button>
<button data-bind="click: function() {viewModel.addItemToQueue($data);}">Add To Queue</button>
</li>
</script>
<script id="queueTemplate" type="text/x-jquery-tmpl">
<li>
<a href="#">${$data.title}</a> by <a href="#">${$data.description}</a>
<button data-bind="click: function() {viewModel.removeItemFromQueue($data);}">Remove From Queue</button>
</li>
</script>
This is the Javascript:
function Item(title, description) {
this.title = ko.observable(title);
this.description = ko.observable(description);
}
var viewModel = {
items: ko.observableArray([
new Item("one", "one description")
]),
queue: ko.observableArray([]),
addItemToQueue: function (item) {
this.queue.push(item);
},
removeItemFromPage: function (item) {
this.items.remove(item);
},
removeItemFromQueue: function (item) {
this.queue.remove(item);
}
};
ko.applyBindings(viewModel);
I found this workaround using ko.toJS(item) in the addItemToQueue function:
<h3>Items:</h3>
<ul data-bind="template: {name:'itemsTemplate', foreach: items}"></ul>
<h3>Queue:</h3>
<ul data-bind="template: {name:'queueTemplate', foreach: queue}"></ul>
<script id="itemsTemplate" type="text/x-jquery-tmpl">
<li>
<a href="#">${$data.title}</a> by <a href="#">${$data.description}</a>
<button data-bind="click: function() {viewModel.removeItemFromPage($data);}">Remove From Page</button>
<button data-bind="click: function() {viewModel.addItemToQueue($data);}">Add To Queue</button>
</li>
</script>
<script id="queueTemplate" type="text/x-jquery-tmpl">
<li>
<a href="#">${$data.title}</a> by <a href="#">${$data.description}</a>
<button data-bind="click: function() {viewModel.removeItemFromQueue($data);}">Remove From Queue</button>
</li>
</script>
And this Javascript:
function Item(title, description) {
this.title = ko.observable(title);
this.description = ko.observable(description);
}
var viewModel = {
items: ko.observableArray([
new Item("one", "one description")
]),
queue: ko.observableArray([]),
addItemToQueue: function (item) {
this.queue.push(ko.toJS(item));
},
removeItemFromPage: function (item) {
this.items.remove(item);
},
removeItemFromQueue: function (item) {
this.queue.remove(item);
}
};
ko.applyBindings(viewModel);
Is there an easier approach?
Also, the cart example here looks to be using similar code to my first example, but does not suffer the same issue with removing items. I'm a bit baffled.
The problem that you are having is that you are adding the same item multiple times to your queue array.
The remove function of an observableArray will remove all copies of the item that you pass into it.
ko.toJS is one way to get a clean copy of your data. However, you will lose any observables, if you need them.
Otherwise, you might want to do something like:
this.queue.push(new Item(item.title(), item.description()) or write a function that will help you make a copy of the item (pass in an item and return a new item).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With