Reputation: 9672
I'd like to pass arguments in to functions called on click, while retaining the default args. The issue is in the Hops part. I tried to make the remove<this>
functions more clean with:
self.removeItem = function(item, name){
self[name].destroy(item);
}
and
<a href="#" data-bind="click: function() { $root.removeItem($data, "hops") }, visible: $root.hops.countVisible() > 1">Delete</a>
I have tried passing $data, event, "hops"
also. I went based on Knockout.js - passing parameters but I want to access the current element (the hop, grain, or yeast I'm deleting) while also giving the string of the array to delete from.
ko.observableArray.fn.countVisible = function(){
return ko.computed(function(){
var items = this();
if (items === undefined || items.length === undefined){
return 0;
}
var visibleCount = 0;
for (var index = 0; index < items.length; index++){
if (items[index]._destroy != true){
visibleCount++;
}
}
return visibleCount;
}, this)();
};
function Hop(data) {
this.name = ko.observable(data.name || "");
this.amount = ko.observable(data.amount || "");
this.time = ko.observable(data.time || "");
this.use = ko.observable(data.use || "Boil");
}
function Fermentable(data) {
this.name = ko.observable(data.name || "");
this.pounds = ko.observable(data.pounds || "");
this.ounces = ko.observable(data.ounces || "");
this.weight_unit = ko.observable(data.weight_unit || "oz");
this.milling_preference = ko.observable(data.milling_preference || "Milled");
}
function Yeast(data){
this.name = ko.observable(data.name || "White Wine");
}
function TaskListViewModel() {
// Data
var self = this;
self.recipe_name = ko.observable("");
self.hops = ko.observableArray([new Hop({}), new Hop({})]);
self.fermentables = ko.observableArray([new Fermentable({name: 'test'}), new Fermentable({})]);
self.yeasts = ko.observableArray([new Yeast({})]);
self.hops_uses = ko.observableArray(['Boil', 'Dry Hop']);
self.weight_units = ko.observableArray(['oz', 'lb']);
self.milling_preferences = ko.observableArray(['Milled', 'Unmilled']);
self.yeast_groups = ko.observableArray(
[
{category: 'Danstar', yeasts: ['Danstar 1', 'Danstar 2']},
{category: 'Fermentis', yeasts: ['West Coast', 'American Saison', 'White Wine']},
{category: 'White Labs', yeasts: ['White 1', 'White Saison']},
]
);
self.addFermentable = function(){
self.fermentables.push(new Fermentable({}))
}
self.addYeast = function(){
self.yeasts.push(new Yeast({}));
}
self.addHop = function(){
self.hops.push(new Hop({}));
}
self.removeFermentable = function(fermentable){
self.fermentables.destroy(fermentable);
}
self.removeYeast = function(yeast){
self.yeasts.destroy(yeast);
}
self.removeHop = function(hop){
self.hops.destroy(hop);
}
self.removeItem = function(item, name){
self[name].destroy(item);
}
self.prepareJSON = function(){
object = {
fermentables: self.fermentables(),
hops: self.hops(),
yeasts: self.yeasts(),
}
return object
}
self.saveRecipeData = function(){
var data_to_send = ko.toJSON(self);
var recipe_data = ko.toJSON(self.prepareJSON());
alert("This is the data you're sending (universal Javascript object notation):\n\n" + recipe_data)
$.ajax({
url: "http://127.0.0.1:5000/receive-recipe",
headers: {
"Content-Type": "application/json"
},
method: "POST",
dataType: "json",
data: data_to_send,
success: function(data){
console.log("Success! Saved the recipe");
}
});
}
}
ko.applyBindings(new TaskListViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
</head>
<body>
<div class="row">
<h2>Fermentables</h2>
<div data-bind="foreach: fermentables">
<label>Name:</label>
<input type="text" data-bind="value: name"/>
<label>Amount:</label>
<input style="width: 45px;" type="number" min="0" data-bind="value: pounds"/> lb
<input style="width: 55px;" type="number" min="0" data-bind="value: ounces"/> oz
<label>Milling preference: </label>
<select data-bind="options: $root.milling_preferences, value: weight_unit">
</select>
<a href="#" data-bind="click: $root.removeFermentable, visible: $root.fermentables.countVisible() > 1">
Delete
</a>
<br><br>
</div>
<input data-bind="click: addFermentable" type="button" value="Add Fermentable" />
</div>
<div class="row">
<h2 class="">Yeast</h2>
<div data-bind="foreach: yeasts">
<span>Yeast Brand Filter:</span>
<select id="yeast-brand-select">
<option value="">-Any-</option>
<option value="Danstar">Danstar</option>
<option value="White Labs">White Labs</option>
<option value="Wyeast">Wyeast</option>
<option value="-">Others</option>
</select>
<br/>
<span>Yeast Variety:</span>
<select id="yeast-variety-select" style="width:325px" data-bind="value: name">
<option value="-"> - </option>
<!-- ko foreach: $root.yeast_groups -->
<optgroup data-bind="attr: {label: category}">
<!-- ko foreach: yeasts -->
<option data-bind="value: $data, text: $data"></option>
<!-- /ko -->
</optgroup>
<!-- /ko -->
</select>
<a href="#" data-bind="click: $root.removeYeast, visible: $root.yeasts.countVisible() > 1">Delete</a>
<br><br>
</div>
<br>
<input data-bind="click: addYeast" type="button" value="Add Yeast"/>
</div>
<div class="row">
<h2 class="">Hops</h2>
<div data-bind='foreach: hops'>
<label>Hop:</label> <input type="text" data-bind="value: name" >
<label>Amount:</label>
<input type="number" data-bind="value: amount" maxlength="6"> oz
Time: <input type="text" data-bind="value: time" >
Min.
Use: <select data-bind="options: $root.hops_uses, value: use"></select>
<a href="#" data-bind="click: function() { $root.removeItem($data, "hops") }, visible: $root.hops.countVisible() > 1">Delete</a>
<br><br>
</div>
<br>
<input data-bind="click: addHop" type="button" value="Add Hop" />
</div>
<p>
<button data-bind="click: saveRecipeData">Save recipe</button>
</p>
</body>
Upvotes: 1
Views: 528
Reputation: 1459
I tried with this code and it worked -
self.removeItem = function(item, name) {
name.remove(function(hop){
return hop.name === item.name;
});
console.log(name());
console.log(self.hops());
}
Also change the binding for deleting like so -
<a href="#" data-bind="click: function() { $root.removeItem($data, $root.hops) }, visible: $root.hops.countVisible() > 0">Delete</a>
And similarly for fermentables and yeasts.
I would suggest you to have some unique property associated with each row that you are adding so that it can be the matching criterion inside of the self.removeItem
function, because as I can see, two records can have the exact same data which can cause ambiguity as to which item to remove from the array.
Fiddle here
Upvotes: 2