Conditional formatting of KO grid cells - javascript

I'm using kogrid to display data as shown below:
My knockout vm makes an ajax call to an MVC controller to retrieve a DTO shaped as follows:
I would like to colour in RED the cell background that have values that failed validation. For example, the 1st element of the data array contains a "CostCentreIsValid" member with a value of "False", so I would like the "Cost Centre (Dim1)" column of the 1st row to be RED. For the same array element, the "AccountIsValid" member contains the value "True", so I would like the "GL Account (Account)" cell of the first row to be GREEN.
Knockout view model:
"use strict";
function ViewModel(interchangeId) {
var edited = function (interchangeId, accountIsValid, costCentreIsValid, supplierIsValid, supplierNo, invoiceNo, costCentre, glAccount, amount, invoiceDesc, originalRec) {
var self = this;
// Properties
self.interchangeId = interchangeId;
self.supplierNo = ko.observable(supplierNo);
self.invoiceNo = ko.observable(invoiceNo);
self.costCentre = ko.observable(costCentre);
self.glAccount = ko.observable(glAccount);
self.amount = ko.observable(amount);
self.invoiceDesc = ko.observable(invoiceDesc);
self.originalRec = originalRec;
}
var editBatchVm = function () {
var self = this;
var $loadingIndicator = $('#loading-indicator');
// Properties
self.recs = ko.observableArray([]);
self.selected = ko.observableArray();
var textEditTemplate = '<div><input type=\"text\" data-bind=\"visible: $parent.selected(), value: $parent.entity[$data.field]" /><span data-bind=\"visible: !$parent.selected(), text: $parent.entity[$data.field]\"></span></div>';
self.columnDefs = [
{ width: 100, field: 'supplierNo', displayName: 'Supplier No', cellTemplate: textEditTemplate },
{ width: 150, field: 'invoiceNo', displayName: 'Invoice No' },
{ width: 150, field: 'costCentre', displayName: 'Cost Centre (Dim1)', cellTemplate: textEditTemplate },
{ width: 200, field: 'glAccount', displayName: 'GL Account (Account)', cellTemplate: textEditTemplate },
{ width: 100, field: 'amount', displayName: 'Amount' },
{ width: 300, field: 'invoiceDesc', displayName: 'Invoice Description' },
];
self.filterOptions = {
filterText: ko.observable(""),
useExternalFilter: false
};
self.pagingOptions = {
currentPage: ko.observable(1),
pageSizes: ko.observableArray([10, 20, 50]),
pageSize: ko.observable(10),
totalServerItems: ko.observable(0)
};
self.sortInfo = ko.observable({ column: { 'field': 'TimeReceived' }, direction: 'desc' });
self.gridOptions = {
data: self.recs,
columnDefs: self.columnDefs,
autogenerateColumns: false,
showGroupPanel: true,
showFilter: true,
filterOptions: self.filterOptions,
enablePaging: true,
pagingOptions: self.pagingOptions,
sortInfo: self.sortInfo,
rowHeight: 35,
selectWithCheckboxOnly: true,
selectedItems: self.selected,
canSelectRows: true,
displaySelectionCheckbox: true,
};
self.batchId = ko.observable();
// Methods
self.get = function () {
$loadingIndicator.show();
$.ajax({
url: BASE_URL + 'EditBatch/GetRecords',
type: 'get',
data: {
'interchangeId': interchangeId
},
contentType: 'application/json; charset=utf-8',
success: function (data) {
var recsArray = [];
$.each(data, function (key, value) {
recsArray.push(
new edited(
interchangeId,
value.AccountIsValid,
value.CostCentreIsValid,
value.SupplierIsValid,
value.Transaction.Voucher[0].Transaction[0].ApArInfo.ApArNo,
value.Transaction.Voucher[0].Transaction[0].ApArInfo.InvoiceNo,
value.Transaction.Voucher[0].Transaction[0].GLAnalysis.Dim1,
value.Transaction.Voucher[0].Transaction[0].GLAnalysis.Account,
value.Transaction.Voucher[0].Transaction[0].Amounts.Amount,
value.Transaction.Voucher[0].Transaction[0].Description,
value.Transaction
)
);
});
self.recs(recsArray);
//batch level info
self.pagingOptions.totalServerItems(data.length);
self.batchId(data[0].BatchId);
}
});
$loadingIndicator.hide();
};
self.resubmit = function () {
var data = { Recs: ko.toJS(this.recs) };
$.ajax({
type: "POST",
url: BASE_URL + 'EditBatch/Resubmit',
data: ko.toJSON(data),
contentType: 'application/json',
async: true,
success: function (data) {
window.location = BASE_URL + 'APInvoicesSummary/Index';
},
error: function (data) {
toastrs(false);
}
});
}
// Subscriptions
self.pagingOptions.pageSize.subscribe(function (data) {
self.pagingOptions.currentPage(1);
self.get();
});
self.pagingOptions.currentPage.subscribe(function (data) {
self.get();
});
self.sortInfo.subscribe(function (data) {
self.pagingOptions.currentPage(1);
self.get();
});
//self.gridOptions.selectedItems.subscribe(function (data) {
// if (data.length > 0) {
// self.date(data[0].date);
// self.voucherNo(data[0].voucherNo);
// self.description(data[0].description);
// self.amount(data[0].amount);
// }
//});
}
/////////////////////////////////////////////////////////////////
// Let's kick it all off
var vm = new editBatchVm();
ko.applyBindings(vm, $("#KoSection")[0]);
vm.get();
};
Has anyone come across examples of how to do this please?

You can bind the style:
<li data-bind="style: { color: !AccountIsValid() ? 'red' }">
Or bind the css:
<li data-bind="css: { failed--account: !AccountIsValid() }">
And then in your stylesheet:
failed--account {
color: red;
}
NOTES
I suposed your data is in a model and AccountIsValid is an observable, if is binded but not observable just remove the parenthesis color: !AccountIsValid.
If your data is not binded you can access it via data[0].AccountIsValid... But I would recommend to bind it.

Here's how I fixed it:
In the site.css
.failed-validation { color: red; }
.passed-validation { color: green; }
and in the knockout js:
var supplierEditTemplate =
`<div><input type=\"text\" data-bind=\"visible: $parent.selected(), value:
$parent.entity[$data.field]" />
<span data-bind=\"visible: !$parent.selected(), text: $parent.entity[$data.field],
css: $parent.entity.supplierIsValid() === 'True' ? \'passed-validation\' : \'failed-validation\'">
</span>
</div>`;
self.columnDefs = [
{ width: 100, field: 'supplierNo', displayName: 'Supplier No', cellTemplate: supplierEditTemplate }];

Related

pass the argument from one method to another method in extjs

This is my view part
Ext.define('A2a.view.act.Job', {
extend: 'Ext.container.Container',
requires: [
'A2a.store.Job',
'A2a.store.SharedData',
],
border: false,
chart: null,
hrer: [],
layout: {type: 'vbox', pack: 'start', align: 'stretch'},
initComponent: function () {
var me = this;
Ext.Ajax.request({
url: utils.createUrl('api', 'dashboard-read'),
async: true,
callback: function(opts, success, response) {
try {
if (success) {
var output = App.decodeHttpResp(response.responseText);
const data = output.data;
var myArr = [];
data.map((date) =>
myArr = Object.keys(date).filter(key => key != 'DATE'));
me.hrer =myArr;
console.log(me.hrer =myArr);
me.loadChart();
//me.loadww();
}
} catch (ex) {
//return ex;
}
}
});
this.loadww();
this.loadData(me.hrer);
me.callParent(arguments);
},
loadData : function () {
console.log("Init Function");
},
loadww: function (hrer) {
var me = this;
//var self = this;
console.log(me.hrer);
me.jobStore = Ext.create('O2a.store.PendingReports');
Ext.apply(me, {
items: [
{
xtype: 'chart',
itemId: 'charid',
name: 'charid',
store : new Ext.create('Ext.data.JsonStore', {
proxy: {
type: 'ajax',
url : utils.createUrl('api', 'dashboard-read'),
reader: {
type: 'json',
root: 'data'
}
},
autoLoad : true,
successProperty : 'success',
fields : [{name: 'DATE', type: 'auto'}].concat(
O2a.store.SharedData.hrer.map(function(companyName) {
console.log(companyName);
return {
name: companyName,
type: 'int'
};
})
)
}),
style: 'background: #fff',
insetPadding: 40,
animate: true,
shadow: false,
flex: 2,
minHeight: 300,
legend: {
position: 'top',
boxStrokeWidth: 0,
labelFont: '12px Helvetica'
},
axes: [{
type: 'Numeric',
position: 'left',
fields: ['1'],
grid: true,
minimum: 0,
}, {
type: 'Category',
position: 'bottom',
fields: ['DATE'],
grid: true,
}],
}]
});
},
loadChart: function (hrer) {
var me = this;
console.log(me.hrer);
var cha = this.down('#charid');
var iii = null;
Ext.Ajax.request({
url: utils.createUrl('api', 'dashboard-read'),
async: true,
callback: function(opts, success, response) {
try {
if (success) {
var output = App.decodeHttpResp(response.responseText);
const data = output.data;
me.hrer
let myArr = [];
data.map((date) =>
myArr = Object.keys(date).filter(key => key != 'DATE'));
cha.series.clear();
for(var i=0;i<myArr.length;i++){
cha.series.add({
type: 'line',
axis: 'left',
xField: 'DATE',
border: false,
flex: 1,
title: myArr[i],
yField: myArr[i],
markerConfig: {
radius: 4
},
highlight: {
fill: '#000',
radius: 5,
'stroke-width': 2,
stroke: '#fff'
},
tips: {
trackMouse: true,
style: 'background: #FFF',
height: 20,
width: 120,
renderer: function (storeItem, item) {
var name = item.series.title[Ext.Array.indexOf(item.series.yField, item.yField)];
this.setTitle(name + ': ' + storeItem.get(item.yField));
}
}
});
}
} else {
//return 'Unknown Reason';
}
} catch (ex) {
//return ex;
}
}
});
}
}
);
I want to pass the hrer inside the loadww method. If I call the loadww inside the callback of initcomponent function I can be able to pass it. But the graph is not loading. If I call it after the ajax request the graph is loading, but can't pass the hrer to outside.
How to pass the hrer array inside the loadww function. Thanks in advance
From the style of the code it looks like this is ExtJS 3.x
In Ext.Ajax.request define the scope with this to stay in the view.
Your code is not in the best shape.
get rid of the try...catch.
try to write success: this.dashboardSuccess
using callback, will run in both cases (success, failure)
If this is ExtJS 4+ you should split your code in MVC
If this is ExtJS 6+ you should split your code in MVVM
write your code declarative
out the stores in VM and use the load-Event
do not use initComponent
use data-binding

kendo grid dynamic columns

I have a grid in kendo it is created dynamically, when creating generated once the titles of the columns well, but when I come back and recreational grid only puts me in the first column title
function GenerarTabla() {
var fieldsDinamicos;
var fieldDinamico;
myList = [];
fieldsdynamic = [];
$('#ColumnasaMostrar option').each(function () {
col = {};
col.text = $(this).attr("nombrecolumna");
col.operacion = $(this).val();
col.tipodato = $(this).attr("tipodato");
col.nombrefuncion = $(this).attr("nombrefuncion");
myList.push(col);
fieldsdynamic.push($(this).attr("nombrecolumna"));
});
var listaColumnas = fieldsdynamic.join(", ");
var datos;
url2 = urlServicio + '/DynamicService.svc/' + entidaddinamica + '?$select=' + listaColumnas;
//$.getJSON(url2, function (data) {
// datos = data;
//});
var model = {
fields: {
}
};
// model.fields["Id"] = { type: "number" };
var columnasDinamicas = [];
var columnasAgregadas = [];
var fieldsDinamicos = [];
$.each(myList, function (key, val) {
if (val.operacion != "undefined") {
columnasDinamicas.push({
field: val.text,
title: val.text,
footerTemplate: val.nombrefuncion + ": #: " + val.operacion + " #"
});
tipodato = consultarTipoDato(val.tipodato)
model.fields[val.text] = { type: tipodato };
columnasAgregadas.push({ field: val.text, aggregate: val.operacion });
} else {
columnasDinamicas.push({
field: val.text,
title: val.text
});
tipodato = consultarTipoDato(val.tipodato)
model.fields[val.text] = { type: tipodato };
}
})
$("#gridkendo").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: {
url: url2,
dataType: "json"
}
},
schema: {
data: function (data) {
return data.value;
},
total: function (data) {
return data['odata.count'];
},
model: model
},
aggregate: columnasAgregadas,
pageSize: 10
//serverPaging: true,
//serverFiltering: true,
//serverSorting: true
},
height: 430,
filterable: false,
sortable: false,
pageable: true,
columns: columnasDinamicas
});
}
first created
second created

Kendo UI grid comboBox undefined on focus out?

I have working on Keno UI grid and I have added a comboBox as a column in the grid which also supports autocomplete feature. Apparently, comboBox is working fine but when I type half of world and focus out of the comboBox cell then it shows undefined. I have tried to handle it on combobox change event, but it is still showing undefined value? Below is my code for combobox and grid.
function productDropDownEditor(container, options) {
$('<input id="ProductDropDown" style="width:250px;" data-bind="value:' + options.field + '"/>')
.appendTo(container).kendoComboBox({
dataSource: dataSource,
autoBind: false,
dataTextField: 'ProductName',
dataValueField: 'ProductID',
filter: "contains",
suggest: true,
index: 3,
change: function (e) {
debugger;
var cmb = this;
// selectedIndex of -1 indicates custom value
if (cmb.selectedIndex < 0) {
cmb.value(0); // or set to the first item in combobox
}
},
close: function (e) {
debugger;
var cmb = this;
}
});
And here is following code for kendo grid.
$(function () {
$("#grid").kendoGrid({
columns: [
{
field: "Products", width: "250px",
editor: productDropDownEditor,
title: "Product",
template: "#=Products.ProductName#",
attributes: {
"class": "select2_single"
}
},
{ field: "PurchasePrice", width: "150px" },
{ field: "PurchaseQuantity", width: "150px" },
{ field: "SaleRate", title: "Sale Rate", width: "150px" },
{ field: "Amount", title: "Amount", width: "150px" },
{ command: "destroy", title: "Delete", width: "110px" },
],
editable: true, // enable editing
pageable: true,
navigatable: true,
sortable: true,
editable: "incell",
toolbar: ["create"], // specify toolbar commands
edit: function (e) {
//debugger;
//// var parentItem = parentGrid.dataSource.get(e.model.PurchaseID);
////e.model.set("ShipCountry", parentItem.Country);
//if (e.model.isNew()) {
// // set the value of the model property like this
// e.model.set("PropertyName", Value);
// // for setting all fields, you can loop on
// // the grid columns names and set the field
//}
},
//editable: "inline",
dataSource: {
serverPaging: true,
requestStart: function () {
kendo.ui.progress($("#loading"), true);
},
requestEnd: function () {
kendo.ui.progress($("#loading"), false);
},
serverFiltering: true,
serverSorting: true,
batch: true,
pageSize: 3,
schema: {
data: "data",
total: "Total",
model: { // define the model of the data source. Required for validation and property types.
id: "Id",
fields: {
PurchaseID: { editable: false, nullable: true },
PurchasePrice: { nullable: true },
PurchaseQuantity: { validation: { required: true, min: 1 } },
SaleRate: { validation: { required: true, min: 1 } },
Amount: { type: "number", editable: false },
Products: {
nullable: false,
validation: { required: true},
defaultValue: {ProductID:1, ProductName:"Googo" },
//from: "Products.ProductName",
parse: function (data) {
debugger;
if (data == null) {
data = { ProductID: 1};
}
return data;
},
type: "object"
}
}
}
},
batch: true, // enable batch editing - changes will be saved when the user clicks the "Save changes" button
change: function (e) {
debugger;
if (e.action === "itemchange" && e.field !== "Amount") {
var model = e.items[0],
type = model.Type,
currentValue = model.PurchasePrice * model.PurchaseQuantity;//formulas[type](model);
if (currentValue !== model.Amount) {
model.Amount = currentValue;
$("#grid").find("tr[data-uid='" + model.uid + "'] td:eq(4)").text(currentValue);
}
//if (e.field == "Products") {
// $("#grid").find("tr[data-uid='" + model.uid + "'] td:eq(0)").text(model.Products);
//}
}
},
transport: {
read: {
url: "#Url.Action("Read", "Purchase")", //specify the URL which should return the records. This is the Read method of the HomeController.
contentType: "application/json",
type: "POST", //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
},
parameterMap: function (data, operation) {
debugger;
if (operation != "read") {
// post the products so the ASP.NET DefaultModelBinder will understand them:
// data.models[0].ProductID = data.models[0].Product.ProductID;
var result = {};
// data.models[0].ProductID = $("#ProductDropDown").val();
for (var i = 0; i < data.models.length; i++) {
var purchase = data.models[i];
for (var member in purchase) {
result["purchaseDetail[" + i + "]." + member] = purchase[member];
}
}
return result;
} else {
var purchaseID = $("#hdnPurchaseId").val();
//output = '{ purchaseID: ' + purchaseID + '}';
data.purchaseID = purchaseID; // Got value from MVC view model.
return JSON.stringify(data)
}
}
}
},
}).data("kendoGrid");

kendo ui grid sortable and crud is not working

I have followed this tutorial and brought up the sorting to work but now the crud operation is not working.
If i remove the grid sortable code then the crud is working, but no sort.
I have no idea where i am making mistake to make both sort and crud to work
THis is the code i have
$(document).ready(function () {
function dataSource_change(e) {
var data = this.data();
console.log(data.length); // displays "77"
}
var dataSource = new kendo.data.DataSource({
//pageSize: 20,
transport:{
read:{
url: function() {
return "/makes"},
dataType: "json",
cache: false
},
update: {
url: function (make) {
console.log(make)
return "/makes/"+ make.models[0].id
},
type: "PUT",
dataType: "json",
beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token',jQuery('meta[name="csrf-token"]').attr("content")); }
},
destroy: {
url: function (make) {
return "/makes/"+ make.models[0].id
},
type: "DELETE",
dataType: "json"
},
create: {
url: "/makes",
type: "POST",
dataType: "json"
},
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
console.log(options)
return{"make": options.models[0]};
}
else{
return {"make":options};
}
}
},
batch: true,
schema: {
model: {
id: "id",
fields: {
id: { editable: false, nullable: true },
name: { validation: { required: true } },
}
}
}
});
dataSource.bind("change", dataSource_change);
dataSource.fetch();
var grid = $("#grid").kendoGrid({
dataSource: dataSource,
pageable: false,
height: 550,
toolbar: [{name: "create", text: "Add New Make"}],
columns: [
{ field:"name",title:"Makes" },
{ command: ["edit", "destroy"], title: "Action", width: "250px" }],
editable: "inline"
}).data("kendoGrid");
grid.table.kendoSortable({
filter: ">tbody >tr",
hint: $.noop,
cursor: "move",
placeholder: function(element) {
return element.clone().addClass("k-state-hover").css("opacity", 0.65);
},
container: "#grid tbody",
change: function(e) {
console.log(grid)
var skip = grid.dataSource.skip(),
oldIndex = e.oldIndex + skip,
newIndex = e.newIndex + skip,
data = grid.dataSource.data(),
dataItem = grid.dataSource.getByUid(e.item.data("uid"));
var updated_order = []
$('tbody tr').each(function(i){
updated_order.push({ name: $(this).children('td:first').text(), position: i+1 });
});
controller_name = $('#controller_name').val();
$.ajax({
type: "PUT",
url: '/sort',
data: { order: updated_order, controller_name: controller_name }
});
grid.dataSource.remove(dataItem);
grid.dataSource.insert(e.newIndex, dataItem);
}
});
});

Getting a string on an update request in KendoUI datasource

I have a pretty simple grid with data source that retrieves data correctly
For that cause I have a schema.parse function defined
The problem is that when I try to update/create new row the schema.parse() called again and the parameter that is passed to it is a string that contains the HTML of my page. cannot really get what the hell is going on there.
thanks
var _dataSource = new kendo.data.DataSource({
transport: {
read: {
dataType: "json",
url: layerDefProvider.getLayerUrlById("surveys") + "/query",
data: {
f: "json",
//token: token,
outFields: "*",
//outSR: 3857,
where: "1=1"
},
type: "POST"
},
create: function (options) {
console.debug("called");//never gets called
},
update: function (options) {
console.debug("called");//never gets called
},
destroy: function (options) {
console.debug("called");//never gets called
}
},
filter: {
field: "OBJECTID", operator: "eq", value: 0
},
schema: {
data:function(response) {
},
parse: function (data) {//on loading it is fine, on updating the data param is a string of my HTML of the page
var rows = [];
var features = data.features;
if (!features) {
return [];
}
for (var i = 0; i < features.length; i++) {
var dataRow = {};
dataRow.OBJECTID = features[i].attributes.OBJECTID;
dataRow.Name = features[i].attributes.Name;
dataRow.Date = features[i].attributes.Date;
dataRow.Comment = features[i].attributes.Comment;
rows.push(dataRow);
}
return rows;
},
model: {
id: "OBJECTID",
fields: {
OBJECTID: { type: "number", editable: false },
Name: { type: "string" },
Date: { type: "string" },
Comment: { type: "string" }
}
}
}
});
var _surveysPicker = $(config.table).kendoGrid({
toolbar: ["create","save"],
editable: true,
dataSource: _dataSource,
height: 300,
sortable: true,
selectable: "multiple",
columnMenu: true,
resizable: true,
columns: [{
field: "OBJECTID",
width: 40
}, {
field: "Name",
width: 40
}, {
field: "Date",
width: 40
}, {
field: "Comment",
width: 100
}]
});
You need to move your parse function inside read event if you need to parse data only on read action.

Categories

Resources