Select a specific row in a table with single select - iview-ui

I want to implement a method that cancels moving to the next row if data has changed.
My thought was to use the on-current-change event as this provides me with the oldCurrentRow.
What event should I emit with what parameters to achieve staying on the last highlighted row.
You can find a fiddle here https://jsfiddle.net/arjanno/pdazb5kf/28/
Key is what happens here
onCancel: function () {
//Move back to oldCurrentRow
this.$Message.info(`Clicked cancel`);
}
As long as you don't set data dirty you should be able to click on any row.
When you click Dirty it should show a modal asking you if you want to lose your changes.
On cancel I want to stay on the row I was before clicking on another row.

I don't think we can know the index of the row by the data the on-current-change callback gives us. This can/should be changed since its useful, fell free to open a issue for it.
In any case what you can do is to compare the last selected row with the current data set and use the _highlight key to tell i-table which row to highlight.
Example: https://jsfiddle.net/pdazb5kf/40/
The code would be:
function rowToString(row) {
const data = ['name', 'age', 'address'].map(key => row[key]);
return JSON.stringify(data);
}
export default {
data() {
return {
columns3: [{
type: 'index',
width: 60,
align: 'center'
},
{
title: 'Name',
key: 'name'
},
{
title: 'Age',
key: 'age'
},
{
title: 'Address',
key: 'address'
}
],
dirty: false,
modal1: false,
data1: [{
name: 'John Brown',
age: 18,
address: 'New York No. 1 Lake Park',
date: '2016-10-03'
},
{
name: 'Jim Green',
age: 24,
address: 'London No. 1 Lake Park',
date: '2016-10-01'
},
{
name: 'Joe Black',
age: 30,
address: 'Sydney No. 1 Lake Park',
date: '2016-10-02',
},
{
name: 'Jon Snow',
age: 26,
address: 'Ottawa No. 2 Lake Park',
date: '2016-10-04'
}
]
}
},
methods: {
onCurrentChange: function(currentRow, oldCurrentRow) {
this.lastIndex = rowToString(oldCurrentRow);
if (this.dirty) {
this.modal1 = true;
}
},
onCancel: function() {
//Move back to oldCurrentRow
this.$Message.info(`Clicked cancel`);
this.data1 = this.data1.map((row, i) => {
return {
...row,
_highlight: rowToString(row) === this.lastIndex
}
});
}
}
}

Related

react-bootstrap-table-next onclick(row) not providing correct key/value information

I'm attempting to add an onClick() event to a cell in a row so that I can get the keyField value for that row when the cell is clicked. This functionality worked initially, then I started getting column description information instead of the data key/value pairs in the row parameter. Here's the code:
import BootstrapTable from 'react-bootstrap-table-next';
import 'react-bootstrap-table-next/dist/react-bootstrap-table2.min.css';
import 'components/Delivery/style.scss';
import { Delivery } from 'models/delivery';
import React from 'react';
function DeliveryTable(props: any) {
const lotSelected = (deliveryId: number) => {
console.log(`lotSelected: deliveryId: ${deliveryId}`);
props.updateDeliveryLot(deliveryId);
};
const columns = [
{
dataField: 'id',
text: 'ID',
sort: true,
},
{
dataField: 'completePercent',
text: '% Complete',
sort: true,
events: {
onClick: (e: any, row: Delivery, rowIndex: any, column: any, columnIndex: any) => {
console.log(`row: ${JSON.stringify(row)}`);
lotSelected(row.id);
},
},
},
];
const defaultSorted = [
{
dataField: 'id',
order: 'asc',
},
];
return (
<div>
<div id="delivery-result">
<BootstrapTable
bootstrap4
keyField="id"
data={props.deliveries}
columns={columns}
defaultSorted={defaultSorted}
/>
</div>
</div>
);
}
The data being loaded into the table:
[
{
"id": 1,
"completePercent": 95
},
{
"id": 5,
"completePercent": 96
},
{
"id": 3,
"completePercent": 61
}
]
When I click on one of the cells in the % Complete column, the console shows the following information in the row attribute:
row: {"dataField":"completePercent","text":"% Complete","sort":true,"events":{}}
Previously, when the onClick() method was working correctly, the row attribute contained:
row: {"id": 1, "completePercent", 95}
Since the key value I'm trying to retrieve doesn't exist any longer in the row data, the value I'm getting is undefined rather than the id number I'm expecting.
I also noticed that if I added a style attribute to the column, for instance to underline the value in the '% Complete' cell, that style information will also show up in the information being returned by the onClick(row) call. For instance, if I add style information to the last column (% Complete) so that it's code looks like:
{
dataField: 'completePercent',
text: '% Complete',
sort: true,
style: {
textAlign: 'center', textDecorationLine: 'underline', fontStyle: 'italic',
},
events: {
onClick: (e: any, row: Delivery, rowIndex: any, column: any, columnIndex: any) => {
console.log(`row: ${JSON.stringify(row)}`);
lotSelected(row.id);
},
},
},
then the console output becomes:
row: {"dataField":"completePercent","text":"% Complete","sort":true,"style":{"textAlign":"center","textDecorationLine":"underline","fontStyle":"italic"},"events":{}}
According to the documentation (https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnevents-object) this should be working. Any help would be greatly appreciated.
I figured out what was causing the problem. The onClick() event requires the parameters to be in the order specified by the documentation:
onClick: (e: any, column: any, columnIndex: any, row: Delivery, rowIndex: any) => {
I had inadvertently changed the parameter order while troubleshooting another issue.

How to validate the items of an array with ajv?

I have my validator defined as follows
var abcSchemaValidator = {
"type": "object",
"required": [],
"properties": {
"remarks": {
"type": "string",
"maxLength": 2000
},
"comment": {
"type": "string",
"maxLength": 2000
}
}
};
In my code where I am applying these validations, I am doing something like this
modelObject.remarks = sometext;
modelObject.parent[0].comment
So when I run my ajv validation using the following code
let validate = ajv.compile(schema);
let validResult = validate(data);
The remarks is validated properly whereas the comment is not. I can see why the remarks is straightforward but I am not sure how to make the comment work. Should I change the comment to parent.comment in the schemaValidator? I tried changing to parent[0].comment but that didn't work.
Your schema doesn't define any rule for parent nor does it forbid additional properties. As is your schema is working as expected.
As far as I can tell, parent is:
A non-required but expected property of an object
An array of objects, each of which can have a comment property which schema is the same as remarks
First, let's define something we can re-use:
ajv.addSchema({
$id: 'defs.json',
definitions: {
userInput: {
type: 'string',
maxLength: 10
}
}
});
Then, let's use this common definitions to redefine remarks and define parent
const validate = ajv.compile({
$id: 'main.json',
type: 'object',
properties: {
remarks: {$ref: 'defs.json#/definitions/userInput'},
parent: {
type: 'array',
items: {
type: 'object',
properties: {
comment: {$ref: 'defs.json#/definitions/userInput'}
}
}
}
}
});
And now let's validate some data:
// OK
console.assert(validate({remarks: 'foo'}),
JSON.stringify(validate.errors, null, 2));
// ERR: `remarks` is too long
console.assert(validate({remarks: 'foobarbazbat'}),
JSON.stringify(validate.errors, null, 2));
// OK: schema doesn't say `parent` can't be empty
console.assert(validate({remarks: 'foo', parent: []}),
JSON.stringify(validate.errors, null, 2));
// OK: schema doesn't say `parent` elements MUST have a `comment` property
console.assert(validate({remarks: 'foo', parent: [{}]}),
JSON.stringify(validate.errors, null, 2));
// OK
console.assert(validate({remarks: 'foo', parent: [{comment: 'foo'}]}),
JSON.stringify(validate.errors, null, 2));
// ERR: `comment` is too long
console.assert(validate({remarks: 'foo', parent: [{comment: 'foobarbazbat'}]}),
JSON.stringify(validate.errors, null, 2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.10.2/ajv.min.js"></script>
<script>
const ajv = new Ajv();
ajv.addSchema({
$id: 'defs.json',
definitions: {
userInput: {
type: 'string',
maxLength: 10
}
}
});
const validate = ajv.compile({
$id: 'main.json',
type: 'object',
properties: {
remarks: {$ref: 'defs.json#/definitions/userInput'},
parent: {
type: 'array',
items: {
type: 'object',
properties: {
comment: {$ref: 'defs.json#/definitions/userInput'}
}
}
}
}
});
</script>

C3.js combination chart with time series - tooltip not functional

I've been trying for 3 days to get this chart to display the way I want it to. Everything was working 100% until I realized the grouped bar chart numbers were off.
Example: When the bottom bar value equals 10 and the top bar value equals 20, the top of the grouped bar read 30. This is the default behavior, but not how I want to represent my data. I want the top of the grouped bar to read whatever the highest number is, which lead me to this fiddle representing the data exactly how I wanted to.
After refactoring my logic, this is what I have so far. As you can see the timeseries line is broken up and the tooltip is not rendering the group of data being hovered over.
My questions:
1) How to get the tooltip to render all three data points (qty, price, searches)
2) How to solidify the timeseries line so it's not disconnected
Any help would be greatly appreciated so I can move on from this 3 day headache!
Below is most of my code - excluding the JSON array for brevity, which is obtainable at my jsfiddle link above. Thank you in advance for your time.
var chart = c3.generate({
bindto: '#chart',
data: {
x: 'x-axis',
type: 'bar',
json: json,
xFormat: '%Y-%m-%d',
keys: {
x: 'x-axis',
y: 'searches',
value: ['qty', 'searches', 'price']
},
types: {
searches: 'line'
},
groups: [
['qty', 'price']
],
axes: {
qty: 'y',
searches: 'y2'
},
names: {
qty: 'Quantity',
searches: 'Searches',
price: 'Price ($)'
},
colors: {
price: 'rgb(153, 153, 153)',
qty: 'rgb(217, 217, 217)',
searches: 'rgb(255, 127, 14)'
}
},
bar: {
width: {
ratio: 0.60
}
},
axis: {
x: {
type: 'timeseries',
label: { text: 'Timeline', position: 'outer-right' },
tick: {
format: '%Y-%m-%d'
}
},
y: {
type: 'bar',
label: {
text: 'Quantity / Price',
position: 'outer-middle'
}
},
y2: {
show: true,
label: {
text: 'Searches',
position: 'outer-middle'
}
}
},
tooltip: {
grouped: true,
contents: function(d, defaultTitleFormat, defaultValueFormat, color) {
var data = this.api.data.shown().map(function(series) {
var matchArr = series.values.filter(function(datum) {
return datum.value != undefined && datum.x === d[0].x;
});
if (matchArr.length > 0) {
matchArr[0].name = series.id;
return matchArr[0];
}
});
return this.getTooltipContent(data, defaultTitleFormat, defaultValueFormat, color);
}
}
});
1) If I got it right, you want tooltip to show all values, even if some of them are null.
Null values are hidden by default. You can replace them with zero (if it is suitable for your task) and thus make them visible.
Also, it seems to me that there is a shorter way to get grouped values:
var data = chart.internal.api.data().map(function(item) {
var row = item.values[d[0].index]; // get data for selected index
if (row.value === null) row.value = 0; // make null visible
return row;
});
2) I think you are talking about line.connectNull option:
line: {
connectNull: true
}
UPDATE
Looks like having duplicate keys breaks work of api.data() method.
You need to change json structure to make keys unique:
Before:
var json = [
{"x-axis":"2017-07-17","qty":100},
{"x-axis":"2017-07-17","price":111},
{"x-axis":"2017-07-17","searches":1},
{"x-axis":"2017-07-18","qty":200},
{"x-axis":"2017-07-18","price":222},
{"x-axis":"2017-07-18","searches":2}
];
After:
var json = [
{"x-axis":"2017-07-17","qty":100,"price":111,"searches":1},
{"x-axis":"2017-07-18","qty":200,"price":222,"searches":2}
];
See fiddle.

