using knockoutjs, i have 2 column Qualification List and Marks . After i click Add button , i want to generate new rows and (Add) button change to Update Button.
Here is my demo: https://jsfiddle.net/fjbrsvgn/3/
function Qualification(data) {
var self = this;
self.QualId = ko.observable(data.QualId);
self.QualName = ko.observable(data.QualName);
self.Marks = ko.observable(data.Marks);
}
function QualificationList(data) {
var self = this;
self.QualId = ko.observable(data.QualId);
self.QualName = ko.observable(data.QualName);
}
var QualificationViewModel = function () {
var self = this;
self.Marks = ko.observable();
self.Qualifications = ko.observableArray(Qualification);
self.QualificationLists = ko.observableArray([
{ QualName: 'Master', QualId: '0' },
{ QualName: 'Bachelor', QualId: '1' },
{ QualName: 'CA', QualId: '2' },
{ QualName: 'School Leaving', QualId: '3' }
]);
self.selectedQualName = ko.observable();
self.AddQualification = function () {
self.Qualifications.push({
QualList: "",
QualificationLists: "",
Marks: "",
selectedQualName: "",
});
};
self.SaveQualification = function () {
console.log(self.Qualifications());
};
};
$(document).ready(function () {
var qualificationViewModel = new QualificationViewModel();
ko.applyBindings(qualificationViewModel);
});
it shows Error: The argument passed when initializing an observable array must be an array, or null, or undefined. My expected result when i console Qualifications need to show Qualification Name Qualification Id and Marks.
The error says
The argument passed when initializing an observable array must be an array, or null, or undefined.
and you are doing this:
self.Qualifications = ko.observableArray(Qualification);
This passes a function to the observable array. This cannot work. You probably wanted to make single new qualification as the default value of qualifications
.
self.Qualifications = ko.observableArray([new Qualification()]);
However, I would initialize the list as empty and let the user add something only when there is something to add. This saves screen space.
The following is an improved version of your attempt:
if
binding to hide the entire qualifications table when there is nothing to show, and an ifnot
binding to show a info paragraph when the list is empty.optionsValue
binding and saves you from having to duplicate the qualification details into each Qualification
object. This also removes the need for an "Update" button.deleteQualification
added.event
binding for that.function checkKeyIsDigit(vm, event) {
return event.charCode >= 48 && event.charCode <= 57 || event.charCode === 46;
}
function Qualification(data) {
var self = this;
self.qual = ko.observable();
self.marks = ko.observable();
}
function EmployeeQualification() {
var self = this;
self.qualificationList = ko.observableArray([
{id: '0', name: 'Master'},
{id: '1', name: 'Bachelor'},
{id: '2', name: 'CA'},
{id: '3', name: 'School Leaving'}
]);
self.qualifications = ko.observableArray();
self.addQualification = function() {
self.qualifications.push(new Qualification());
};
self.deleteQualification = function(qual) {
self.qualifications.remove(qual);
};
self.saveQualification = function() {
console.log(self.qualifications());
};
}
var vm = new EmployeeQualification();
ko.applyBindings(vm);
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h3>Employee Qualification</h3>
<hr>
<div class="col-md-12">
<p data-bind="ifnot: qualifications().length">No qualifications</p>
<table class="table-bordered" data-bind="if: qualifications().length">
<thead>
<tr>
<th class="text-center">Qualification</th>
<th class="text-center">Marks</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody data-bind="foreach: qualifications">
<tr>
<td>
<select class="form-control" data-bind="
value: qual,
options: $parent.qualificationList,
optionsText: 'name',
optionsCaption: '--Choose--'
"></select>
</td>
<td>
<input type="text" placeholder='Marks' data-bind="
value: marks,
event: {keypress: checkKeyIsDigit}
" class="form-control">
</td>
<td>
<button class="btn btn-default" data-bind="click: $parent.deleteQualification">Delete</button>
</td>
</tr>
</tbody>
</table>
<hr>
<div class="col-md-6">
<button class="btn btn-default" data-bind="click: addQualification">Add Qualification</button>
<button class="btn btn-default" data-bind="click: saveQualification">Submit</button>
</div>
</div>
<hr>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>