Closed mtrzensky closed 3 years ago
Sorry for the delay, here is a repo with an example: https://github.com/mtrzensky/angular-datatables-ngtemplateref-bug
To reproduce:
Is this description and the repo sufficient for you to see my issue?
Big confirmed :)
@mtrzensky could you confirm if #1578 fixed it? I'm placing the PR as a draft until the fix is confirmed.
@shanmukhateja I will be able to investigate the fix early August, then I will test it and tell you :-) Thanks for your support!
@mtrzensky is the issue fixed?
@shanmukhateja Sorry for reaching out late. I will test the fix this week and tell you if the issue is resolved
@shanmukhateja I have problems installing your fork/commit. I tried using:
The package doesn't seem to be built locally. I get an "angular-datatables" folder within node_modules only with schematics and no "src" folder. This results in the app missing the "angular-datatables" package (imports fail)
I also wanted to copy paste the code snipped but this doesn't seem to be compatible since your file is a ".ts" file and mine from "angular-datatables: 12.0.0" only contains the ".js" files with TypeScript definition files on top. What did I do wrong?
Hi @mtrzensky
If you look at https://github.com/l-lin/angular-datatables/pull/1578/files you'll need to update the node_modules/angular-datatables/angular-datatables.directive.js
file.
It could be because of as any
in line 77. I don't see any other TS specific code so it should work.
Hope that helps :)
Hey @shanmukhateja
Unfortunately this has not helped me :(
I tried the following:
The guide mentions that old versions may crash the "npm build". My node version: v16.4.0 My npm version: 7.18.1
Errors:
> angular-datatables@12.0.0 build
> npm run clean && npm run compile && npm run bundles && npm run schematics:build
> angular-datatables@12.0.0 clean
> rimraf -f index.{d.ts,js,js.map,metadata.json} src/*.{d.ts,js,map,metadata.json} bundles schematics/**/*.{d.ts,js,map}
> angular-datatables@12.0.0 compile
> npm run lint:code && ngc -p tsconfig-build.json
> angular-datatables@12.0.0 lint:code
> tslint ./src/**/*.ts -t verbose --exclude ./src/**/*.d.ts
angular-whitespace is deprecated. Use a formatter like Prettier for formatting purposes.
node_modules/@types/jasmine/index.d.ts:34:18 - error TS2300: Duplicate identifier 'describe'.
34 declare function describe(description: string, specDefinitions: () => void): void;
~~~~~~~~
../../node_modules/@types/mocha/index.d.ts:2615:13
2615 declare var describe: Mocha.SuiteFunction;
~~~~~~~~
'describe' was also declared here.
node_modules/@types/jasmine/index.d.ts:48:18 - error TS2300: Duplicate identifier 'xdescribe'.
48 declare function xdescribe(description: string, specDefinitions: () => void): void;
~~~~~~~~~
../../node_modules/@types/mocha/index.d.ts:2636:13
2636 declare var xdescribe: Mocha.PendingSuiteFunction;
~~~~~~~~~
'xdescribe' was also declared here.
node_modules/@types/jasmine/index.d.ts:57:18 - error TS2300: Duplicate identifier 'it'.
57 declare function it(expectation: string, assertion?: jasmine.ImplementationCallback, timeout?: number): void;
~~
../../node_modules/@types/mocha/index.d.ts:2650:13
2650 declare var it: Mocha.TestFunction;
~~
'it' was also declared here.
node_modules/@types/jasmine/index.d.ts:73:18 - error TS2300: Duplicate identifier 'xit'.
73 declare function xit(expectation: string, assertion?: jasmine.ImplementationCallback, timeout?: number): void;
~~~
../../node_modules/@types/mocha/index.d.ts:2671:13
2671 declare var xit: Mocha.PendingTestFunction;
~~~
'xit' was also declared here.
node_modules/@types/jasmine/index.d.ts:101:18 - error TS2300: Duplicate identifier 'beforeEach'.
101 declare function beforeEach(action: jasmine.ImplementationCallback, timeout?: number): void;
~~~~~~~~~~
../../node_modules/@types/mocha/index.d.ts:2581:13
2581 declare var beforeEach: Mocha.HookFunction;
~~~~~~~~~~
'beforeEach' was also declared here.
node_modules/@types/jasmine/index.d.ts:108:18 - error TS2300: Duplicate identifier 'afterEach'.
108 declare function afterEach(action: jasmine.ImplementationCallback, timeout?: number): void;
~~~~~~~~~
../../node_modules/@types/mocha/index.d.ts:2599:13
2599 declare var afterEach: Mocha.HookFunction;
~~~~~~~~~
'afterEach' was also declared here.
../../node_modules/@types/jasminewd2/index.d.ts:10:18 - error TS2300: Duplicate identifier 'it'.
10 declare function it(expectation: string, assertion?: (done: DoneFn) => Promise<void>, timeout?: number): void;
~~
../../node_modules/@types/mocha/index.d.ts:2650:13
2650 declare var it: Mocha.TestFunction;
~~
'it' was also declared here.
../../node_modules/@types/jasminewd2/index.d.ts:12:18 - error TS2300: Duplicate identifier 'xit'.
12 declare function xit(expectation: string, assertion?: (done: DoneFn) => Promise<void>, timeout?: number): void;
~~~
../../node_modules/@types/mocha/index.d.ts:2671:13
2671 declare var xit: Mocha.PendingTestFunction;
~~~
'xit' was also declared here.
../../node_modules/@types/jasminewd2/index.d.ts:13:18 - error TS2300: Duplicate identifier 'beforeEach'.
13 declare function beforeEach(action: (done: DoneFn) => Promise<void>, timeout?: number): void;
~~~~~~~~~~
../../node_modules/@types/mocha/index.d.ts:2581:13
2581 declare var beforeEach: Mocha.HookFunction;
~~~~~~~~~~
'beforeEach' was also declared here.
../../node_modules/@types/jasminewd2/index.d.ts:14:18 - error TS2300: Duplicate identifier 'afterEach'.
14 declare function afterEach(action: (done: DoneFn) => Promise<void>, timeout?: number): void;
~~~~~~~~~
../../node_modules/@types/mocha/index.d.ts:2599:13
2599 declare var afterEach: Mocha.HookFunction;
~~~~~~~~~
'afterEach' was also declared here.
../../node_modules/@types/mocha/index.d.ts:2581:13 - error TS2300: Duplicate identifier 'beforeEach'.
2581 declare var beforeEach: Mocha.HookFunction;
~~~~~~~~~~
node_modules/@types/jasmine/index.d.ts:101:18
101 declare function beforeEach(action: jasmine.ImplementationCallback, timeout?: number): void;
~~~~~~~~~~
'beforeEach' was also declared here.
../../node_modules/@types/jasminewd2/index.d.ts:13:18
13 declare function beforeEach(action: (done: DoneFn) => Promise<void>, timeout?: number): void;
~~~~~~~~~~
and here.
../../node_modules/@types/mocha/index.d.ts:2599:13 - error TS2300: Duplicate identifier 'afterEach'.
2599 declare var afterEach: Mocha.HookFunction;
~~~~~~~~~
node_modules/@types/jasmine/index.d.ts:108:18
108 declare function afterEach(action: jasmine.ImplementationCallback, timeout?: number): void;
~~~~~~~~~
'afterEach' was also declared here.
../../node_modules/@types/jasminewd2/index.d.ts:14:18
14 declare function afterEach(action: (done: DoneFn) => Promise<void>, timeout?: number): void;
~~~~~~~~~
and here.
../../node_modules/@types/mocha/index.d.ts:2615:13 - error TS2300: Duplicate identifier 'describe'.
2615 declare var describe: Mocha.SuiteFunction;
~~~~~~~~
node_modules/@types/jasmine/index.d.ts:34:18
34 declare function describe(description: string, specDefinitions: () => void): void;
~~~~~~~~
'describe' was also declared here.
../../node_modules/@types/mocha/index.d.ts:2636:13 - error TS2300: Duplicate identifier 'xdescribe'.
2636 declare var xdescribe: Mocha.PendingSuiteFunction;
~~~~~~~~~
node_modules/@types/jasmine/index.d.ts:48:18
48 declare function xdescribe(description: string, specDefinitions: () => void): void;
~~~~~~~~~
'xdescribe' was also declared here.
../../node_modules/@types/mocha/index.d.ts:2650:13 - error TS2300: Duplicate identifier 'it'.
2650 declare var it: Mocha.TestFunction;
~~
node_modules/@types/jasmine/index.d.ts:57:18
57 declare function it(expectation: string, assertion?: jasmine.ImplementationCallback, timeout?: number): void;
~~
'it' was also declared here.
../../node_modules/@types/jasminewd2/index.d.ts:10:18
10 declare function it(expectation: string, assertion?: (done: DoneFn) => Promise<void>, timeout?: number): void;
~~
and here.
../../node_modules/@types/mocha/index.d.ts:2671:13 - error TS2300: Duplicate identifier 'xit'.
2671 declare var xit: Mocha.PendingTestFunction;
~~~
node_modules/@types/jasmine/index.d.ts:73:18
73 declare function xit(expectation: string, assertion?: jasmine.ImplementationCallback, timeout?: number): void;
~~~
'xit' was also declared here.
../../node_modules/@types/jasminewd2/index.d.ts:12:18
12 declare function xit(expectation: string, assertion?: (done: DoneFn) => Promise<void>, timeout?: number): void;
~~~
and here.`
So I can't compile the cloned project for some reason and according to the stated versions I should have a compatible compile environment.
Maybe the tslint files are outdated due to changes to angular types? Even if I disable the linting part, I still get more ts linting errors. The list is very long so if you want it posted I can hand that in another comment. Is this another issue?
Hi,
Could you downgrade to NodeJS 12 and NPM v6? Maybe this is why the build's failing? Opinion: NodeJS 14+ and NPM6 are known to cause problems sometimes.
In my previous message I meant patching the js
file relatively at <your_web_app>/node_modules/angular-datatatables/<ivy something folder>/
followed by the directive js's file.
Hi,
I have some good news and some bad news. Good one's first:
Bad news:
Interesting.
I suspect we aren't synchronised to column visibility changes.
I'll update this post once I figure it out.
Hi @mtrzensky
I'm unable to reproduce the issue.
Here's what I did:
<project_dir>/node_modules/angular-datatables/__ivy_ngcc__/src/angular-datatables.directive.js
. (This code is rebased from master branch)./**
* @license
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://raw.githubusercontent.com/l-lin/angular-datatables/master/LICENSE
*/
import { Directive, ElementRef, Input, Renderer2, ViewContainerRef } from '@angular/core';
import { Subject } from 'rxjs';
import * as ɵngcc0 from '@angular/core';
var DataTableDirective = /** @class */ (function () {
function DataTableDirective(el, vcr, renderer) {
this.el = el;
this.vcr = vcr;
this.renderer = renderer;
/**
* The DataTable option you pass to configure your table.
*/
this.dtOptions = {};
}
DataTableDirective.prototype.ngOnInit = function () {
var _this = this;
if (this.dtTrigger) {
this.dtTrigger.subscribe(function (options) {
_this.displayTable(options);
});
}
else {
this.displayTable(null);
}
};
DataTableDirective.prototype.ngOnDestroy = function () {
if (this.dtTrigger) {
this.dtTrigger.unsubscribe();
}
if (this.dt) {
this.dt.destroy(true);
}
};
DataTableDirective.prototype.displayTable = function (dtOptions) {
var _this = this;
// assign new options if provided
if (dtOptions) {
this.dtOptions = dtOptions;
}
this.dtInstance = new Promise(function (resolve, reject) {
Promise.resolve(_this.dtOptions).then(function (resolvedDTOptions) {
// validate object
var isTableEmpty = Object.keys(resolvedDTOptions).length === 0 && $('tbody tr', _this.el.nativeElement).length === 0;
if (isTableEmpty) {
reject('Both the table and dtOptions cannot be empty');
return;
}
// Using setTimeout as a "hack" to be "part" of NgZone
setTimeout.call(_this, function () {
// Assign DT properties here
var options = {
rowCallback: function (row, data, index) {
if (resolvedDTOptions.columns) {
// `colVis` extension support
// See: https://github.com/l-lin/angular-datatables/issues/1576
var visibleTableColumns_1 = _this.dt.columns().visible().toArray();
var columns = resolvedDTOptions.columns.filter(function (_, i) { return visibleTableColumns_1[i]; });
// Apply transforms
_this.applyNgPipeTransform(row, columns);
_this.applyNgRefTemplate(row, columns, data);
// run user specified row callback if provided.
if (resolvedDTOptions.rowCallback) {
resolvedDTOptions.rowCallback(row, data, index);
}
}
}
};
// merge user's config with ours
options = Object.assign({}, resolvedDTOptions, options);
_this.dt = $(_this.el.nativeElement).DataTable(options);
resolve(_this.dt);
});
});
});
};
DataTableDirective.prototype.applyNgPipeTransform = function (row, columns) {
// Filter columns with pipe declared
var colsWithPipe = columns.filter(function (x) { return x.ngPipeInstance && !x.ngTemplateRef; });
colsWithPipe.forEach(function (el) {
var pipe = el.ngPipeInstance;
// find index of column using `data` attr
var i = columns.findIndex(function (e) { return e.data === el.data; });
// get <td> element which holds data using index
var rowFromCol = row.childNodes.item(i);
// Transform data with Pipe
var rowVal = $(rowFromCol).text();
var rowValAfter = pipe.transform(rowVal);
// Apply transformed string to <td>
$(rowFromCol).text(rowValAfter);
});
};
DataTableDirective.prototype.applyNgRefTemplate = function (row, columns, data) {
var _this = this;
// Filter columns using `ngTemplateRef`
var colsWithTemplate = columns.filter(function (x) { return x.ngTemplateRef && !x.ngPipeInstance; });
colsWithTemplate.forEach(function (el) {
var _a = el.ngTemplateRef, ref = _a.ref, context = _a.context;
// get <td> element which holds data using index
var i = columns.findIndex(function (e) { return e.data === el.data; });
var cellFromIndex = row.childNodes.item(i);
// render onto DOM
// finalize context to be sent to user
var _context = Object.assign({}, context, context === null || context === void 0 ? void 0 : context.userData, {
adtData: data
});
var instance = _this.vcr.createEmbeddedView(ref, _context);
_this.renderer.appendChild(cellFromIndex, instance.rootNodes[0]);
});
};
DataTableDirective.ctorParameters = function () { return [
{ type: ElementRef },
{ type: ViewContainerRef },
{ type: Renderer2 }
]; };
DataTableDirective.propDecorators = {
dtOptions: [{ type: Input }],
dtTrigger: [{ type: Input }]
};
DataTableDirective.ɵfac = function DataTableDirective_Factory(t) { return new (t || DataTableDirective)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ElementRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ViewContainerRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.Renderer2)); };
DataTableDirective.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: DataTableDirective, selectors: [["", "datatable", ""]], inputs: { dtOptions: "dtOptions", dtTrigger: "dtTrigger" } });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(DataTableDirective, [{
type: Directive,
args: [{
selector: '[datatable]'
}]
}], function () { return [{ type: ɵngcc0.ElementRef }, { type: ɵngcc0.ViewContainerRef }, { type: ɵngcc0.Renderer2 }]; }, { dtOptions: [{
type: Input
}], dtTrigger: [{
type: Input
}] }); })();
return DataTableDirective;
}());
export { DataTableDirective };
//# sourceMappingURL=angular-datatables.directive.js.map
npm run start
and open http://localhost:4200
ngTemplateRef
buttons rendered.What do you see?
Hi, I will test it eod or tomorrow and then tell you my observations. I will test it against the testcase project listed here and the real project I'm working in to verify each observations
Regarding your last ticket: The difference with my observation was that I tested an older version before the refactoring of that file. I have to update it first and then patch it. I will post results later.
@shanmukhateja
I reproduced your steps as you have told with the exact copied code and made following observations:
4a) If I do it exactly like you did, it works:
4b) But what I meant happens (the stated bug with no rendered button), when I do it this way:
It seems the button won't get rendered when the column initially is not loaded (i.e. due to a page refresh)
Hi @mtrzensky
bug confirmed. Let me see if I can work something out this weekend :)
@mtrzensky I checked the documentation of ColVis and I noticed the extension is marked as legacy.
After discussing with @l-lin it's been decided we don't provide support for legacy extensions.
According to DataTables authors, it is recommended to use Buttons extension. See here
As such, I'm closing this issue as well as the draft PR. Sorry for the inconvenience :(
@shanmukhateja Alright. I changed colvis with "columnsToggle" and get the same result. Shall I open another issue so the context is seperated from this legacy context? I can also update the issue showcase, if you want.
@mtrzensky yes and yes - an updated repo project as well as new issue would help.
The same issue happens to me when using columns, and you hide some using the DataTables built-in extensions
{ title: 'Actions', data: null, defaultContent: '', ngTemplateRef: { ref: this.demoNg, context: { // needed for capturing events inside <ng-template> captureEvents: self.onCaptureEvent.bind(self) } } }
IMPORTANT: I will try to deliver a stackblitz or minimal reproduction project later. I tried to create a stackblitz or use the stackblitz "angular-datatables-gitter" but I couldn't get them to work with ngTemplateRef. Please don't close this issue immediately!
:beetle: bug report
I have a datatable that gets initialized within "ngAfterViewInit". It uses "ajax" to gather data. I use the datatable "server side the angular way". I have activated the "buttons" plugin to use "colvis" and "stateSave: true".
In my use-case I need one column with a ngTemplateRef. I initialize "this.columns" and put the column with ngTemplateRef at the end, then pass it into "dtOptions". The Datatable initializes fine.
Once I turn one column before my ngTemplateRef column invisible and reload the page, the datatable crashes with this error:
:microscope: Minimal Reproduction
IMPORTANT: Will deliver stackblitz or project later!
x.component.ts
x.component.html
:8ball: Expected behavior
The Datatable should render fine.
:globe_with_meridians: Your Environment
:memo: Additional context
It seems like in the line 66-80 within angular-datatables.directive.js are the issue:
I think after disabling some columns and reloading the page, there is a bug with referenced indeces. Naively spoken: The column of ngTemplateRef gets a certain index beforehand (index = 3), a column gets "visible: false, the column.length only goes to index 2 and then it tries to map everything to index 3 causing a null reference error.