KendoGrid - After applying custom filter and then navigating to next or any other page, the filter values are not getting passed to controller

Used Kendo Version: 2015.2.624
I have implemented kendogrid server side paging with additional parameters. Below is how my controller looks like:
public ActionResult GetData([DataSourceRequest] DataSourceRequest request, DateTime startDate, DateTime endDate, int state = -1, string poolName = null, string submitter = null)
{
poolName = string.IsNullOrEmpty(poolName) ? null : poolName;
submitter = string.IsNullOrEmpty(submitter) ? null : submitter;
var summarylist = new List<Summary>();
var total = 0;
using (var db = new SummaryEntities())
{
var jobs = db.SummaryTable.Where(k => k.created >= startDate && k.created <= endDate)
.Where(k => state != -1 ? k.state == state : k.state > state)
.Where(k => poolName != null ? k.pool_name == poolName : k.pool_name != null)
.Where(k => submitter != null ? k.submitter == submitter : k.submitter != null);
jobs = jobs.OrderByDescending(job => job.id);
total = jobs.Count();
// Apply paging...
if (request.Page > 0)
{
jobs = jobs.Skip((request.Page - 1) * request.PageSize);
}
jobs = jobs.Take(request.PageSize);
foreach (var job in jobs)
{
summarylist.Add(new Summary(job));
}
}
var result = new DataSourceResult()
{
Data = summarylist,
Total = total
};
return Json(result, JsonRequestBehavior.AllowGet);
}
additional parameters are the current values which the user has set over the widget datepicker, input box etc.
Below is how my datasource looks like in grid:
<script type="text/javascript">
j$ = jQuery.noConflict();
j$(document).ready(function () {
j$("#grid").kendoGrid({
dataSource: {
transport: {
read: {
url: "/Home/GetData/",
dataType: "json",
data: {
startDate: j$("#startdate").val(),
endDate: j$("#enddate").val()
}
}
},
pageSize: 30,
serverPaging: true,
schema: {
data: 'Data',
total: 'Total'
}
},
height: j$(window).height() - 85,
groupable: true,
sortable: true,
filterable: false,
columnMenu: true,
pageable: true,
columns: [
{ field: "JobId", title: "Job Id", template: '#:JobId#', type: "number" },
{ field: "Name", title: "Job Name", hidden: true },
{ field: "PoolName", title: "Pool Name" },
{ title: "Date Time", columns: [{ field: "Start", title: "Start" },
{ field: "End", title: "End" }
],
headerAttributes: {
"class": "table-header-cell",
style: "text-align: center"
}
},
{ field: "State", title: "State" },
{
title: "Result", columns: [{ field: "ResultPassed", title: "P" },
{ field: "ResultFailed", title: "F" }
],
headerAttributes: {
"class": "table-header-cell",
style: "text-align: center"
}
},
{ field: "Submitter", title: "Submitter" }
]
});
});
</script>
It works pretty good until I observed this issue:
Change the filter values i.e submitter, date range etc and
controller gets all this information in additional parameters where
I am taking action accordingly and it works just fine.
Now suppose the result returned from step 1 has multiple pages and
when you click next page, or last page or any other page number, the
controller gets invoked which is expected but the additional
parameters being set in step 1 is not getting passed again instead
the default values are there which is ruining everything.
Correction:
Additional parameters are getting lost at client side only.
Now please tell me what am I missing here?
Expected Result: In step 2 additional parameters should not get lost and it should be same as step 1.
Any help is appreciated.
EDITED:
Complete controller and grid code.
Thanks,
Vineet
I got the solution from telerik support team:
Reply:
The described undesired behavior can be caused by the fact that the additional parameters:
data: {
startDate: j$("#startdate").val(),
endDate: j$("#enddate").val()
}
... are set to objects, instead of a functions. If they are set as functions, the values of the corresponding inputs will be evaluated every time read() is called, and the current values will be passed (like shown in the second example in the API reference):
http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-transport.read.data

