Knockout JS: Get dropdown selected data and populate other fields - javascript

Using Knockout JS here.
I have a HTML table and the table has 4 columns. I have button to add a row to table and then remove button against each row to delete it. I also have a dropdown in the first column of this table. The dropdown is populated from the button click event outside the table. Below is my html:
<table class="table table-bordered">
<thead class="mbhead">
<tr class="mbrow">
<th>Input</th>
<th>First Name</th>
<th>Last Name</th>
<th>Address</th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td>
<select class="form-control" data-bind="options: $parent.ddl, optionsText: 'name', value: $parent.selectedColumnValue, optionsCaption: '--Select--', event: { change: $parent.ddlChanged }">
</select>
</td>
<td><span class="input-small" data-bind="value: firstName" /></td>
<td><span class="input-small" data-bind="value: lastName" /></td>
<td><span class="input-small" data-bind="value: address" /></td>
<td>
<input type="button" value="Remove Row" data-bind="click: $parent.removeRow" class="btn btn-danger" />
</td>
</tr>
</tbody>
</table>
<div class="col-xs-12 col-sm-6">
<input type="button" value="Add Row" class="btn btn-primary" data-bind="click: addRow" />
<input type="submit" value="Get Data" data-bind="click: GetData" class="btn btn-primary" />
</div>
My knockout code can be seen in the jsfiddle link as below.
What I am looking for is:
When the user selects the dropdown the selected dropdown text gets populated to that rows one column and the value gets populated to that rows other columns/cell.
My Issue:
1.) I am not able to get the selected text and selected value from the dropdown
When the dropdown selected index change event is fired the event param has the below value as seen in console:
firstName : ƒ c()
lastName: ƒ c()
address : ƒ c()
proto : Object
2.) Secondly I don't know how I could update other column values based on the dropdown selection.
The json that gets binded to dropdown is like below:
'[{"FirstName":"Alex","LastName":"Sanders","Address":123},{"FirstName":"Sam","LastName":"Billings","Address":"Mahony Street"}]';
Here is my fiddle:
https://jsfiddle.net/aman1981/njbyumrs/12/
Inputs are appreciated.

You've got some parent and level stuff mixed up, and your table was binding on value instead of text. I moved the drop down binding, selectedValue to Item since it's at the row level and not the parent level. I used the KO with binding to show the values inside selectedValue for that part of the HTML.
I also added a <pre> tag with the KO values so you can see what happens as you interact with it and the KO model data changes.
Side note: The three properties in Item don't need to be observable in this demo as the values do not change while on the screen.
var ViewModel = function() {
var self = this;
//Empty Row
self.items = ko.observableArray([new Item()]);
self.ddl = ko.observableArray();
self.addRow = function() {
self.items.push(new Item());
};
self.removeRow = function(data) {
self.items.remove(data);
};
self.GetData = function() {
if (self.ddl().length === 0) {
var item1 = new Item("Alex", "Sanders", "Maple Street");
self.ddl.push(item1);
var item2 = new Item("Sam", "Billings", "Mahony Street");
self.ddl.push(item2);
}
}
}
var Item = function(fname, lname, address) {
var self = this;
self.firstName = ko.observable(fname);
self.lastName = ko.observable(lname);
self.address = ko.observable(address);
self.selectedValue = ko.observable();
};
vm = new ViewModel()
vm.GetData();
ko.applyBindings(vm);
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table table-bordered">
<thead class="mbhead">
<tr class="mbrow">
<th>Input</th>
<th>First Name</th>
<th>Last Name</th>
<th>Address</th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td><select class="form-control" data-bind="options: $parent.ddl, optionsText: 'firstName', value: selectedValue, optionsCaption: '--Select--'"> </select></td>
<td data-bind="with: selectedValue">
<span data-bind="text: firstName"></span>
</td>
<td data-bind="with: selectedValue">
<span data-bind="text: lastName"></span>
</td>
<td data-bind="with: selectedValue">
<span data-bind="text: address"></span>
</td>
<td>
<input type="button" value="Remove Row" data-bind="click: $parent.removeRow" class="btn btn-danger" />
</td>
</tr>
</tbody>
</table>
<div class="col-xs-12 col-sm-6">
<input type="button" value="Add Row" class="btn btn-primary" data-bind="click: addRow" />
</div>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

Related

Knockout JS: Dynamically adding and removing table row

