每次使用单独的选择框时,我都需要更新一个observableArray。问题是酵母.如果用户选择“Danstar”作为酵母的类别,“酵母品种”现在应该只显示
Danstar
Danstar 1
Danstar 2
其中“Danstar”是选项组。我的想法是
{category: 'Danstar', yeasts: ['Danstar 1', 'Danstar 2']}
并设置为yeast_groups_individual
。我需要每对“酵母品牌过滤器”和“酵母品种”独立运作。到目前为止我有:
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){
var self = this;
self.name = ko.observable(data.name || "White Wine");
self.current_filter = ko.observable("-Any-");
var yeast_options = [
{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.yeast_groups_individual = ko.observableArray();
ko.computed(function(){
if (self.current_filter() !== "-Any-"){
var options = _.filter(yeast_options, function(option){
return option.category === self.current_filter();
})
} else{
self.yeast_groups_individual(yeast_options);
}
}
);
self.yeast_categories = ko.observableArray();
ko.computed(function(){
var starter_list = ['-Any-'];
var categories = _.pluck(self.yeast_groups_individual(), 'category');
var final = starter_list.concat(categories);
self.yeast_categories(final);
})
}
function TaskListViewModel() {
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.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){
name.remove(function(hop){
return hop.name === item.name;
});
console.log(name());
console.log(self.hops());
}
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());
<style>
.setuprow label {
margin: 8px 0 0;
display: block;
clear: both;
}
</style>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js'></script>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js'></script>
<div class="setuprow">
<label>Recipe Name:</label>
<input type="text" data-bind="value: recipe_name" maxlength="250" class="recipeSetupText" />
</div>
<div class="setuprow">
<label>Brew Method:</label>
<select class="recipeSetupSelect">
<option value="extract" selected>Extract</option>
<option value="partialmash">Mini-Mash</option>
<option value="allgrain">All Grain</option>
<option value="biab">Brew-in-a-bag</option>
</select>
</div>
<div class="setuprow">
<label>Batch Size:</label>
<input type="text" value="5" maxlength="6" style="width: 60px" /> <span class="unit">(gallons)</span>
</div>
<div class="setuprow">
<label>Style:</label>
<select class="recipeSetupSelect">
<option value="--">--</option>
<option value="Standard American Beer">1. Standard American Beer</option>
<option value="International Lager">2. International Lager</option>
<option value="Czech Lager">3. Czech Lager</option>
<option value="Pale Malty European Lager">4. Pale Malty European Lager</option>
<option value="Pale Bitter European Beer">5. Pale Bitter European Beer</option>
<option value="Amber Malty European Lager">6. Amber Malty European Lager</option>
<option value="Amber Bitter European Lager">7. Amber Bitter European Lager</option>
<option value="Dark European Lager">8. Dark European Lager</option>
</select>
</div>
<div>
<label>Boil Time:</label>
<input type="text" value="60" maxlength="3" style="width: 60px" /> <span class="unit">(minutes)</span>
</div>
<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 data-bind="options: yeast_categories, value: current_filter" id="yeast-brand-select">
</select>
<br/>
<span>Yeast Variety:</span>
<select id="yeast-variety-select" style="width:325px" data-bind="value: name">
<option value="-"> - </option>
<!-- ko foreach: yeast_groups_individual -->
<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, $root.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>
当current_filter
被改变时,如何使yeast_groups_individual
可观察数组更新?
1条答案
按热度按时间2ekbmq321#
到目前为止,我找到的最好的答案是将主数组永久连接到ViewModel,并将其副本(
yeast_options
)传递给每个酵母,现在它可以在不破坏其他酵母行为的情况下使用该数组: