Bootstrap-Vue: Sorting table column based on Formatter data - vue.js

So right now I have data presenting the way that is required. This is how I have the field set up
{
key: "pendingTime",
formatter: (value, key, item) => {
return this.pendingSinceDate(_, key, item);
},
label: "Pending Since",
sortable: true,
},
And this is the function being used.
pendingSinceDate(value, key, item) {
const timeMath = (day1, day2) => {
const hours = dayjs(day1).diff(day2, "hours");
return Math.trunc(hours / 24);
};
const timeFormat = dayjs(
item.operations.localAreaOrder.dateLastModified,
).format("L");
const dayCount = timeMath(
dayjs().startOf("day"),
dayjs(item.operations.localAreaOrder.dateLastModified).startOf("day"),
);
key = `${timeFormat} - ${dayCount} ${dayCount === 1 ? "Day" : "Days"}`;
return key;
},
I've been reading about sortByFormatted and sort-compare and trying to understand implementation. Is there a way to have sorting work based on timeFormat as we need sorting based on that date.
From I'm understanding with sortByFormatted can accept a function or true. So I tried to see and created a function to console.log just to make sure things work.
Not getting anything back with this function when I add it to sortByFormatted
sortedByFormatTest(value, key, item){
console.log(value, key, item)
},
Anyone got direction on where to look or tips to get started on figuring out how to sort on that?

Related

Redis getting all fields of sorted set

im trying to make a freelancing website that will hold gigs at redis for caching, in order to categorise them, there are 2 fields called "categoryId" and "skillId" and i want to keep them sorted with "createdAt" field which is a date. So i have two options and i have some blank spots about first one.
option1
Im holding my gigs at sorted set and making a key with two parameter which holds categoryId And skillId, but the problem is user may want only select gigs with specific category and skill doesn't matter. But user may also want select gigs with both categoryId and skillId. So for that reason i used a key like
`gigs:${categoryId}:${skillId != null ? skillId : "*"}`
here's my full code
export const addGigToSortedSet = async (value) => {
return new Promise<string>((resolve, reject) => {
let date =
value.gigCreatedAt != null && value.createdAt != undefined
? Math.trunc(Date.parse(<string>value.createdAt) / 1000)
: Date.now();
redisClient
.zAdd(`gigs:${value.gigCategory}:${value.gigSkill}`, {
score: date,
value: JSON.stringify(value),
})
.then((res) => {
if (res == 1) {
resolve("Başarılı");
} else {
reject("Hata");
return;
}
});
});
};
export const multiAddGigsToSortedSet = async (gigs: any[]) => {
return new Promise((resolve, reject) => {
let multiClient = redisClient.multi();
for (const gig of gigs) {
let date =
gig.gigCreatedAt != null && gig.createdAt != undefined
? Math.trunc(Date.parse(<string>gig.createdAt) / 1000)
: Date.now();
multiClient.zAdd(`gigs:${gig.gigCategory}:${gig.gigSkill}`, {
score: date,
value: JSON.stringify(gig),
});
}
multiClient.exec().then((replies) => {
if (replies.length > 0) {
resolve(replies);
} else {
reject("Hata");
return;
}
});
});
};
export const getGigsFromSortedSet = async (
categoryId: string,
page: number,
limit: number,
skillId?: string
) => {
return new Promise<string[]>((resolve, reject) => {
redisClient
.zRange(
`gigs:${categoryId}:${skillId != null ? skillId : "*"}`,
(page - 1) * limit,
page * limit
)
.then((res) => {
if (res) {
resolve(res.reverse());
} else {
reject("Hata");
return;
}
});
});
};
Option 2
option two is way more simpler but less more effective with storage usage
i'll create two sorted set about category and skill and then will use zinterstore to get my values, and i will easily get gigs about only category since i have different set.
so my question is which way is more effective solution and will this line give me gigs with given category without skill parameter?
gigs:${categoryId}:${skillId != null ? skillId : "*"}
Your approach #2 is the most common implementation. See https://redis.io/docs/reference/patterns/indexes/
But...
Indexes created with sorted sets are able to index only a single
numerical value. Because of this you may think it is impossible to
index something which has multiple dimensions using this kind of
indexes, but actually this is not always true. If you can efficiently
represent something multi-dimensional in a linear way, they it is
often possible to use a simple sorted set for indexing.
For example the Redis geo indexing API uses a sorted set to index
places by latitude and longitude using a technique called Geo hash.
The sorted set score represents alternating bits of longitude and
latitude
Therefore if you can find an encoding scheme of your "categoryId" and "skillId" into a single value then you could use a single sorted set.

Loopback 4 - How to find the highest value in column (Like SELECT MAX(column) from Table)?

I want to find the highest value in a specific column of a specific table. It should be very simple.
this is the documentation of LB4 https://loopback.io/doc/en/lb2/Where-filter But I didn't find it there.
We did this through a custom repository method where we execute a select max() query and have a custom controller method (i.e. /next-id) that calls it.
Repository method:
async nextId(): Promise<any> {
return this.dataSource
.execute('select MAX(id)+5 as nextId from route_lookup')
.then(data => {
if (data[0].NEXTID === null) {
data[0].NEXTID = 1005;
}
return data[0].NEXTID;
});
}
Controller method:
#get('/route-lookups/next-id')
#response(200, {
description: 'Next avaialble id for route lookup',
content: {
'application/json': {
schema: {
type: 'number',
},
},
},
})
async nextId(): Promise<number> {
return await this.routeLookupRepository.nextId();
}
Within the Loopback Filter Documentation they do mention a way to achieve this, even though it's not as obvious.
/weapons?filter[where][effectiveRange][gt]=900&filter[limit]=3
Essentially you can do the following:
Identify the column of interest.
Use the gt operator to set a min number
Add order if you wanted to ensure the sorting order is as expected.
Limit the results to 1.
Here is a code example:
Employees.find({
where: {
age: {
gt: 1
}
},
order: 'age ASC',
limit: 1
})
Please let me know if this is what you were going for or if you need some more support.

In ag grid drop down, how to show name once selected and on save set value instead of name.?

Using this reference, I had worked ag grid drop down.
Issue : once I selected a drop down value, then getvalue() returns value instead of name. Hence it shows the number on the column and it should be text.
If I change that to name, while saving, its bind to name . But here it should be value.
Required : getValue should return name & saving the array should contain value.
agInit(params: any): void {
this.params = params;
this.value = this.params.value;
this.name = this.params.name;
this.options = params.options;
}
getValue(): any {
return this.value;
}
ngAfterViewInit() {
window.setTimeout(() => {
this.input.element.nativeElement.focus();
})
}
stackbltiz here
here
How can I achieve this.
You don't have to create new cellRenderer and cellEditor for it, ag-grid provides inbuilt select for it. **
When you using objects (for dropdown\combobox) inside single cell - you have to implement value handlers: valueParser and valueFormatter:
Value parser: After editing cells in the grid you have the opportunity to parse the value before inserting it into your data. This is done using Value Parsers.
colDef.valueParser = (params) => {
return this.lookupKey(mapping, params.newValue);
}
Value formatter: Value formatters allow you to format values for display. This is useful when data is one type (e.g. numeric) but needs to be converted for human reading (e.g. putting in currency symbols and number formatting).
colDef.valueFormatter = (params) => {
return this.lookupValue(mapping, params.newValue);
}
*where mapping represents your object and inside each of those functions you are just extracting key or value.
Original solution:
lookupValue(mappings, key) {
return mappings[key];
}
lookupKey(mappings, name) {
var keys = Object.keys(mappings);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (mappings[key] === name) {
return key;
}
}
}
and here my little bit modified:
lookupValue(mappings, key:string) {
if(!mappings || !mappings.find(item => item.Id == key)) return null;
else
return mappings.find(item => item.Id == key).Value;
}
lookupKey(mappings, name) {
let key: any;
for (key in mappings) {
if (mappings.hasOwnProperty(key)) {
if (name === mappings[key]) {
return key.Id;
}
}
}
}
UPDATE
To populate dropdown you need yo use cellEditorParams:
colDef.cellEditor = 'selectCellEditor';
colDef.cellEditorParams = {
values: yourList,
},
** But in case when it could be required you still need to have both of renderers and store object inside, and then you would be able to choose what would be displayed on every stage.

SDK2: sorting custom column in a rally grid

I have a rally grid that shows defects. I want do add a column that shows the number of days a defect has been open.
I know can do that by adding a custom renderer in the column configs, but I would also like to sort on this column. Unfortunately, the renderer does not change the sorting of the column.
I think I might be able to use the convert() function on the store instead to create a new virtual column (in this case openAgeDays), but I'm not sure how to do this from the constructor--I presume I make some changes to storeConfig?
Does anyone have an example of how to use a convert function (assuming that this is the right way to do it) to add a new virtual, sortable column to a rally grid?
this.grid = this.add({
xtype: 'rallygrid',
model: model,
disableColumnMenus: false,
storeConfig: [...]
As is the answer in the duplicate, you can add a doSort to the column:
{dataIndex: 'Parent', name: 'Parent',
doSort: function(state) {
var ds = this.up('grid').getStore();
var field = this.getSortParam();
console.log('field',field);
ds.sort({
property: field,
direction: state,
sorterFn: function(v1, v2){
console.log('v1',v1);
console.log('v2',v2);
if (v1.raw.Parent) {
v1 = v1.raw.Parent.Name;
} else {
v1 = v1.data.Name;
}
if (v2.raw.Parent) {
v2 = v2.raw.Parent.Name;
} else {
v2 = v2.data.Name;
}
return v1.localeCompare(v2);
}
});
},
renderer: function(value, meta, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
meta.tdCls = 'invisible';
return record.data.Name;
}
}
},

How update datatable without render all the table again?

I´m working with datatables for a meteor app.
My problem is that when some fields change all the table is rendered again, if I´m on page two on the table or I order by field, the table is rendered again and I´m back on the beginning.
My code:
Template.adminpage.rendered = function() {
$('#userData').dataTable({
"bDestroy":true,
"aaSorting": [[ 0, "desc" ]],
"bAutoWidth":false,
"bFilter": false,
"aoColumns": [
{ "bVisible": false },
null,
null,
null,
null,
null,
null,
null
],
"aaData": Template.adminpage.arrayUsersAdmin()
});
}
Array that populates the table:
Template.adminpage.arrayUsersAdmin=function() {
var adminUsers = allUserData.find({roles: 'basic'});
var arrayUserAdmin = [];
var count=0;
adminUsers.forEach(function(user) {
var idColumn = user._id;
var dateColumn=moment(user.createdAt).format("MMM Do HH:mm");
var usernameColumn=username;
var emailColumn=email;
arrayUserAdmin[count]=[
idColumn,
dateColumn,
usernameColumn,
emailColumn
];
count++;
});
return arrayUserAdmin;
}
Collection on the server:
if(Meteor.users.find({_id: this.userId}, {roles: 'admin'})){
Meteor.publish("allUserData", function () {
var self = this;
var handle = Meteor.users.find({}).observeChanges({
added: function(id, fields){
self.added("allUsersCollection", id, fields);
},
changed: function(id, fields){
self.changed("allUsersCollection", id, fields);
},
removed: function(id){
self.removed("allUsersCollection", id);
}
});
self.ready();
this.onStop(function() {
handle.stop();
});
});
}
Thanks for your time.
You can pass reactive: false as an option to find, which disables the underlying addition of a dependency, like so:
Template.adminpage.arrayUsersAdmin=function() {
var adminUsers = allUserData.find({roles: 'basic'}, reactive: false);
// Your code
return arrayUserAdmin;
}
This behaviour is documented here
Alternatively, if you would like the individual fields to update, you will have to add them in yourself. To do this, you can use allUserDate.find({roles: 'basic'}).observe. This will require you, however, to edit the HTML directly, and is quite messy. A better alternative would be to change your table structure entirely - don't use a data table, use a vanilla HTML table, and sort the data with minimongo queries.
Regardless, you can use observe like so:
allUserData.find({roles: 'basic'}).observe({
changed: function(newDocument, oldDocument) {
// Update table
}
});