I am using knockout js here.
I have a HTML table and the table has 4 columns. I have button to add a row to table and then remove button against each row to delete it. HTML table as below.
<table class="table table-bordered">
<thead class="mbhead">
<tr class="mbrow">
<th>Input</th>
<th>First Name</th>
<th>Last Name</th>
<th>Address</th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td>
<select class="form-control common-input-text" data-bind="event: { change: $root.addNewItem }">
<option value="">One</option>
<option value="">Two</option>
<option value="">Three</option>
</select>
</td>
<td><span class="input-small" data-bind="value: firstName" /></td>
<td><span class="input-small" data-bind="value: lastName" /></td>
<td><span class="input-small" data-bind="value: address" /></td>
<td>
<input type="button" value="Remove Row" data-bind="click: removeRow" class="btn btn-danger" />
</td>
</tr>
</tbody>
</table>
<input type="button" value="Add Row" class="btn btn-primary" data-bind="click: addRow" />
My knockout as:
(function () {
var ViewModel = function () {
var self = this;
//Empty Row
self.items = ko.observableArray([]);
self.addRow = function () {
self.items.push(new Item());
};
self.removeRow = function (data) {
self.items.remove(data);
};
}
var Item = function (fname, lname, address) {
var self = this;
self.firstName = ko.observable(fname);
self.lastName = ko.observable(lname);
self.address = ko.observable(address);
};
vm = new ViewModel()
ko.applyBindings(vm);
})();
When I click add row, it adds the first row but gives me console error:
knockout.js:73 Uncaught ReferenceError: Unable to process binding "click: >function (){return removeRow }"
Message: removeRow is not defined
When I click add row again it gives me another console error:
Uncaught Error: You cannot apply bindings multiple times to the same element.
And when I click removeRow nothing happens.
When I comment out the code for removeRow, I am able to add a new row.
Not sure where I am going wrong.
Here is my jsfiddle:
https://jsfiddle.net/aman1981/nz2dtud6/2/
When using the data binding foreach the context changes to the context of its childs. To access the context of the parent, you need to add $parent to access removeRow
<td>
<input type="button" value="Remove Row" data-bind="click: $parent.removeRow" class="btn btn-danger" />
</td>
Since your <tbody> defines a new scope by using a foreach: items binding, you need to use $parent.removeRow to refer to the method.
<input data-bind="click: $parent.removeRow" type="button" value="Remove Row" />
See BindingContext

How to use jQuery to get Input Field Value of dynamic table

