Knockout foreach bound to value in inputfield - javascript

I want to autogenerate a number of labels on the bottom of my page based on what someone fills in in an inputfield.
So when someone fills in "2", I want 2 labels to pop up, preferable when he typed it without leaving the inputfield or anything.
This is what I have:
HTML
<div class="form-group">
<label class="control-label" for="if_aantalMensen">
Hoeveel extra mensen wil je inschrijven?
</label>
<div>
<input type="text" class="form-control" id="if_aantalMensen" name="if_aantalMensen"
data-bind="textInput: aantalMensen">
</div>
</div>
<div data-bind="foreach: aantalMensenArray" class="form-group">
<label><span data-bind="text: $index"></span></label>
</div>
Javascript
var vm = {
aantalMensen: ko.observable(0),
aantalMensenArray: ko.computed(function() {
var fields = [];
for (var i = 0; i < self.selectedNumberOfFields(); i++) {
fields.push(new Parameter());
}
return fields;
})}
It works if I just make "aantalMensenArray" into an observableArray that already has values in it. However, I can't get it to change the amount of labels shown.

Use valueUpdate:'afterkeydown'
"http://jsfiddle.net/dpa6zk9j/"

Related

How align static labels with a scrolling container of dynamically created forms?

I want the labels and description of the inputs to be to the left of a horizontally scrolling array of forms. Ideally all with their own submit buttons and a submit all button. I've experimented with a much smaller version of what I want. Here's what I've got right now in a fiddle:
https://jsfiddle.net/RedGoblin17/2r3hufpa/58/ .
I think I'm pretty close on the view model:
function FormViewModel(){
var self = this;
self.firstName = ko.observable("");
self.lastName = ko.observable("");
self.number = ko.observable();
self.data = ko.computed(
function(){
return self.firstName() + " " + self.lastName() + " " + (typeof self.number() == "undefined" ? "" : self.number());
}, this
);
}
function AppViewModel(){
var self = this;
self.forms = new ko.observableArray([new FormViewModel()]);
self.addForm = function(){
self.forms.push(new FormViewModel());
}
}
ko.applyBindings(new AppViewModel());
But I don't know how to put the labels in a separate div than the inputs and still line them up properly:
<div class="scroll-grid-container">
<div class="frozelabels">
<label for="fn">First Name</label>
<label for="ln">Last Name</label>
<label for="nn">Number</label>
<label for="fullN">Full Name:</label>
</div>
<div class="scrolling-wrapper" data-bind="foreach: forms">
<div class="card" >
<form class="form-group">
<input id="fn" type="text" data-bind="textInput: firstName"/><br>
<input id="ln" type="text" data-bind="textInput: lastName"/><br>
<input id="nn" type="number" min="1" data-bind="value: number"/>
</form>
<p>
<br /><strong id="fullN" data-bind="text: data"></strong>
</p>
</div>
</div>
</div>
<button data-bind="click: addForm">Add New Form</button>
I can't get the labels to line up correctly with the inputs. I've got it scrolling and adding forms but it's pretty hackly put together, and doesn't look very good. I'm gonna keep working on it and I'll update this post if I figure it out. In the mean time here are some questions that would help me out:
Is there a way to align the labels with the inputs of the form? Is there a way to present a scrollable list of forms next to it? If I'm not too far off base can you point me to examples?
Thank you very much!

only the first row were calculated automatically using jquery