How to use c3.js No data option

I am trying to use no data option from c3.js but somehow it does not work for me.
My js fiddle:
http://jsfiddle.net/ymqef2ut/7/
I am trying to use the empty option according to c3 documentation:
empty: { label: { text: "No Data Available" } }
There are two issues in your fiddle:
Problem1:
data: {
columns: [
['electricity plants', elec_plants],
['CHP plants', chp_planrs],
['Unallocated autoproducers / Other energy industry own use', auto_pro],
['Other', other_elec],
],
type : 'pie'
},
empty: { label: { text: "No Data Available" } },//this is wrong should be a part of data
The empty should be a part of the data json like below
data: {
columns: [
['electricity plants', elec_plants],
['CHP plants', chp_planrs],
['Unallocated autoproducers / Other energy industry own use', auto_pro],
['Other', other_elec],
],
type : 'pie',
empty: { label: { text: "No Data Available" } },//this is correct
},
Problem 2:
When data is not present the column array should be an empty array
var col5 = [];//set empty array
if (resi || com || agri || other_sec){
col5 = [['Residential', resi],
['Commercial and public services', com],
['Agriculture/forestry', agri],
['Other', other_sec]]
}
//if all are 0 then col = []
var chart = c3.generate({
bindto: "#chart_5",
data: {
columns: col5,
type: 'pie',
empty: {
label: {
text: "No Data Available"
}
}
},
Working code here
Testcase: Check for Iraq
Hope this helps!

Resources