how to bind elements from multiple javascript files in html using knockoutjs - javascript

even though this is primary question, i cant solve this even with several attempts. (but im new to this area)
what i need is i have 2 separate java script files and i want to bind from them.
<table style="width: 100%;">
<tr>
<td class="auto-style1">Time For Work: </td>
<td><input id="Text2" type="text" data-bind="value: TimeForWork" /></td>
</tr>
<tr>
<td class="auto-style1">Rest </td>
<td><input id="Text4" type="text" data-bind="value: Rest" /></td>
</tr>
<td class="auto-style1">Project Code </td>
<td ><select id="Select1" data-bind='options: Projects' style="width: 312px"></select>
<button data-bind="click: AddProjects">Cancel</button>
</td>
<td><input id="Text6" type="text" data-bind="value:Test" />
</table>
<script src="Scripts/TimeRecord.js"></script>
<script src="Scripts/ProjectDetail.js"></script>
my java scripts : TimeRecord.js
var ViewModel = {
CheckIn: ko.observable(),
CheckOut: ko.observable(),
Lunch: ko.observable(),
Rest: ko.observable(),
WorkOnProject: ko.observable(),
//Projects: ko.observableArray()
};
ViewModel.TimeForWork = ko.dependentObservable(function () {
return ViewModel.CheckIn() ? ViewModel.CheckOut() ? parseFloat(this.Lunch()) ? parseFloat(this.CheckOut()) - parseFloat(this.CheckIn()) - parseFloat(this.Lunch()) : parseFloat(this.CheckOut()) - parseFloat(this.CheckIn()) : 0 : 0;
}, ViewModel);
ViewModel.RemainHour = ko.dependentObservable(function () {
return ViewModel.TimeForWork() ? ViewModel.Rest() ? ViewModel.WorkOnProject() ? parseFloat(this.TimeForWork()) - parseFloat(this.Rest()) - parseFloat(this.WorkOnProject()) : parseFloat(this.TimeForWork()) - parseFloat(this.Rest()) : parseFloat(this.TimeForWork()) : 0
}, ViewModel);
ProjectDetail.js
var projectLine = function () {
var self = this;
//self.RemainHour = ko.observable();
self.Test = "abc";
self.Projects = ko.observableArray();
self.AddProjects = function () {
alert('abc');
}
}
ko.applyBindings(new projectLine());
in here TimeRecord.js values are binding as i expected. but ProjectDetail values are not binding. even self.Test value does not display. what dd i do wrong?

ko.applyBindings can only be called once per section. If you don't pass a second parameter, the section is the entire page.
Do this something like that.
<div id="one">
<input data-bind="value: name" />
</div>
<div id="two">
<input data-bind="value: name" />
</div>
<script type="text/javascript">
var viewModelA = {
name: ko.observable("Anurag")
};
var viewModelB = {
name: ko.observable("Chaurasia")
};
ko.applyBindings(viewModelA, document.getElementById("one"));
ko.applyBindings(viewModelB, document.getElementById("two"));
</script>
That might help you.

In this situation can create another View model and using that view model can access other view model functions.
var ModelHome={
TimeRecord:ViewModel ,
Project :projectLine ,
};
ko.applyBindings(ModelHome);

Related

Knockout JS : click-to-edit in table