i have this table that has a column for the edit button. a modal will pop up and the data from the row selected will show when the button is clicked.
so on my edit modal, i have 3 textboxes: Quantity, Consumed, and Available.
$('#edit-quant').keyup(function() {
var quant;
var consumed;
quant = parseFloat($('#edit-quant').val());
consumed = parseFloat($('#edit-consumed').val());
avail = quant - consumed || 0;
$("#edit-avail").val(avail);
});
$('#edit-consumed').keyup(function() {
var quant;
var consumed;
quant = parseFloat($('#edit-quant').val());
consumed = parseFloat($('#edit-consumed').val());
avail = quant - consumed || 0;
$("#edit-avail").val(avail);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="input-group mb-3">
<span class="input-group-text" style="color: #008080"><label>Quantity</label></span>
<input class="form-control" type="text" id="edit-quant" name="edit-quant" placeholder="Quantity" value="2"></i>
<span class="input-group-text" style="color: #008080"><label>Consumed</label></span>
<input class="form-control" type="text" id="edit-consumed" name="edit-consumed" placeholder="Consumed" value="3">
<span class="input-group-text" style="color: #008080"><label>Available</label></span>
<input class="form-control" id="edit-avail" type="text" name="edit-avail" placeholder="Available" value="4" readonly>
</div>
and when i try to change the values of the Quantity and Consumed and calculates its Available. only the first row of the table were working. the proceeding rows remains the same. how can i fix this?
I assume you have these repeated. You should not have an id attribute that is the same on any two or more elements on the same page. When you select an element by its id, the first element found with that value is going to be returned.
What you can do is make these into classes, then to get the fields, you can find the .closest(".input-group") which is wrapping all of your fields. From there, you can pull any of the fields by their given class. Alternatively, just use the name attribute on the fields and get rid of the id all together.
<div class="input-group mb-3">
<span class="input-group-text" style="color: #008080"><label>Quantity</label></span>
<input class="form-control" type="text" name="edit-quant" placeholder="Quantity" value="{{$med->med_quantity}}" ></i>
<span class="input-group-text" style="color: #008080"><label>Consumed</label></span>
<input class="form-control" type="text" name="edit-consumed" placeholder="Consumed" value="{{$med->med_consumed}}">
<span class="input-group-text" style="color: #008080"><label>Available</label></span>
<input class="form-control" type="text" name="edit-avail" placeholder="Available" value="{{$med->med_available}}" readonly>
</div>
I've removed the id attributes from the three fields. Now, when our event triggers, we'll find the group (parent DIV), and get each field with .find().
$('input[name = "edit-quant"], input[name = "edit-consumed"]').keyup(function()
{
var $group = $(this).closest('.input-group');
var quant = parseFloat($group.find('input[name = "edit-quant"]').val());
var consumed = parseFloat($group.find('input[name = "edit-consumed"]').val());
$group.find('input[name = "edit-avail"]').val(quant - consumed || 0);
});
Untested, but should work for you, or at least get you on the right track.

Angularjs: Dynamic Input in a single array for row

I'm a newbie and I need some help for something you'll maybe find too easy.
I want to add with a single button different inputs at the same time.
I don't know how to manage.
This is what I'm doing, and I'm blocked.
I'll thank you your ideas.
So, my form shows each name and an input box for entering the age of that person (We don't know how many persons are in 'people').
And in the end, an 'submit' button that calls the showAll() function.
And then, I just want to show the content of the array in console.log
A Form like this:
Form with only 3 people
HTML:
<form name="myForm3">
<div class="form-group row" ng-repeat="person in people track by $index">
<label for="player" class="col-xs-3 col-form-label text-right">{{ person.name }}</label>
<div class="col-xs-2">
<input class="form-control" type="text" ng-model="person.age[$index]" required>
</div>
</div>
<button type="submit" class="btn btn-success btn-lg" ng-click="showAll()" >Show all</button>
</form>
controller.js:
$scope.person = [];
// POST
$scope.showAll = function() {
for (var i=0; i < person.length; i++){
console.log('person: ' + {{ $scope.person[i] }} );
}
}
you can hide the inputs by using ng-if or ng-hide and show them on showAll by setting that variable used by those to true or false:
<div class="col-xs-2" ng-if="person.show">
<input class="form-control" type="text" ng-model="person.age[$index]" required>
</div>
And in showAll:
$scope.showAll = function() {
for (var i=0; i < $scope.people.length; i++) {
$scope.people[i].show = true;
}
};

Put all values from input fields into an array and sort them

for my RPG sessions I want to create an Initiative helper, so I have 2 input fields, number+text where number is the modifier to the
d20 roll and text is the name of the subject (player or npc) -> example of the html (bootstrap components) (I have 6 of these rows so 12 number/text input pairs in total):
<div class="row">
<div class="col-lg-6">
<p>Modifier + Player</p>
<div class="input-group">
<span class="input-group-addon">
<input type="number" min="-5" step="1" placeholder="0">
</span>
<input type="text" class="form-control" placeholder="player1">
</div>
</div>
<div class="col-lg-6">
<p>Modifier + NPC</p>
<div class="input-group">
<span class="input-group-addon">
<input type="number" min="-5" step="1" placeholder="0">
</span>
<input type="text" class="form-control" placeholder="monster1">
</div>
</div>
</div>
Currently I read all the values on click of a button into an object but that is not the optimal base to work with:
var subjects = {};
$("#create").click(function() {
subjects.mod = $("input[type=number]").map(function() { return this.value; }).get();
subjects.name = $("input[type=text]").map(function() { return this.value; }).get();
});
because now I have ONE Object containing all the numbers and names in an array
Object {
mod=[12],
name=[12]
}
but I need both properties coupled into 1 object:
object1 {
"name":"player1",
"iniNumber": 17
},
object2 {
"name":"npc1",
"iniNumber": 10
},
...
I have a function to roll d20 + add the modifier for the final initiative value, but I am too stupid to solve the existing problems...
My current problems:
How do I create coupled Number+Name objects from the input fields, which selector/function to use?
How do I sort it descending? (I suppose I can do that myself as soon as 1) is corrected)
I hope this is what you're looking for.
// At first there was nothing.
var npcs = [];
// Someone eventually interacted with reality.
$('#create').click(function(){
// For every row in now... (You should add another class because you only want npc rows)
$('.row').each(function(i, $row){
// Create object from inputs of a specific row from this dimension.
var newNpc = {
name: $('input[type=text]', $row).val(),
iniNumber: $('input[type=number]', $row).val()
};
// Add object to array to fill our insecurities.
npcs.push(newNpc);
});
});

knockout validation - at least one field has a value and at least one checkbox checked

I'm trying to do some very simple validation using the knockout validation plugin. I want to validate if at least one text field has text and at least one checkbox is checked. All bindings work correctly and knockout itself is awesome so far. I've tested native validation rules and they work with messaging. I just can't get the validation to work for these 2 rules.
I realize I can check for empty values very easily with jQuery but I would really like to utilize knockout.
The model (without validation because I haven't found anything that works yet):
var SearchForm = function(collections) {
// main search fields
this.fullRecord = ko.observable();
this.title = ko.observable();
this.author = ko.observable();
// collections to search
var sources = [];
$.each(collections, function(index,collection) {
sources.push(new Source(collection));
});
this.sources = ko.observableArray(sources);
// Error handling vars
this.errors = ko.validation.group(this);
};
var Source = function(collection) {
$.extend(this,collection);
this.id = "collection-"+this.code;
this.selected = ko.observable(true);
};
Here I'm just creating a list of source objects from collection data that comes from the server. That data is irrelevant since I'm only concerned with the observable 'selected' property.
The markup:
<div id="advanced-controls" class="row">
<div class="col-sm-8">
<fieldset id="search-fields">
<div class="form-group">
<label for="fullrecord" class="control-label">Keywords:</label>
<input type="text" id="fullrecord" class="form-control" name="fullrecord" placeholder="Full Record Search" data-bind="value:fullRecord" />
</div>
<div class="form-group">
<label for="title" class="control-label">Title:</label>
<input type="text" id="title" name="title" class="form-control" data-bind="value:title"/>
</div>
<div class="form-group">
<label for="author" class="control-label">Author:</label>
<input type="text" id="author" name="author" class="form-control" data-bind="value:author"/>
</div>
<div class="form-group">
<button id="advanced-search-submit" class="btn btn-primary" data-bind="click:search">Search</button>
<button id="advanced-search-reset" class="btn" data-bind="click: clear">Clear All</button>
</div>
</fieldset>
</div>
<div class="col-sm-4">
<fieldset data-bind="foreach: sources">
<div class="form-group">
<input type="checkbox" name="collections" data-bind="attr:{ id:id, value:code }, checked:selected, click: $parent.clearRequiredSourceError ">
<label data-bind="attr:{ for:id }, text: name"></label>
</div>
</fieldset>
</div>
</div>
In the validation function before submitting:
// If there's any knockout validation errors
if (model.errors().length > 0) {
model.errors.showAllMessages();
isValid = false;
}
I've tried setting a custom validation extension on the observable array of sources like this:
this.sources = ko.observableArray(sources).extend({
validation: {
validator : function (sources) {
var anySelected = false;
$(sources).each(function(){
anySelected = this.selected();
});
return anySelected;
},
message: 'At least one source is required to search.'
}
});
But that doesn't fire when the checkboxes are clicked, only when the array is changed ~ push, pop, etc. Yes I have the config set correctly:
ko.validation.configure({
grouping: {
deep: true,
observable: true
}
});
This seems like it should be very simple to achieve. Maybe my brain is just fried from diving into the whole knockout world this week. Any suggestions are greatly appreciated. Thanks in advance!
Forgive me for not reading your entire question, as it is very long, but I am curious if you need Knockout validation for this or if you are looking for something like this -
var selectedOption = ko.observable();
var selectionsOk = ko.computed(function () {
((!!field1()|| !!field1()|| !!field1())&&!!selectedOption())
});
Where selectedOption is a list of radio buttons, and once one is selected returns the value, and you could either use an observableArray to contain each of your fields so it is dynamic or you list the fields out and make sure that at least one of them has a value. The !! will evaluate your observable as true or false, true would be returned unless the observables' value was null, undefined, '', or false
The selectionOk computed could be used to prevent clicking some button to proceed or inversely for displaying an error message until the conditions are met.

Categories