applyTransaction remove not working with id - ag-grid

I'm using ag-grid in Angular9 project. I'm using Transactions to do CRUD operations in grid when my backend request resolve. I need to provide RowNodeId myself, i dont want to use object-references as i have large data set.
Thing is, i've provided the ID and i can add/update item in the grid but i'm unable to delete the item. In Doc it mentions, you only need to provide id to remove the item but i'm getting the following error.
Here's the code.
class HostAppListPage
{
#ViewChild('agGrid', {static: true}) grid:AgGridAngular;
constructor()
{
}
ngOnInit()
{
this.grid.getRowNodeId = (data) => {
return data.entityId;
};
this.columns = [
{headerName: 'App Name', field: 'name', rowDrag: true, headerCheckboxSelection: true, checkboxSelection: true},
{headerName: 'App Id', field: 'id'},
{headerName: 'Compatibility', field: COMPATIBILITY'},
{headerName: 'Creation', field: 'createdAtToString'},
{headerName: 'Last Update', field: 'updatedAtToString'}
];
}
deleteRow()
{
let ids = this.gridApi.getSelectedNodes()
// .map((row) => {
// return {id: row.entityId}
// return row.entityId;
// });
console.log(ids);
this.grid.api.applyTransaction({remove: ids});
}
I tried both with and without map statement, nothing worked
but my Add and Update works fine.

Replace map with following code.
.map((row) => {
return {entityId: row.data.entityId};
});
it should be the the same field (entityId) which i set in getRowNodeId function.

In a typical situation, where one does not define a getRowNodeId, one should be able to do:
const removeData: any[] = [{id: rowNode0.id}, {id: rowNode1.id}, ...];
applyTransaction({remove: removeData});
where rowNode0, rowNode1, etc. are the nodes you want to remove.
However when you provide your own getRowNodeId callback, ag-grid will fetch the id's by applying your callback on the data you provided. Therefore, the name(s) in the data must match those used in your callback. That's why return {id: row.entityId} doesn't work, but return {entityId: row.entityId} does.
In other words, if one defines:
this.grid.getRowNodeId = (data) => {
return data.column1 + data.column5 + data.column2;
};
Then one would need to provide
const removeData: any[] = [
{column1: 'a1', column2: 'b1', column5: 'c1'},
{column1: 'a2', column2: 'b2', column5: 'c2'},
{column1: 'a3', column2: 'b3', column5: 'c3'},
];
so that ag-grid would have all the names it needs to find the id's via the given getRowNodeId.

Related

Can't change the pagination 'next' and 'prev' labels to my language in grid.js

There is no such option as change the prev and next button label in the documentation, and when i try to use string replacement or change the button innerHTML via Javascript, it doesn't work, is there any way that I can safely change the label?
You can use the language config (added since v1.5.0) to customize this:
new Grid({
columns: ['Name', 'Email', 'Title'],
sort: true,
search: true,
pagination: {
limit: 5
},
data: Array(50).fill().map(x => [
faker.name.findName(),
faker.internet.email(),
faker.name.title(),
]),
language: {
'search': {
'placeholder': '🔍 Search...'
},
'pagination': {
'previous': '⬅️',
'next': '➡️',
'showing': '😃 Displaying'
}
}
});
Also see this example: https://gridjs.io/docs/examples/i18n/

ExtJS MultiSelect Edit - Not working for multi value selection

I have a GridEditPanel where the 1st column is a combobox with multiSelect. The values are being loaded correctly from the DB and is being written in the DB correctly as well. In the event where the the combobox has a single value, the drop-down highlights the value correctly as well.
The issue is when the combobox has multiple values, it displays the values correctly, however during edit the multiple values are not selected.
Model:
extend: 'Ext.data.Model',
idProperty: 'contactTypeID',
fields: [
{
name: 'contactTypeID',
type: 'string'
},
{
name: 'contactType',
type: 'string'
}
],
View GridEditPanel
emptyText: "There are no contacts.",
insertErrorText: 'Please finish editing the current contact before inserting a new record',
addButtonText: 'Add Contact',
itemId: 'contacts',
viewConfig: {
deferEmptyText: false
},
minHeight: 130,
initComponent: function () {
var me = this,
contactTypes;
// Creating store to be referenced by column renderer
contactTypes = Ext.create('Ext.data.Store', {
model: '********',
autoLoad: true,
listeners: {
load: function () {
me.getView().refresh();
}
}
});
this.columns = [
{
text: 'Contact Role',
dataIndex: 'contactRoleID',
flex: 1,
renderer: function (value) {
// Lookup contact type to get display value
//If a contact has multiple roles, use split by ',' to find display values.
if (value.includes(',')) {
var a = value.split(','), i, contTypeIds = [];
var contTypes = new Array();
for (i = 0; i < a.length; i++) {
contTypeIds.push(a[i]);
contTypes.push(contactTypes.findRecord('contactTypeID', a[i], 0, false, false, true).get('contactType'));
}
console.log('Multi Render Return Value: ' + contTypes);
return contTypes;
}
else {//if not a contact will only have one role.
var rec = contactTypes.findRecord('contactTypeID', value, 0, false, false, true); // exact match
console.log('Single Render Return Value: ' + rec.get('contactType'));
return rec ? rec.get('contactType') : '<span class="colselecttext">Required</span>';
}
},
align: 'center',
autoSizeColumn: true,
editor: {
xtype: 'combobox',
store: contactTypes,
multiSelect: true,
delimiter: ',',
forceSelection: true,
queryMode: 'local',
displayField: 'contactType',
valueField: 'contactTypeID',
allowBlank: false
}
},
I cannot see the model of GridEditPanel, but I assume you are using the wrong field type, string instead of array (Have a look at the converter function, maybe it will help you to fix the problem). I wrote a small post in my blog about multiSelect combobox editor in editable grid. The sample works with v4.2
Hope it will help you to fix the bug.

MongoDB - "The dollar ($) prefixed field \'$$hashKey\' in \'fieldName".$$hashKey\' is not valid for storage.'"

While trying to update a document I'm getting the above error for the field timesToDisplay.
MongoDB version 2.6.7.
The whole model:
msg = {
'name': '',
'template': '',
'displayDurInMilliSec': 0,
'timesToDisplay': [],
'images': [],
'texts': [],
'screen': []
}
I guess I will be getting the same error with the other 3 array fields.
I've tried using $set but sill getting the same error.
The code:
function updateMessage(msg) {
var conditions = {_id: msg._id}
, update = { 'name': msg.name,
'template': msg.template,
'displayDurInMilliSec': msg.displayDurInMilliSec,
'timesToDisplay': msg.timesToDisplay,
'images': msg.images,
'texts': msg.texts,
'screen': msg.screen
}
messageModel.update(conditions, update, callback);
function callback(err, numAffected) {
if (!err) console.log(numAffected)
else console.log(err)
}
}
EDIT: The msg parameter is a document in itself:
{ _id: '557d58abd54955480db6694f',
name: 'msg99',
timesToDisplay: [ { startDate: '2015-06-19T21:00:00.000Z',
'$$hashKey': 'object:214',
endDate: '2015-06-25T21:00:00.000Z',
daysOfTheWeek: [Object],
startTimeOfDay: '11',
endTimeOfDay: '13' } ],
images: [],
texts: [],
screen: [ 1 ],
'$$hashKey': 'object:54',
displayDurInMilliSec: '40189',
template: 'templates/Template2.html' }
The $$hashkey field is added by AngularJS when working with ngRepeat or ngOptions. In the case of ngRepeat you can change the repeat string by appending track by $index to it. For using ngOptions you'll have to filter out that field yourself. AngularJS provides a quick solution for filtering it out: angular.toJson. This will filter out all fields prefixed with two dollar signs. Check out the documentation.
I realize that this isn't a MongoDB answer, but this specific error ($$hashkey), is usually due to AngularJS.

Sencha ExtJS RESTful grid example confusion

I am very confused by the Sencha documentation for ExtJS. The documentation begins with a Getting Started guide which highlights and illustrates the importance on a suitable structure for the classes and source code of your application. But the provided examples then break all the conventions laid down by the Getting Started guide. Instead of code being broken down into appropriate Model, Store, View, etc. class files the examples are provided as a single file with example source code which is not easily re-usable in separate source files.
I started by following the Portal example (http://docs.sencha.com/ext-js/4-1/#!/example/portal/portal.html) as this is the sort of application I want to create. I wanted to enhance the Portal example and add in a screen which would display a grid and use a RESTful web service as the data backend. I have created the backend I just want to create the front-end. So I looked at the RESTful example (http://docs.sencha.com/ext-js/4-1/#!/example/restful/restful.html)
I have tried to copy the RESTful example into the recommended pattern of seperate classes e.g. Model, Store, View:
Model:
Ext.define('MyLodge.model.Member', {
extend: 'Ext.data.Model',
fields: [
{name: 'name', type: 'string'},
{name: 'email', type: 'string'},
{name: 'href', type: 'string'}
]
});
Store:
Ext.require('MyLodge.model.Member');
Ext.define('MyLodge.store.Members', {
autoLoad: true,
autoSync: true,
model: 'MyLodge.model.Member',
proxy: {
type: 'rest',
url: 'http://localhost:8888/rest/memberapi/members' ,
reader: {
type: 'json',
root: 'data'
},
writer: {
type: 'json'
}
},
listeners: {
write: function(store, operation){
var record = operation.getRecords()[0],
name = Ext.String.capitalize(operation.action),
verb;
if (name == 'Destroy' ) {
record = operation.records[0];
verb = 'Destroyed';
} else {
verb = name + 'd';
}
Ext.example.msg(name, Ext.String.format( "{0} member: {1}", verb, record.getId()));
}
}
});
View:
Ext.define('MyLodge.view.content.MemberGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.membergrid',
initComponent: function(){
var store = Ext.create('MyLodge.store.Members' );
Ext.apply( this, {
height: this.height,
store: store,
stripeRows: true,
columnLines: true,
columns: [{
id : 'name',
text : 'Name',
flex: 1,
sortable : true,
dataIndex: 'name'
},{
text : 'E-Mail',
width : 150,
sortable : true,
dataIndex: 'email'
},{
text : 'Href',
width : 200,
sortable : true,
dataIndex: 'href'
}],
dockedItems: [{
xtype: 'toolbar',
items: [{
text: 'Add',
iconCls: 'icon-add',
handler: function(){
// empty record
store.insert(0, new MyLodge.model.Member());
rowEditing.startEdit(0, 0);
}
}, '-', {
itemId: 'delete',
text: 'Delete',
iconCls: 'icon-delete',
disabled: true,
handler: function(){
var selection = grid.getView().getSelectionModel().getSelection()[0];
if (selection) {
store.remove(selection);
}
}
}]
}]
});
this.callParent(arguments);
}
});
But I am not sure where to put the code to control the grid row selection and enable the Delete button:
grid.getSelectionModel().on('selectionchange', function(selModel, selections){
grid.down('#delete').setDisabled(selections.length === 0);
});
Also when I press the Add button I get the following error:
Uncaught TypeError: Object [object Object] has no method 'insert'.
Any help would be appreciated.
You are having scoping issues. Basically the variable store is defined only in the initComponent function and therefore of local function scope.
Your handler function has it's own scope. It is firing in the scope of the toolbar button. So if you say this in the handler it would refer to the button. Hence you can say this.up('panel').store - and that gives you the correct reference to the store backing your grid panel.
Another advice is not to implement everything at once. Write a little bit to see if it works and then add to it little by little.
RE: the docs examples, I agree that it's frustrating, but there's not many options. Having a fully-MVC-style implementation of each example would not only be onerous to produce, but would also probably make point of the example get lost in the structure.
RE: your question about the where to "put" the code to control the grid, I would recommend setting up a controller with listeners for the events on the grid in the control() section. This will let you decouple the handling of the events that are fired by your grid from the view itself.

Sencha touch 2 filterby() not updating records

I have a nested list on one of the pages of a Tabbed Panel app that is pulling data from "offices.json"
I should like to be able to filter this list when a user clicks on a toolbar button. However my filterBy() function doesn't update the store and the list of offices I can see, even though I can see in the console it is iterating the records and finding a match. What am I doing wrong?
(And yes I have tried doing s.load() both before and after the filterBy to no avail!)
toolbar:{
items:[{
text: 'Near you',
id: 'btnNearYou',
xtype: 'button',
handler: function() {
s = Ext.StoreMgr.get('offices');
s._proxy._url = 'officesFLAT.json';
console.log("trying to filter");
s.filterBy(function(record) {
var search = new RegExp("Altrincham", 'i');
if(record.get('text').match(search)){
console.log("did Match");
return true;
}else {
console.log("didnt Match");
return false;
}
});
s.load();
}
}]
For the record I'm defining my store like so:
store: {
type: 'tree',
model: 'ListItem',
id: 'offices',
defaultRootProperty: 'items',
proxy: {
type: 'ajax',
root: {},
url: 'offices.json',
reader: {
type: 'json',
rootProperty: 'items'
}
}
}
No need to recreate the regex each time, cache it outside.
You can simplify the code a lot (see below).
Why are you calling load directly after? That's going to send it to the server and it will just retrieve the same dataset.
toolbar: {
items: [{
text: 'Near you',
id: 'btnNearYou',
xtype: 'button',
handler: function() {
s = Ext.StoreMgr.get('offices');
s._proxy._url = 'officesFLAT.json';
var search = /Altrincham/i;
s.filterBy(function(record) {
return !!record.get('text').match(search);
});
}
}]
}