PrimeNG select datatable cell - primeng

I am working on a project using Angular 4 and PrimeNG where I need to be able to double click on a cell, selected it and open a dialog to do some modifications on the cell's underlying data.
As far as I can see from the documentation, currently there is no way to accomplish this. What is the best way to handle this situation?
Thanks.

So after some playing around I came up with a solution, which being far from perfect serves the purpose while we wait for the folks from PrimeNG (which I love, btw) to include this functionality.
The first issue was to determine which cell the user double-clicked on. I did that by having all column's templates in a div which I can get a reference to:
<p-dataTable #grd [value]="view"
(onRowDblclick)="editTemplate($event)"
(onRowClick)="clearSelection($event)">
<p-column field="SomeFieldName" header="Header" [editable]="false">
<ng-template let-col let-data="rowData" pTemplate="body">
<div [id]="col.field" class="cell-content">
<div [innerHTML]="data[col.field]" class="center-parent-screen"></div>
</div>
</ng-template>
</p-column>
All columns I am interested in handling on double click are wrapped in the div with class cell-content. Also notice the id attribute. It is set to match the field. Then in the onRowDblclick event:
editTemplate(e: any) {
let target = e.originalEvent.toElement.closest('div.cell-content');
if (target && target.id) {
let td = target.closest('td');
if (td) {
td.style.backgroundColor = 'darkorange';
td.style.color = 'white';
}
let fieldValue = e.data[target.id];
//do something with this data
}
}
The key here is the id attribute. Once we have that now we know which cell was clicked and we can proceed to do what we need to do. Also notice that I get a reference of the parent TD element and set the background and the color of the cell. Once you are finished working with it, you can clear the formatting to go back to normal.
You can also use the onRowClick event to clear the selection like so:
clearSelection(e: any) {
let target = e.originalEvent.toElement.closest('div.cell-content');
if (target && target.id) {
let td = target.closest('td');
if (td) {
td.style.backgroundColor = 'white';
td.style.color = 'black';
}
}
}
I know manipulating the DOM directly is not the way to go, but until we get the new version of PrimeNG that includes this functionality, this will do, at least for me.
Please let me know if you have a better way of doing this.

Related

ngx Datatable update header dynamically