first of all Im using Knockout js.
So I have a table that I can add and remove rows from it dynamically, my problem is that I want to add a click-to-edit in the table for each row but it doesn't work. once I add a second row Im not enable to edit. Here is my code, you can just copy and past it JSFiddle and it will explain further what Im saying.
Here is my code:
(function () {
var ViewModel = function () {
var self = this;
//Empty Row
self.items = ko.observableArray([]);
self.editing = ko.observable(true);
self.edit = function() { this.editing(true) }
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);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<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>
<th>Actions</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>
<b data-bind="uniqueName: true,visible: !($parent.editing()), text: firstName, click: function() { $parent.editing(true) }"></b>
<input data-bind="uniqueName: true, visible: $parent.editing, value: firstName, hasFocus: $parent.editing" />
</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>
<input type="button" value="Add Row" class="btn btn-primary" data-bind="click: addRow" />
thank you for your help
The problem lies in creating a new row that bounds an observable to hasFocus:
<input data-bind="uniqueName: true,
visible: $parent.editing,
value: firstName,
hasFocus: $parent.editing" /> <-- the problem cause
On row creation, the previously-focused row loses focus, which causes editing to be set to false.
So the solution would be to just use the observable value (instead of bounding the observable itself):
<input data-bind="uniqueName: true,
visible: $parent.editing,
value: firstName,
hasFocus: $parent.editing()" /> // <-- call the observable
But better yet is to add an observable into Item view model, called isFocused, and use it instead:
var Item = function (fname, lname, address) {
var self = this;
self.isFocused = ko.observable(true);
// ... other observables ...
};
<input data-bind="uniqueName: true,
visible: isFocused(),
value: firstName,
hasFocus: isFocused" />

Knockout foreach bidning not working

I'm trying to get the Knockout foreach binding working in my code. I've done it many times before, but in this particular case I can't seem to get it right. I must be doing something wrong here, but I can't see it. I created a jsfiddle here: https://jsfiddle.net/9Lc144jv/
JavaScript:
var ReportModel = function (parent) {
var self = this;
self.parent = parent;
self.filters = ko.observableArray([]);
self.addFilter = function () {
self.filters.push({ logicOperator: 0, columnName: null, comparisonOperator: 0, value: null });
};
self.removeFilter = function () {
self.filters.remove(this);
};
};
var ViewModel = function () {
var self = this;
self.reportModel = false;
self.init = function () {
self.reportModel = new ReportModel(self);
};
};
var viewModel;
$(document).ready(function () {
viewModel = new ViewModel();
ko.applyBindings(viewModel);
viewModel.init();
});
HTML:
<body>
<table class="table table-bordered">
<thead>
<tr>
<th></th>
<th>Column</th>
<th>Operator</th>
<th>Value</th>
<th></th>
</tr>
</thead>
<tbody>
<!-- ko foreach: reportModel.filters -->
<tr>
<td><input type="text" class="form-control" data_bind="value: logicOperator" /></td>
<td><input type="text" class="form-control" data_bind="value: columnName" /></td>
<td><input type="text" class="form-control" data_bind="value: comparisonOperator" /></td>
<td><input type="text" class="form-control" data_bind="value: value" /></td>
<td>
<button type="button" class="btn btn-danger" data-bind="click: $parent.removeFilter">
Remove
</button>
</td>
</tr>
<!-- /ko -->
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: right;">
<button type="button" class="btn btn-primary" data-bind="click: reportModel.addFilter">
Add
</button>
</td>
</tr>
</tfoot>
</table>
</body>
UPDATE
A few notes:
I was using the wrong attribute: "data_bind" instead of "data-bind". I corrected it now and the updated code is here: https://jsfiddle.net/9Lc144jv/2/
It's still not working even though I made that fix
When I copied and pasted it to a plain .html file and ran it, I could see something interesting in Firebug:
As you can see, running the following script in the command window shows there is nothing in the collection before clicking Add, and then something afterwards:
JSON.stringify(viewModel.reportModel.filters());
So the new object is in the observable array, but it's not binding to the table in the foreach block. But, why? From what I can see, everything looks fine.. but maybe I need a fresh pair of eyes on this. Someone please show me what I am doing wrong here...
You are setting reportModel after the bindings plus I had to add the function call to the buttons() .
slight changes:
var ReportModel = function (parent) {
var self = this;
self.parent = parent;
self.filters = ko.observableArray([]);
self.addFilter = function () {
self.filters.push({ logicOperator: 0, columnName: null, comparisonOperator: 0, value: null });
};
self.removeFilter = function () {
self.filters.remove(this);
};
};
var ViewModel = function () {
var self = this;
self.reportModel = new ReportModel(self);
self.init = function () {
console.info(self);
//self.reportModel = new ReportModel(self);
};
};
var viewModel;
$(document).ready(function () {
viewModel = new ViewModel();
ko.applyBindings(viewModel);
viewModel.init();
});
HTML
<body>
<table class="table table-bordered">
<thead>
<tr>
<th></th>
<th>Column</th>
<th>Operator</th>
<th>Value</th>
<th></th>
</tr>
</thead>
<tbody>
<!-- ko foreach: reportModel.filters -->
<tr>
<td><input type="text" class="form-control" data_bind="value: logicOperator" /></td>
<td><input type="text" class="form-control" data_bind="value: columnName" /></td>
<td><input type="text" class="form-control" data_bind="value: comparisonOperator" /></td>
<td><input type="text" class="form-control" data_bind="value: value" /></td>
<td>
<button type="button" class="btn btn-danger" data-bind="click: $parent.removeFilter()">
Remove
</button>
</td>
</tr>
<!-- /ko -->
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: right;">
<button type="button" class="btn btn-primary" data-bind="click: reportModel.addFilter()">
Add
</button>
</td>
</tr>
</tfoot>
</table>
</body>
https://jsfiddle.net/vw2kngqq/

Knockout: Using select in foreach loop selects the same exact value in all selects

I just recently started (actually my first project with it) to use Knockout and absolutely love it.
However I've run into an issue, that I seems unable to resolve on my own.
I have a select drop down that runs inside another foreach loop.
Everything looks ok, but the moment I select in one of the dropdowns, it automatically selects same value in all of them.
For example if I select value 'Remove' then all the dropdowns in that foreach will become selected on 'Remove' value.
I would really appreciate help with this one.
Here is the relevant JavaScript (There is more going on in FoldersFileBrowserViewModel but I have removed the excess code) and HTML code
Thank you in advance.
/// <reference path="jquery-2.1.4.min.js" />
/// <reference path="knockout-3.3.0.debug.js" />
$(document).ready(function () {
function FoldersFileBrowserViewModel() {
var self = this;
//actions drop down
self.itemActions = ko.observableArray([{ ActionName: 'Remove' }, { ActionName: 'Move' }]);
self.selectedAction = ko.observable();
var subscription = self.selectedAction.subscribe(function (newValue) {
console.log(newValue.ActionName);
//alert(self.selectedAction().ActionName);
/* do stuff */
});
// ...then later...
//subscription.dispose(); // I no longer want notification
}
ko.applyBindings(new FoldersFileBrowserViewModel());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<tbody data-bind="foreach: filesInFolder" style="border-top:none;">
<tr>
<td></td>
<td class="color-blue">
<input type="checkbox" />
<img src="~/Images/icons/Document-copy-icon.png" alt="file" />
<span style="font-weight:500; color:#555;" data-bind="text: FileName"></span>
#*<input type="hidden" data-bind="text: FilePath">*#
</td>
<td></td>
<td>
#*value: $root.selectedAction,*#
<select data-bind="options: $root.itemActions, optionsText: 'ActionName', value: $root.selectedAction, optionsCaption: '- Select Action -'"></select>
<button data-bind="click: $parent.RemoveFile" style="background-color:transparent; border:none;">
<img src="~/Images/icons/window-app-list-close-icon.png" alt="delete file" />
</button>
</td>
</tr>
</tbody>
You need something to wrap each selected action for each fileInfolder
Something like this based in your code:
$(document).ready(function () {
var File = function (file) {
var self = this;
/* some fields*/
self.FileName = ko.observable( file ? file.FileName : '');
self.FilePath = ko.observable( file ? file.FilePath : '');
self.selectedAction = ko.observable(file ? file.selectedAction : undefined);
var subscription = self.selectedAction.subscribe(function (newValue) {
console.log(newValue); // Log selectedAction here comes the optionsValue field
//alert(self.selectedAction().ActionName);
/* do stuff */
});
// ...then later...
//subscription.dispose(); // I no longer want notification
}
function FoldersFileBrowserViewModel() {
var self = this;
//actions drop down are ok here load them only once if are the same :)
self.filesInFolder = ko.observableArray();
self.itemActions = ko.observableArray([{ ActionName: 'Remove' }, { ActionName: 'Move' }]);
self.filesInFolder.push(new File({ FileName : 'File1' }));// just to add some stuff to test
}
ko.applyBindings(new FoldersFileBrowserViewModel());
});
HTML:
<table>
<tbody data-bind="foreach: { data: filesInFolder , as: 'file' }" style="border-top:none;">
<tr>
<td></td>
<td class="color-blue">
<span style="font-weight:500; color:#555;" data-bind="text: FileName"></span>
<input type="hidden" data-bind="text: FilePath">
</td>
<td></td>
<td>
<select data-bind="options: $root.itemActions, optionsText: 'ActionName', optionsValue: 'ActionName', value: selectedAction, optionsCaption: '- Select Action -'"></select>
</td>
</tr>
</tbody>
Sorry, I'm really bad using this editor always >.<

Accessing part of the data in Knockoutjs with multiple models

I just want to understand why does Knockout.js does not let me access part of the model data. Is it because I am binding the model to the div containing all the submodels (Form in this example) or I am thinking it wrong?
For example, in this jsfiddle http://jsfiddle.net/zv6hauft/1/
I want to save just fare information but leave out bus information. So even if i just pass "fare_lines" in the example, it shows me all the models in the console.
<!doctype html>
<script src="/javascript/knockout-3.3.0.js"></script>
<form id="transport_form" method="post">
<table class="table table-condensed required" data-bind='visible: bus_lines().length > 0'>
<thead>
<tr>
<th>Bus</th>
</tr>
</thead>
<tbody data-bind='foreach: bus_lines'>
<tr>
<td>
<input name="bus_date" type="text" class="bus_date" value=" " data-bind='value: bus_desc' required/>
</td>
<td><a href='#' id="bus_remove" data-bind='click: $parent.removeBusLine'>Delete</a>
</td>
</tr>
</tbody>
</table>
<div class="controls">
<button id="bus_button" data-bind='click: addBusLine'>Add Bus</button>
</div>
<div id="fare_info_table">
<table data-bind='visible: fare_lines().length > 0'>
<thead>
<tr>
<th>Fare</th>
</tr>
</thead>
<tbody class="table required" data-bind='foreach: fare_lines'>
<tr>
<td>
<input id="fare_amnt" data-bind='value: fare_desc' required />
</td>
<td><a href='#' id="fare_remove" data-bind='click:$parent.remove_fare_line'>Delete</a>
</td>
</tr>
</tbody>
</table>
<div class="controls">
<button id="fare_button" data-bind='click: add_fare_line'>Add fare</button>
</div>
</div>
</br>
</br>
<div class="control-group">
<div class="controls">
<button type='submit' data-bind="click: save_record">Submit</button>
</div>
</div>
</form>
</html>
<script>
//Bus Model
var Bus_model = function () {
var self = this;
self.bus_desc = ko.observable();
};
var fare_model = function () {
var self = this;
self.fare_desc = ko.observable();
}
var operations_bus_fare = function () {
var self = this;
//Study Schedule Operations
self.bus_lines = ko.observableArray([new Bus_model()]);
self.addBusLine = function () {
self.bus_lines.push(new Bus_model())
};
self.removeBusLine = function (Bus_line) {
self.bus_lines.remove(Bus_line)
};
//Fare operations
self.fare_lines = ko.observableArray([new fare_model()]);
self.add_fare_line = function () {
self.fare_lines.push(new fare_model())
};
self.remove_fare_line = function (fare_line) {
self.fare_lines.remove(fare_line)
};
self.save_record = function (fare_lines) {
var saveData2 = ko.toJSON(fare_lines);
console.log(saveData2);
alert(saveData2);
};
};
ko.applyBindings(new operations_bus_fare(), document.getElementById("transport_form"));
</script>
You can access part of ViewModel my doing like this
ViewModel:
self.save_record = function (data) { // we get entire vm here as param
var saveData2 = ko.toJSON(data.fare_lines); // access required part
console.log(saveData2);
alert(saveData2);
};
Working fiddle here

Get value from selected Table row Knockout.js

I need a little help.
I have created a table that gets values from JSON response, but for this example lets create a hardcoded html table like following:
<table id="devtable">
<tr>
<th>ID</th>
<th>Name</th>
<th>Status</th>
</tr>
<tr>
<td>001</td>
<td>Jhon</td>
<td>Single</td>
</tr>
<tr>
<td>002</td>
<td>Mike</td>
<td>Married</td>
</tr>
<tr>
<td>003</td>
<td>Marrie</td>
<td>Complicated</td>
</tr>
</table>
ID : <input type="text" name="ID" data-bind="value: ID" disabled/>
<br>
Name : <input type="text" name="Name" data-bind="value: Name" disabled/>
<br>
Status : <input type="text" name="Status" data-bind="value: Status" disabled/>
<br>
<input type="button" value="Send" disabled/>
Requirement is: when I select a row of table, values of columns goes to the input boxes and enable button as well. As I am trying to learn Knockout.js by doing this exercise. I think I have to make a viewmodel like this:
var rowModel = function (id, name, status) {
this.ID = ko.observable(id);
this.Name = ko.observable(name);
this.Status = ko.observable(status);
}
Link of project is here: http://jsfiddle.net/qWmat/
Here's an example of how you could do it:
http://jsfiddle.net/qWmat/3/
function MyVM(data) {
var self = this;
self.items = ko.observableArray(data.map(function (i) {
return new rowModel(i.id, i.name, i.status);
}));
self.select = function(item) {
self.selected(item);
};
self.selected = ko.observable(self.items()[0]);
}
And you bind your textboxes to the properties in the selected property:
<input type="text" name="ID" data-bind="value: selected().ID" disabled/>
And you bind the click handler in your tr like so:
<tr data-bind="click: $parent.select">
Updated to include enable binding (http://jsfiddle.net/qWmat/8/). Add a property for whether or not to edit:
self.enableEdit = ko.observable(false);
Then update your select function to turn it to true:
self.select = function(item) {
self.selected(item);
self.enableEdit(true);
};
If / when you save or cancel you could the set it back to false if you want.
Update your bindings on the input boxes:
<input type="text" name="Status" data-bind="value: selected().Status, enable: enableEdit" />
I've created a demo for you, but to know how it works, you should investigate knockout documentation.
ViewModel:
<table id="devtable">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Status</th>
</tr>
</thead>
<tbody data-bind="foreach: Items" >
<tr data-bind='click: $parent.setEditItem'>
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Status"></td>
</tr>
</tbody>
</table>
<!-- ko with: SelectedItem -->
ID :
<input type="text" name="ID" data-bind="value: ID, attr: {disabled: !$parent.IsEditMode()}" />
<br>Name :
<input type="text" name="Name" data-bind="value: Name, attr: {disabled: !$parent.IsEditMode()}"/>
<br>Status :
<input type="text" name="Status" data-bind="value: Status, attr: {disabled: !$parent.IsEditMode()}"/>
<br>
<input type="button" value="Send" data-bind="attr: {disabled: !$parent.IsEditMode()}"/>
<!-- /ko -->
Html:
function ItemModel(id, name, status) {
var self = this;
self.ID = ko.observable(id);
self.Name = ko.observable(name);
self.Status = ko.observable(status);
}
function ViewModel() {
var self = this;
self.Items = ko.observableArray([
new ItemModel('001', 'Jhon', 'Single'),
new ItemModel('002', 'Mike', 'Married'),
new ItemModel('003', 'Marrie', 'Complicated')
]);
self.SelectedItem = ko.observable(new ItemModel());
self.IsEditMode = ko.observable();
self.setEditItem = function(item) {
self.SelectedItem(item);
self.IsEditMode(true);
}
}
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
Demo

Categories

Resources