I'm just starting with Knockout JS, and I'm having trouble finding what is wrong here.
I'm calling a controller Web Service to get some data that I want to display in my page.
This is my ViewModel:
function ViewModel() {
var self = this;
self.MonthSalesList = ko.observableArray();
var url = 'myurl';
self.GetQueryData = function () {
$.ajax({
type: "GET",
url: url,
dataType: "json",
success: function (data) {
console.log('callback success');
console.log(data);
var observableData = ko.mapping.fromJS(data);
var array = observableData();
self.MonthSalesList(array);
},
error: function (jq, st, error) {
alert(error);
}
});
}
}
$(document).ready(function () {
ko.applyBindings(new ViewModel());
});
And in html:
<body>
<table>
<thead>
<tr>
<th>Year</th>
<th>Mes</th>
<th>Ano Atual</th>
<th>Ano Anterior</th>
<th>Variação</th>
</tr>
</thead>
<tbody data-bind="foreach: vendasMesList">
<tr>
<!-- <td data-bind="text: ko.toJSON($data)"></td> -->
<td data-bind="text: Year"></td>
<td data-bind="text: Mes"></td>
<td data-bind="text: Ano Atual"></td>
<td data-bind="text: Ano Anterior"></td>
<td data-bind="text: Variação"></td>
</tr>
</tbody>
</table>
<br/>
<input type="button" value="Get Sales" data-bind="click: GetQueryData" />
</body>
When I load the page and click on "Get Sales", I only get the first values of the json data:
The data I'm trting to get looks like this on Postman:
The only difference I see it's the numeric type of "Ano Atual".
Does anyone know what I'm doing wrong?
Thank you.
You need to change these:
<td data-bind="text: Ano Atual"></td>
<td data-bind="text: Ano Anterior"></td>
...into these:
<td data-bind="text: $data['Ano Atual']"></td>
<td data-bind="text: $data['Ano Anterior']"></td>
That's ugly, but seems to be the way to go.
Related
Knockout observable value not updating on bootstrap Modal. In debug I can see that the value have been successfully added to observable. It just not updating/appearing on the modal DOM.
self.getSdsById = function (val) {
var ID = val.ID;
var operation = event.currentTarget.dataset['operation'];
$.ajax({
url: baseUrl + '/SdsView/getSdsByID',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: { 'ID': ID },
success: function (data) {
self.CopySdsDetail().RegistrationNo(data.Sds.RegistrationNo);
self.CopySdsDetail().MSDSIssueDate(data.Sds.MSDSIssueDate);
self.CopySdsDetail().Place(data.Sds.Place);
self.CopySdsDetail().Dept(data.Sds.Dept);
self.CopySdsDetail().Div(data.Sds.Div);
if (operation == 'COPY') {
$('#copyModalTitle').text('Copy & Add SDS to other Division');
$('#copyModal').modal();
}
}
}).fail(
function (xhr, textStatus, err) {
swal("Error", err, "error");
});
}
Modal :
<div class="modal fade" id="copyModal">
<div class="table-responsive" data-bind="with: CopySdsDetail">
<table class="table table-bordered table-sm">
<tr>
<td>Division: </td>
<td>Department: </td>
<td>Place: </td>
</tr>
<tr>
<td><input type="text" data-bind="value: Div"/></td>
<td><input type="text" data-bind="value: Dept"/></td>
<td><input type="text" data-bind="value: Place"/></td>
</tr>
<tr>
<td data-bind="text: RegistrationNo" colspan="2"></td>
<td data-bind="text: MSDSIssueDate"></td>
</tr>
</table>
</div>
</div>
Ko observable value in debug:
Any idea why?
in the short time I had to look at this, it generally looks ok, I got a very basic sample working with what you have provided. maybe it will help
var data = {
Dept: "Dicing",
Div: "DCG",
ID: 0,
MSDSIssueDate: "/Date(1602172800000)/",
Place: "Etching Process",
RegistrationNo: "DS-033"
}
function ViewModel() {
var self = this;
self.CopySdsDetail = ko.observable(new ModalViewModel());
self.clearData = function(){
self.CopySdsDetail(new ModalViewModel());
}
self.getData = function() {
self.CopySdsDetail(new ModalViewModel(data));
// self.CopySdsDetail().RegistrationNo(data.RegistrationNo);
// self.CopySdsDetail().MSDSIssueDate(data.MSDSIssueDate);
// self.CopySdsDetail().Place(data.Place);
// self.CopySdsDetail().Dept(data.Dept);
// self.CopySdsDetail().Div(data.Div);
}
}
function ModalViewModel(data){
var self = this;
data = data || {};
self.RegistrationNo = ko.observable(data.RegistrationNo || "");
self.Dept = ko.observable(data.Dept || "");
self.Div = ko.observable(data.Div || "");
self.ID = ko.observable(data.ID || "");
self.MSDSIssueDate = ko.observable(data.MSDSIssueDate || "");
self.Place = ko.observable(data.Place || "");
}
var vm = new ViewModel();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="modal fade" id="copyModal">
<div class="table-responsive" data-bind="with: CopySdsDetail">
<table class="table table-bordered table-sm">
<tr>
<td>Division: </td>
<td>Department: </td>
<td>Place: </td>
</tr>
<tr>
<td><input type="text" data-bind="value: Div" /></td>
<td><input type="text" data-bind="value: Dept" /></td>
<td><input type="text" data-bind="value: Place" /></td>
</tr>
<tr>
<td data-bind="text: RegistrationNo" colspan="2"></td>
<td data-bind="text: MSDSIssueDate"></td>
</tr>
</table>
</div>
</div>
<button data-bind="click: getData">Get Data</button>
<button data-bind="click: clearData">Clear Data</button>
When I change the dropdown value, json data is change but not loads, and throws this error:
Uncaught Error: You cannot apply bindings multiple times to the same element.
How to resolve this?
$("#VehicleID").change(function () {
var categoryid = $("#VehicleTypeID option:Selected").val().trim();
var subcategoryid = $(this).val();
var url = "../Consignment/LoadratebydetailId";
$.getJSON(url, { CategoryID: categoryid, SubCategory: subcategoryid },
function (classesData) {
//var koNode = document.getElementById('fareDetailbody');
ko.cleanNode(classesData);
//ko.cleanNode($element[0]);
ko.applyBindings({
teams: classesData,
});
});
$("#rateChargeDiv").hide();
$("#rateChargeDiv").show();
});
<div id="rateDiv">
<div>
<h4>Selected Detail Changed</h4>
<table>
<thead>
<tr>
<th>name</th>
<th>cloth</th>
<th>color</th>
<th>size</th>
<th>length</th>
<th>total</th>
</tr>
</thead>
<tbody id="fareDetailbody" data-bind="foreach: teams">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: cloth"></td>
<td data-bind="text: color"></td>
<td data-bind="text: size"></td>
<td data-bind="text: length"></td>
<td data-bind="text: total"></td>
</tr>
</tbody>
</table>
</div>
<div id="close">close</div></div>
public JsonResult LoadratebydetailId(string CategoryID, string SubCategory)
{
if (CategoryID == "" || string.IsNullOrEmpty(CategoryID))
{
return Json("failure");
}
var vehCategory = this.GetratebydetailId(Convert.ToInt32(CategoryID));
var StatesData = vehCategory.
Where(cat => cat.VehicleCategoryID==Convert.ToInt32(SubCategory))
.Select(m => new
{
m.name,
m.cloth,
m.color,
m.size,
m.length,
m.total
});
return Json(StatesData, JsonRequestBehavior.AllowGet);
}
How get data-bind value in ViewsModel from Button in html table when click ?
Please help me?
Views:
<table border="1">
<thead>
<tr>
<th>
Id
</th>
<th>
Naziv
</th>
</tr>
</thead>
<tbody data-bind="foreach: customers">
<tr>
<td data-bind="text: Id_dobavljaca">
</td>
<td data-bind="text: NazivDobavljaca">
</td>
<td>
<button data-bind="click: edit, value: Id_dobavljaca">
Edit</button>
<button >
Test</button>
</td>
</tr>
</tbody>
</table>
ViewModel:
define(function (require) {
var app = require('durandal/app'), system = require('durandal/system'),
ko = require('knockout');
return {
customers: ko.observableArray([]),
activate: prikazi
}
});
function prikazi() {
var system = require('durandal/system');
var that = this;
system.log('krenu po podatke');
$.ajax({
type: 'GET',
url: '/Durandal/VratiDobavljace',
dataType: "json",
success: function (data) {
that.customers(data);
},
error: function (jq, st, error) {
alert(error);
}
});
system.log('doneo podatke');
edit = function edit1(Id_dobavljaca) {
var system = require('durandal/system');
alert(Id_dobavljaca);
var router = require('plugins/router');
router.navigate('treci/' + 123456);
};
return that.customers
}
I want to pass value ( Id_dobavljaca )in ViewsModels when click button in html table..
Thanks alot!
Martin
In DurandalJS, the object that you return from your requirejs module that is your view model is the object bound to the view. The activate function will be called when DurandalJS composes your view and view model, you can read more here.
In your current implementation the observableArray customers is a property on your view model and can be bound to your view, which is great and I assume working.
However, from looking at your current implementation you have not exposed the edit function on your view model which means it cannot be bound to the UI and used.
I have refactored your view model:
define(function(require) {
var app = require('durandal/app'),
system = require('durandal/system'),
router = require('plugins/router'),
ko = require('knockout');
var customers = ko.observableArray([]);
return {
customers: customers,
edit: function(context) {
alert(context.Id_dobavljaca);
router.navigate('treci/' + context.Id_dobavljaca);
},
activate: function() {
system.log('krenu po podatke');
return $.ajax({
type: 'GET',
url: '/Durandal/VratiDobavljace',
dataType: "json"
})
.done(function(data) { customers(data); })
.fail(function(jq, st, error) { alert(error); })
.always(function() { system.log('doneo podatke'); });
}
}
});
This refactoring exposes the customers observableArray property and the edit function. The activate function also loads your data and returns the promise back to the DurandalJS composition life cycle.
Now, you will notice that the edit function takes an argument called context, this is a knockoutjs thing. When a function is bound to the click binding the first argument passed to the function is the binding context, you can read more here.
Using this refactored view model, in your markup you want to bind your edit button to the edit function on the $root context, which is your view model.
<td>
<button data-bind="click: $root.edit">Edit</button>
<button>Test</button>
</td>
Hopefully, the snippet below can demonstrate this explanation.
var example1 = {
customers: ko.observableArray([{
Id_dobavljaca: 123,
NazivDobavljaca: 'Martin',
edit: function(context) {
alert('Id_dobavljaca: ' + this.Id_dobavljaca);
alert('Id_dobavljaca: ' + context.Id_dobavljaca);
}
}, {
Id_dobavljaca: 321,
NazivDobavljaca: 'Anish',
edit: function(context) {
alert('Id_dobavljaca: ' + this.Id_dobavljaca);
alert('Id_dobavljaca: ' + context.Id_dobavljaca);
}
}, ])
}
ko.applyBindings(example1, $('#example1')[0]);
var example2 = {
customers: ko.observableArray([{
Id_dobavljaca: 123,
NazivDobavljaca: 'Martin'
}, {
Id_dobavljaca: 321,
NazivDobavljaca: 'Anish'
}, ]),
edit: function(context) {
alert('Id_dobavljaca: ' + context.Id_dobavljaca);
}
}
ko.applyBindings(example2, $('#example2')[0]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<p>Edit function is a property on each customer object<p>
<table id="example1" border="1">
<thead>
<tr>
<th>
Id
</th>
<th>
Naziv
</th>
</tr>
</thead>
<tbody data-bind="foreach: customers">
<tr>
<td data-bind="text: Id_dobavljaca">
</td>
<td data-bind="text: NazivDobavljaca">
</td>
<td>
<button data-bind="click: edit">
Edit</button>
<button>
Test</button>
</td>
</tr>
</tbody>
</table>
<br>
<br>
<br>
<p>Edit function is a property on the view model<p>
<table id="example2" border="1">
<thead>
<tr>
<th>
Id
</th>
<th>
Naziv
</th>
</tr>
</thead>
<tbody data-bind="foreach: customers">
<tr>
<td data-bind="text: Id_dobavljaca">
</td>
<td data-bind="text: NazivDobavljaca">
</td>
<td>
<button data-bind="click: $root.edit">
Edit</button>
<button>
Test</button>
</td>
</tr>
</tbody>
</table>
I hope this helps.
I'm presenting data in a table by calling an Action(that returns a list in Json) through an AJAX call.
Output:
http://imageshack.com/a/img673/3484/zxZIqy.png
What i would like to do is to make each user (rows in table) linkable to an edit page (Admin/Edit/Id). Either by simply clicking on them, or by having an Edit-link at the end of each row.
I don't know how to achieve this. It would be easy with ordinary razor syntax. But this template seams to be nice to work with to achieve this sort of dynamic datatable.
I'm working with a template called KODataTable to make this table with both searching and sorting ability.
View..
<div id="kodt">
<div>
<input type="text" data-bind="value: searchText, valueUpdate: 'afterkeydown'" />
<select data-bind="value: selectedColumn, options: columns"></select>
<button data-bind="click: search">Search</button>
</div>
<div>
<table class="table table-striped table-hover">
<thead>
<tr data-bind="foreach: columns">
<th data-bind="text: $data, click: function() { $parent.sort($index()) }" style="cursor: pointer"></th>
</tr>
</thead>
<tbody data-bind="foreach: currentRows">
<tr data-bind="foreach: $parent.columns, click: function () { $root.selectRow($data); }, css: { 'success': $root.selectedRow() == $data }">
<td data-bind="text: $parent[$data]" style="cursor: pointer; text-align: center"></td>
</tr>
</tbody>
</table>
</div>
<div>
<button data-bind="click: firstPage">First</button>
<button data-bind="click: prevPage">Prev</button>
Page <span data-bind="text: currentPage() + 1"></span> of <span data-bind="text: pageCount"></span>
<button data-bind="click: nextPage">Next</button>
<button data-bind="click: lastPage">Last</button>
</div>
</div>
Script..
<script>
var users = new Object();
$.getJSON("/Admin/GetUsers", function (data) {
users = data;
var TableDataVM = new KODataTable({
columns: ["Id", "Username", "RoleId", "CompanyId", ""],
rows: users,
});
ko.applyBindings(TableDataVM, document.getElementById("kodt"));
});
</script>
Right now, it looks like when a user clicks a row, $root.selectRow($data); is invoked, which passes the row object's data over to some function in the ViewModel called selectRow(). If this function exists, you could use it to $.post the row (representing the user object) to the MVC controller in this function, and use the response to redirect to the Edit view.
var vm = function() {
var self = this;
var selectRow = function(rowClicked) {
var data = {
Id = rowClicked.Id,
Username = rowCicked.Username,
// etc.
};
// post the data to some MVC controller - something remotely like this
$.ajax({
url: '/Admin/Edit/' + rowClicked.Id,
data: ko.toJSON(data),
type: 'POST',
success: function (result) {
window.location.href = result.url;
}
});
};
};
Hi I'm trying to make the first element of my observableArray hidden, the following doesn't appear to be working, any ideas?
data-bind="ifnot: $root.typedData[0]===$data"
http://jsfiddle.net/Lx8jR/
<table border="1" style="width:90%">
<tr>
<td data-bind="text: typedData()[0].name"></td>
<td data-bind="text: typedData()[0].type"></td>
</tr>
<tr>
<td>
<table data-bind="foreach: typedData()">
<tr>
<td data-bind="text: name"></td>
</tr>
</table>
</td>
<td>
<table data-bind="foreach: typedData()">
<tr data-bind="ifnot: $root.typedData[0]===$data">
<td data-bind="text: type">
</td>
<td data-bind="text: $index">
</td>
</tr>
</table>
</td>
</tr>
</table>
var ViewModel = function() {
var self = this;
this.typedData = ko.observableArray([
{ name: "Bungle", type: "Bear" },
{ name: "George", type: "Hippo" },
{ name: "Zippy", type: "Unknown" }
]).indexed();
}
Looks like you missed a () on that line.
ifnot: $root.typedData[0]===$data
becomes
ifnot: $root.typedData()[0]===$data
http://jsfiddle.net/Lx8jR/1/
A simple mistake I've made a few dozen times.
If you get into the habit of using ko.utils.unwrapObservable this becomes less of an issue. If you use that function on a non-observable, it still succeeds.
... ko.utils.unwrapObservable($root.typedData)[0]
And for reference, there's an article on KnockMeOut which suggests a few other standards that help simplify our templates and bindings.
typedData is an observableArray, so in your comparison you would want to do (add ()):
$root.typedData()[0] === $data