I'm currently using Meteor/Blaze framework to build a table. The row in the table will change according to the selected supplier. I have added class={{_id}} to the field and q.{{_id}} , lot.{{_id}} , and exp.{{_id}} to the quantity, lot , and expire date INPUT.
I'm trying to write a Submit Events to get these value and pass it to the Mongo Database. Please suggest a good way to loop through these rows to get the value.
Website Image
Part of the code
receiveForm template
<template name="receiveForm">
...
<select data-placeholder="Select an option" class="sel2js form-control select select-primary" id="supplier_sel" name="supplier">
{{#each suppliers}}
{{> sel_supplier}}
{{/each}}
</select>
</div>
<!-- Receive Lot Table -->
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Product Name</th>
<th>Current Quantity</th>
<th>Unit of Measurement</th>
<th>Receive Quantity</th>
<th>Lot No</th>
<th>Exp Date (DD/MM/YYYY)</th>
</tr>
</thead>
<tbody>
{{#each items}}
{{> receiveRow2}}
{{/each}}
</tbody>
</table>
<div class="text-center">
<button type="submit" class="btn btn-embossed btn-primary btn-wide" id="submitNewReceive" value="Submit">Submit</button>
<button type="reset" class="btn btn-embossed btn-warning btn-wide" value="Reset">Reset</button>
</div>
</form>
receiveRow2 template
<template name="receiveRow2">
<tr id="{{_id}}">
<td class="pn">{{name}}</td>
<td class="pq">{{totalQuantity}}</td>
<td>{{uomid.name}} ({{uomid.unit}} {{uomid.unitname}}/{{uomid.name}})</td>
<td><input type="text" class="form-control" name="q.{{_id}}" placeholder="Quantity" /></td>
<td><input type="text" class="form-control" name="lot.{{_id}}" placeholder="Lot No XX/YYYY" /></td>
<td>
<div class="input-group datetimepicker text-primary">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
<input class="set-due-date form-control" name="exp.{{_id}}" type="text" placeholder="วัน/เดือน/ปี"/>
<hr />
</div>
</td>
</tr>
</template>
JS
Template.receiveForm.events({
'submit form': function(event, template){
var supplierSelected = Template.instance().supplierSelected;
items = Products.find({suppliers: supplierSelected.get()});
event.preventDefault();
docdate = event.target.docdate.value;
supplier = event.target.supplier_sel.value;
console.log("---event---");
console.log(docdate)
console.log(supplier)
items.forEach(function(item){
????
})
}
})
In line 4 its missing a var before items, and also in line 6, 7.
After that I think you can loop on them.(But they will come from the DB).
BUT if you want to get the input values, why would you ask for a data in MongoDB?
Also I would prefer to get DB values as a promise.
var items = Promise.resolve(Products.find({suppliers: supplierSelected.get()});
and get back the items in this way:
items.then(function(item){console.log(item)})

how to generate blank table rows before filling with ngrepeat

I am relatively new to JavaScript
angular
.module('MainView', ['Utils','ngMaterial'])
.controller('MainCtrl', ['$scope','$timeout','$q','$log' ,function($scope,$timeout,$q,$log) {
var self = this;
self.keychain = null;
self.keychain = [{description:'some description',couponCode:37678 },{description:'some text',couponCode:23478,unitPrice:300.99,totalCost:300.99,actions: 'move' }]
}]);
<div ng-app="MainView" ng-controller="MainCtrl">
<table>
<thead>
<tr>
<th>Description</th>
<th>Coupon Code</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in vm.stockList track by $index" class="item--{{$index}}">
<td>{{$index + 1}}
</td>
<td class="mdl-textfield__input">
<input value="{{item.qty}}" size="3" maxlength="3" class="" type="number" required />
</td>
<td>{{item.couponCode || 'n/a'}}</td>
<td>{{item.description || 'n/a'}}</td>
<td> <button class="mdl-button mdl-js-button ">
<i class="material-icons">delete</i>
</button></td>
</tr>
</tbody>
</table>
</div>
and angular. I am trying to get a blank scroll-able table which i can then enter data into.How can i do this using ng-repeat.I have been on this for several hours. Any help will be appreciated. thanks.
You should initialize your stocklist with empty values
vm.stockList = [
{qty: null, couponCode: null, description: null},
{qty: null, couponCode: null, description: null},
]
I can not run your code snippet and you are using stockList <--!--> keychain.
So the first thing i see is that your input uses value="{{item.qty}}" whereas you should use ng-model="item.qty"
see https://docs.angularjs.org/api/ng/directive/input
Here it's working. You missed out angular file. And so many unwanted codes.
angular.module('MainView', [])
.controller('MainCtrl', ['$scope' ,function($scope) {
var self = this;
self.keychain = null;
self.keychain = [{description:'some description', couponCode:37678 },
{description:'some text',couponCode:23478,unitPrice:300.99,totalCost:300.99,actions: 'move' }];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="MainView">
<table ng-controller="MainCtrl as vm">
<thead>
<tr>
<th>Description</th>
<th>Coupon Code</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in vm.keychain" class="item">
<td>{{$index + 1}}
</td>
<td class="mdl-textfield__input">
<input size="3" maxlength="3" class="" type="number" required />
</td>
<td>{{item.couponCode}}</td>
<td>{{item.description}}</td>
<td> <button class="mdl-button mdl-js-button ">
<i class="material-icons">delete</i>
</button></td>
</tr>
</tbody>
</table>
</div>

Change tr color when checkbox checked

I have created table like below:
<table data-bind="with: choosenDateGoal">
<tbody data-bind="foreach: tblGoals">
<!-- ko if: status -->
<tr class="success">
<td>
<input type="checkbox" onclick="this.disabled = 'disabled';" data-bind="checked: status, disable: status, click: $root.UpdateStatus" />
</td>
<td>
<span style="width: 80%" data-bind="text: goals" />
</td>
<td>
<input type="text" style="width: 80%" data-bind="value: notes , event: { blur: $root.UpdateNote}" />
</td>
</tr>
<!-- /ko -->
</tbody>
</table>
I have an checkbox in every row and when i click on it it should change the row color.
But not working. here is my script for changing color:
self.UpdateColor = function ChangeBackgroundColor() {
debugger;
if ($("input[type='checkbox']:checked")) {
$(this).parent().addClass('success'); ;
}
};
Use knockout's css binding - see http://knockoutjs.com/documentation/css-binding.html
Try binding below and you don't call the ChangeBackgroundColor function
<tr data-bind="css: {success: status()}">
Zaik's answer will work, but if you do it the knockout way, you don't need to add any JavaScript eventing code. This is one of the real benefit's of knockout.

Knock javascript returns nulls to save function

Im new to using Knockout for data-binding and MVC, I can retrieve data just fine returning in a Json object, but when I attempt to return user data back and selections to save my values are null. If I separate remove saveContent div and place the save button control in the searchAudio div then I the user input data is returned but I need to return all the form data that the user selects and inputs.
<form action="AudioLookup" method="get" enctype="multipart/form-data">
<div id="saveContent" data-bind="with: saveContent">
<div id="allAudio" data-bind="with: $root.allAudio">
<h3>Audio Playback</h3>
<table>
<thead>
<tr>
<th>Bind Audio</th>
<th>ID</th>
<th>Text</th>
<th>Url</th>
<th>File Name</th>
<th>Prompt Type</th>
</tr>
</thead>
<tbody data-bind="foreach: AudioResults">
<tr>
<td><input type="radio" name="adgroup"/></td>
<td data-bind="text : _id"></td>
<td ></td>
<td data-bind="text: aUrl"></td>
<td data-bind="text: fileName"></td>
<td data-bind="text: PromptType"></td>
</tr>
</tbody>
</table>
<button data-bind="click: getAllAudio">Get Audio</button>
</div>
<br />
<hr />
<div id="searchAudio" data-bind="with: $root.searchAudio">
<h3>Refine Audio Lookup</h3>
<label for="CallCenterDLL">Choice Call Center: </label>
<select id="CallCenterDLL" data-bind ="value: searchfields.CCCode" name="CallCenterT">
<option value =""></option>
<option value = "11">Kansas City</option>
<option value = "6">Dallas</option>
<option value = "7">Houston</option>
<option value = "8">SanAntonio</option>
<option value = "12">Charlotte</option>
<option value = "9">Raleigh</option>
</select>
<div>
<label for="RBgroup">Choice Prompt Type: </label>
<br/>
<input type="radio" name="RBgroup" value='3' data-bind ="checked: searchfields.searchType"/> Agent<br/>
<input type="radio" name="RBgroup" value='4' data-bind ="checked: searchfields.searchType"/>Office<br/>
</div>
<input type="text" name="serchTxt" placeholder="search string Here" data-bind="value: searchfields.searchVal" onblur="minleng(this.value,25);Minimum(this,3);" onkeypress="minleng(this.value,25)" />
<button data-bind="click: runQuery">Search Data</button>
#* <div id="select-all" data-bind="with: $root.select-all"> *#
<table>
<thead>
<tr>
<th>
<input type="checkbox" name="select-all" id="select-all"/>Select All
</th>
</tr>
</thead>
<tbody data-bind="foreach: dataResult">
<tr>
<td><input data-bind="value: PK" class="selectedPK" type="checkbox" /></td>
<td data-bind="text: PKType"></td>
<td data-bind="text: DisplayVal"></td>
</tr>
</tbody>
</table>
#*</div>*#
</div>
<button data-bind="click: SaveQuery">Save Data</button>
</div>
</form>
function saveViewModel() {
var self = this;
var SviewModel = function (CCCode, PK, PKType, SearchType, SearchVal, Text, fileName, aUrl) {
self.searchfields.CCCode = ko.observable(CCCode);
self.searchfields.searchType = ko.observable(SearchType);
self.searchfields.searchVal = ko.observable(SearchVal);
self.PK = ko.observable(PK);
self.PKType = ko.observable(PKType);
self.Text = ko.observable(Text);
self.fileName = ko.observable(fileName);
self.aUrl = ko.observable(aUrl);
}
self.state = ko.observable();
self.dataResult = ko.observableArray();
self.SaveQuery = function () {
alert(ko.toJSON(SviewModel));
$.ajax(
{
url: "/CallCenter/SaveQuery",
contentType: "application/json",
type: "POST",
dataType: "json",
data: ko.toJSON(self.dataResult),
success: function (data) {
self.SaveResult(data);
}
});
}
}
you alert :-
alert(ko.toJSON(SviewModel));
the data you send :-
data: ko.toJSON(self.dataResult),
and that is :-
self.dataResult = ko.observableArray();
which seems unused.... so not too surprising everything is null

Categories

Resources