I am using the component ngx-datatable in my angular app and I am trying to update the header texts dynamically.
What I was trying was the following:
<ngx-datatable-column prop="day_1" name="{{day_1_header}}">
and updating the day_1_header property dynamically, but when I do so the change is never reflected.
I have also tried adding a ViewChild and changing the name directly like so:
HTML:
<ngx-datatable-column #dataTable1 prop="day_1" name="{{day_1_header}}">
TS:
#ViewChild('dataTable1') dataTable1;
[..]
this.dataTable1.nativeElement.name = "test";
When I check the properties of my dataTable1 object the new name is set.
So can anyone tell me how to rerender/sync the datatable headers?
Thanks!
Damn...
Tried forever, asked the question and found a solution right away.
It worked by adding an explicit header-template to the column like this:
<ngx-datatable-column>
<ng-template let-column="column" ngx-datatable-header-template>
{{day_1_header}}
</ng-template>
</ngx-datatable-column>
Maybe it helps someone someday.
I have no idea why the other answer (which seems pretty direct and logical) didn't work for me. Maybe breaking change in higher version.
This GitHub issue gives another perspective on how to achieve it.
There's also this example in the source code that shows it.
Basically, you'll need the custom template for the column header
<ngx-datatable
class="material"
[rows]="rows"
[columns]="columns"
[columnMode]="ColumnMode.force"
[headerHeight]="50"
[footerHeight]="50"
rowHeight="auto"
>
</ngx-datatable>
<!-- custom column header template -->
<ng-template #hdrTpl let-column="column"> <strong>Fancy</strong>: {{ column.name }} !! </ng-template>
Then access it in your component class with #ViewChild() decorated property.
export class TemplateRefTemplatesComponent {
#ViewChild('hdrTpl', { static: true }) hdrTpl: TemplateRef<any>;
rows = [];
columns = [];
ColumnMode = ColumnMode;
constructor() {
}
ngOnInit() {
// You'll need to map over all columns to use it in all
this.columns = this.columns.map(columns => ({...columns, headerTemplate: this.hdrTpl});
}
}

Ask to confirm when changing tabs in angular bootstrap

I have tabs with forms and I want ask the user to confirm or discard their changes when changing tabs. My current code works
<uib-tab heading="..." index="3" deselect="main.onDeselect($event)" ... >
this.onDeselect = function($event) {
if(...isDirty...) {
if($window.confirm("Do you want to discard?")) {
... discard (and go to new tab) ...
} else {
$event.preventDefault(); //stays on current tab
}
}
}
The problem is I want to change confirm to javascript dialog and I will get result in callback.
I planed to preventDefault() all and then switch manually, but I cannot figure out where to get new tab id.
Any solution is appreciated. Even if it is easier in other tab implementations.
I use AngularJS v1.4.7, ui-bootstrap-tpls-1.3.3.min.js
You can make use of $selectedIndex and the active property for that purpose. See this Plunk
One thing to be noted here is that when we manually change the active property, it again fires the deselect event which needed to be handled. Otherwise it seems to do what you wanted.
Edit
Indeed as noted in the comments, the deselect carries the HTML index rather than what is passed in in the tab index property. A workaround could be in this: Another Plunk. Here I'm pulling the actual index from the HTML index.
And a little research indicates that this issue might as well be fixed already with 3.0 bootstrap tpl See this.
I spent some time with different approaches and this one is stable for some time. What I do is to prevent deselect at the beginning and set the new tab in callback if confirmed to loose changes...
this.onDeselect = function($event, $selectedIndex) {
var me = this;
if(this.tabs.eventDirty || this.tabs.locationDirty || this.tabs.contractDirty) {
$event.preventDefault();
var alert = $mdDialog.confirm({
title: 'Upozornění',
textContent: 'Na záložce jsou neuložené změny. Přejete si tyto změny zrušit a přejít na novou záložku?',
ok: 'Přijít o změny',
cancel: 'Zůstat na záložce'
});
$mdDialog
.show( alert )
.then(function() {
$rootScope.$emit("discardChanges");
me.tabs.activeTab = $selectedIndex;
})
}
};

Angularjs Dom Manipilation in a Table

i have a table where i can turn pages, you can choose a color for a user and that color is shown in the circle, but when i turn one page, the color is gone!
I read about dom manipluation in directives, but that still didnt solve my problem:
the tutorials mostly show one with a click funktion, and i dont to click the circle
they also werent "permanent"
maybe i did something wrong? please can someone help or give me a hint?
i made also a plnkr :
Here's the link!
You need to save chosen color to currect user object. Maybe like this:
$scope.showColorPicker = function(user) {
data = $scope.colors;
dlg = $dialogs.create('/dialogs/pickColor.html','pickColorCtrl',$scope.colors,{},{key:false ,back:'static'});
dlg.result.then(function(data) {
var colnr = data;
var user_circle = angular.element(document.getElementById('color_' + user.id));
user_circle.context.style.backgroundColor = $scope.colors[colnr-1].color;
user.color = $scope.colors[colnr-1];
});
};
HTML for color circle:
<span class="smallcircle" ng-bind="color_{{user.id}}" id="color_{{user.id}}" name="color_{{user.id}}" style="background-color: {{user.color.color || 'lightgray'}};"></span>
Make sure you pass user object to showColorPicker function:
Change Color
Demo: http://plnkr.co/edit/em0ZUHjbXUNa7MYgpC5f?p=info

NatTable - need checkbox only when editable

I am new to NatTable. I have gone thorough the NatTable examples and its source code but am not getting a solution to one of my problems.
In the NatTable I have a column that should provide a checkbox for selection depending on the value of another column.
I have used Checkboxpainter, checkboxcelleditor, the defaultbooleanconverter and IEditableRule. This renders a checkbox irrespective of whether the cell is editable or not though it allows me to mark the checkbox only if it is enabled.
However as per our requirement user should not see the checkbox if the row is not selectable. or in worst case a disabledcheckbox should be rendered for rows that are not selectable.
Can someone please help me out?
Thanks and regards,
Pradyumna
Got a solution for this.
I had to write a custom checkboxpainter (inheriting from the one that is available OOTB) and override its getImage method to return null for appropriate cells
There is a better solution which I have just applied to a similar case in my work.
I did it by adding the following configuration to the table:
// make checkbox cells editable
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE, DisplayMode.EDIT, CONFIG_LABEL_CHECKBOX);
// register the checkbox editor for DisplayMode.EDIT
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new CheckBoxCellEditor(), DisplayMode.EDIT, CONFIG_LABEL_CHECKBOX);
// register the checkbox painter for DisplayMode.NORMAL
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new CheckBoxPainter(), DisplayMode.NORMAL, CONFIG_LABEL_CHECKBOX);
// register the painter for empty cells in DisplayMode.NORMAL
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new BackgroundPainter(), DisplayMode.NORMAL, CONFIG_LABEL_EMPTY);
Basically, this introduces the configuration labels CONFIG_LABEL_CHECKBOX for an editable checkbox, and CONFIG_LABEL_EMPTY for an empty cell.
Now all you have to do is to attach an IConfigLabelAccumulator to your bodyDataLayer:
bodyDataLayer.setConfigLabelAccumulator(new IConfigLabelAccumulator()
{
public void accumulateConfigLabels(LabelStack configLabels, int columnPosition, int rowPosition)
{
if(columnPosition == CHECKBOX_COLUMN_INDEX)
{
if(someCodeToCheckIfRowIsEditable(rowPosition))
{
configLabels.add(CONFIG_LABEL_CHECKBOX);
}
else
{
configLabels.add(CONFIG_LABEL_EMPTY);
}
}
}
}

ExtJS: Added grid rows wont de-highlight

When adding a rows to a grid, and then clicking on it, it gets selected (and highlighted). Then, clicking elsewhere but the new row remains highlighted (so now there are to highlighted rows).
Please, does anyone know what the problem could be? How to make it behave normally, i.e. clicking a row deselects (de-highlights) the other one?
After I reload the page (so the new row is not new anymore), everything works as expected.
Edit: Here's the code for adding rows:
var rec = new store.recordType({
test: 'test'
});
store.add(rec);
Edit 2: The problem seems to be listful: true. If false, it works! But I need it to be true so I'm looking at this further... It looks like as if the IDs went somehow wrong... If the ID would change (I first create the record and then the server returns proper ID, that would also confuse the row selector, no?)
(Note, correct as ExtJS 3.3.1)
First of all, this is my quick and dirty hack. Coincidentally I have my CheckboxSelectionModel extended in my system:-
Kore.ux.grid.CheckboxSelectionModel = Ext.extend(Ext.grid.CheckboxSelectionModel, {
clearSelections : function(fast){
if(this.isLocked()){
return;
}
if(fast !== true){
var ds = this.grid.store,
s = this.selections;
s.each(function(r){
//Hack, ds.indexOfId(r.id) is not correct.
//Inherited problem from Store.reader.realize function
this.deselectRow(ds.indexOf(r));
//this.deselectRow(ds.indexOfId(r.id));
}, this);
s.clear();
}else{
this.selections.clear();
}
this.last = false;
}
});
And this is the place where the clearSelections fails. They try to deselect rows by using ds.indexOfId(r.id) and it will returns -1 because we do not have the index defined remapped.
And this is why we can't find the id:-
http://imageshack.us/photo/my-images/864/ssstore.gif/
Note that the first item in the image is not properly "remapped". This is because we have a problem in the "reMap" function in our Ext.data.Store, read as follow:-
// remap record ids in MixedCollection after records have been realized. #see Store#onCreateRecords, #see DataReader#realize
reMap : function(record) {
if (Ext.isArray(record)) {
for (var i = 0, len = record.length; i < len; i++) {
this.reMap(record[i]);
}
} else {
delete this.data.map[record._phid];
this.data.map[record.id] = record;
var index = this.data.keys.indexOf(record._phid);
this.data.keys.splice(index, 1, record.id);
delete record._phid;
}
}
Apparently, this method fails to get fired (or buggy). Traced further up, this method is called by Ext.data.Store.onCreateRecords
....
this.reader.realize(rs, data);
this.reMap(rs);
....
It does look fine on the first look, but when I trace rs and data, these data magically set to undefined after this.reader.realize function, and hence reMap could not map the phantom record back to the normal record.
I don't know what is wrong with this function, and I don't know how should I overwrite this function in my JsonReader. If any of you happen to be free, do help us trace up further for the culprit that causes this problem
Cheers
Lionel
Looks like to have multi select enabled for you grid. You can configure the selection model of the grid by using the Ext.grid.RowSelectionModel.
Set your selection model to single select by configuring the sm (selection model) in grid panel as show below:
sm: new Ext.grid.RowSelectionModel({singleSelect:true})
Update:
Try reloading the grid using the load method or loadData method of the grid's store. Are you updating the grid on the client side? then maybe you can use loadData method. If you are using to get data from remote.. you can use load method. I use load method to update my grid with new records (after some user actions like add,refresh etc). Or you could simply reload as follows:
grid.getStore().reload();

Resources