这是一个足够简单的问题(TLDR;):
为什么Angular Mat Table 2选择模型失败?
特别是为什么它会因为传递给它的 select()
或 toggle()
方法的对象的副本而失败 .
但是我包含了很多我的调试过程,因此长度:
尽管这是任何人都能在一两分钟内读到的东西,但不要被它吓到 .
背景:
-
在mat table 2制作的一张 table
-
开始使用材料2的选择模型
selection
在单击时选择表项 -
添加了ctrl-click(当您按住Ctrl键单击时添加删除到选择)
-
也试图添加shift-click支持(Shift-单击将添加/删除点击和最后添加/删除项目之间的所有项目)
什么失败:
通过Shift-单击方法添加到选择中的项目在选择数组中,但不会在视觉上显示为选定的,与以下点击/选择无关(这将产生相同的结果EG:保持选择时的当前视觉错误)保持一个完美的选择数组 . 是的人会认为如果整个数组在console.log中是正确的,那么之后点击"bug-free"类型至少会修复有错误的数组,但是没有 .
守则:
解决Shift-select:
HTML:
...
</div>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="pinnedColumnsWSelect"></mat-header-row>
<mat-row *matRowDef="let row; columns: pinnedColumnsWSelect;"
class="noselect"
[ngClass]="{ 'selected': selection.isSelected(row)}"
(click)="addToSelection(row, $event, false)"></mat-row>
</mat-table>
...
(假的是,点击源自行开头的复选框元素,还是只是点击了行的其余部分?)
ts:
addToSelection(row, event, checkbox){
if(event.shiftKey && this.previous !== -1 && this.previous !== row.numberOfRow) {
if(this.previous > row.numberOfRow){
for(let previous = this.previous - 1; previous >= row.numberOfRow; previous-- ){
this.selection.toggle(this.originalDataSet.filter(x => x['numberOfRow'] === previous)[0] as object[]);
}
}else{
for(let previous = this.previous + 1; previous <= row.numberOfRow; previous++ ){
this.selection.toggle(this.originalDataSet.filter(x => x['numberOfRow'] === previous)[0] as object[]);
}
}
} else if(event.ctrlKey || checkbox) {
this.selection.toggle(row);
} else {
if(this.originalDataSet){
if(this.selection.selected.length === 1 && this.selection.selected[0] === row) {
this.selection.clear();
} else {
this.selection.clear();
this.selection.select(row);
}
}
}
this.previous = row.numberOfRow;
}
你可以从上面推断我首先检查Shift键是否被按下 . 如果是,我应用我当前导致问题的选择,如果没有按住Shift但是Ctrl是,我添加到选择(这可行),最后我是在没有按键的情况下,我只需清除选择并将新项目设置为唯一选定的项目 .
您也可以通过阅读上面的代码得出结论,我在“shift hold down”部分尝试做的是获取要选择的每一行的相应行并将其传递给selection的切换函数 .
调试:
以前有console.logged行并注意到该行确实是表的整个当前行,我推断出我可以模拟正确的对象传递给方法在A点和B点之间“切换” .
我的材质表接受一个对象数组作为它的数据集 . 每个对象对应一行,每个对象的键对应于表的 Headers . 到现在为止还挺好 .
从我自己的数组中拉出右行(使用我匹配 numberOfRow
的过滤器,我的唯一标识符,恰好计算行数(0,1,2,3,等等))应该给我同样的东西 .
控制台记录这两个给我 the same thing :
const y = this.originalDataSet.filter(x => x['numberOfRow'] === previous)[0];
console.log('filtered item ', y, ' row ', row, ' equal ', y === row, y == row );
然而,噩梦始于两个宣称不相等的噩梦 .
现在 ===
足够公平,但对于 ==
,为什么?
怎么会发生这种情况,我不知道:
filtered item {numberOfRow: 2, nCommande: "4500131111", nLigne: "00010", nEcheance: "0001", id: {…}, …} row {numberOfRow: 2, nCommande: "4500131111", nLigne: "00010", nEcheance: "0001", id: {…}, …} equal false false
这是我以前在javascript中从未见过的东西 . 这两个对象是IDENTICAL我现在通过打开所有节点手动检查了15次 . 但是==失败了 .
但是抱着这个想法,虽然它很迷人,但我还有一些更令人着迷的东西 .
深种子问题:
让我们选择console.log( console.log(this.selection.selected);
)
-
然后单击我们的mat-table的第一个Item
-
shift-单击第四个
-
ctrl单击fith
你会发生什么?
没有最终选择,因为选择格式不正确?我喜欢只选择第一个结尾,因为选择的数组在那之后是不正确的?这也可以正确选择所有5个项目吗?一个人可以做梦
好吧没有:
好吧,让我们看看日志:
(5) [{…}, {…}, {…}, {…}, {…}]
0 : {numberOfRow: 0, nCommande: "2284595", nLigne: "1", nEcheance: "0", id: {…}, …}
1 : {numberOfRow: 1, nCommande: "2284595", nLigne: "2", nEcheance: "0", id: {…}, …}
2 : {numberOfRow: 2, nCommande: "4500131111", nLigne: "00010", nEcheance: "0001", id: {…}, …}
3 : {numberOfRow: 3, nCommande: "4500131111", nLigne: "00020", nEcheance: "0001", id: {…}, …}
4 : {numberOfRow: 4, nCommande: "4500634818", nLigne: "00010", nEcheance: "0001", id: {…}, …}
length : 5
__proto__:Array(0)
我糊涂了 .
你使用这个数组正确地选择了数组项目0和4,但是对于介于两者之间的所有东西,禁止进行,即使4的选择(第5项)是最后的 .
怎么样?
这种“区分”在人眼不能的“错误”和“正确”之间的模式,在你无限制地叠加换档选择和ctrl选择时继续 . 如果你的this.selection.selected是100000个项目,它仍然没有在实际的可视化表示中选择所有那些添加在其数组中的项目,并且已经正确选择了所有使用ctrl添加的项目 .
Shift-Click up? :
让我们把它混淆起来,因为这就是我们如何获得最终偏离常规路径的东西 .
让我们尝试用shift取消选择
如果我再做一个狗屎点击打算再添加三个项目,再点击一个控件点击下面的项目然后转移点击返回UP到第二个项目:
没有什么可以摆脱我们目前的混乱,至少在视觉上:
(9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0 : {numberOfRow: 0, nCommande: "2284595", nLigne: "1", nEcheance: "0", id: {…}, …}
1 : {numberOfRow: 1, nCommande: "2284595", nLigne: "2", nEcheance: "0", id: {…}, …}
2 : {numberOfRow: 2, nCommande: "4500131111", nLigne: "00010", nEcheance: "0001", id: {…}, …}
3 : {numberOfRow: 3, nCommande: "4500131111", nLigne: "00020", nEcheance: "0001", id: {…}, …}
4 : {numberOfRow: 4, nCommande: "4500634818", nLigne: "00010", nEcheance: "0001", id: {…}, …}
5 : {numberOfRow: 5, nCommande: "4500634818", nLigne: "00020", nEcheance: "0001", id: {…}, …}
6 : {numberOfRow: 6, nCommande: "4500634818", nLigne: "00030", nEcheance: "0001", id: {…}, …}
7 : {numberOfRow: 7, nCommande: "4500634818", nLigne: "00040", nEcheance: "0001", id: {…}, …}
8 : {numberOfRow: 8, nCommande: "4500634818", nLigne: "00050", nEcheance: "0001", id: {…}, …}
length : 9
(4) [{…}, {…}, {…}, {…}]
0 : {numberOfRow: 0, nCommande: "2284595", nLigne: "1", nEcheance: "0", id: {…}, …}
1 : {numberOfRow: 4, nCommande: "4500634818", nLigne: "00010", nEcheance: "0001", id: {…}, …}
2 : {numberOfRow: 8, nCommande: "4500634818", nLigne: "00050", nEcheance: "0001", id: {…}, …}
3 : {numberOfRow: 4, nCommande: "4500634818", nLigne: "00010", nEcheance: "0001", id: {…}, …}
length : 4
这是出乎意料的 .
为什么它保留了第4项而不是像其他部分一样取消选择它并且再次添加它?
这让我觉得还有另一个数组用于我不知道的比较 .
onChange怎么样? :
此外
onChange
结果完全符合预期:
ngOnInit() {
this.selection.onChange.subscribe(x=> {
console.log(x);
});
}
从第一个项目到第六个项目的再次点击并再次返回:
{source: SelectionModel, added: Array(1), removed: Array(0)}
{source: SelectionModel, added: Array(1), removed: Array(0)}
{source: SelectionModel, added: Array(1), removed: Array(0)}
{source: SelectionModel, added: Array(1), removed: Array(0)}
{source: SelectionModel, added: Array(1), removed: Array(0)}
{source: SelectionModel, added: Array(1), removed: Array(0)}
{source: SelectionModel, added: Array(0), removed: Array(1)}
{source: SelectionModel, added: Array(0), removed: Array(1)}
{source: SelectionModel, added: Array(0), removed: Array(1)}
{source: SelectionModel, added: Array(0), removed: Array(1)}
{source: SelectionModel, added: Array(1), removed: Array(0)}
我检查他们指出的内容是否正确(正确的项目编号) .
然而,视觉效果并不适用 .
碳复制真的失败了吗? :
另一个实验:
我在介绍中提到过,对象的副本将被拒绝:这是真的 .
如果我这样做到目前为止功能的ctrl代码它停止运行(这是导入的underscorejs库btw,它是一个浅层克隆,但它不会省略下属,它使用它们的内存引用):
} else if(event.ctrlKey || checkbox) {
const bb = _.clone(row);
this.selection.toggle(bb);
}
这种方法也会发生同样的事情(这是一个深层克隆):
} else if(event.ctrlKey || checkbox) {
const bb = jQuery.extend(true, {}, row);
this.selection.toggle(bb);
}
使用ctrl-click不再可视地选择行,而控制台记录的选择数组和选择的所有其他方面仍然是完美无缺的 .
哪些版本的Angular,Material,OS,TypeScript,浏览器? :
windows pro 10 64bit chrome
{
"name": "web.ui",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve --aot",
"build": "ng b --prod",
"test": "ng test",
"lint": "ng lint"
},
"private": true,
"dependencies": {
"@angular/animations": "^6.0.3",
"@angular/cdk": "^6.1.0",
"@angular/common": "^6.0.3",
"@angular/compiler": "^6.0.3",
"@angular/core": "^6.0.3",
"@angular/forms": "^6.0.3",
"@angular/http": "^6.0.3",
"@angular/material": "^6.1.0",
"@angular/platform-browser": "^6.0.3",
"@angular/platform-browser-dynamic": "^6.0.3",
"@angular/router": "^6.0.3",
"@types/underscore": "^1.8.7",
"angular-font-awesome": "^3.1.2",
"bootstrap": "^4.0.0",
"classlist.js": "^1.1.20150312",
"core-js": "^2.5.3",
"file-saver": "^1.3.8",
"font-awesome": "^4.7.0",
"jquery": "^3.3.1",
"lodash": "^4.17.5",
"ng2-ion-range-slider": "^2.0.0",
"ngx-bootstrap": "^3.0.0",
"ngx-dropzone-wrapper": "^6.1.0",
"rxjs": "^6.2.0",
"rxjs-compat": "^6.0.0-rc.0",
"typescript": "2.7.2",
"underscore": "^1.8.3",
"web-animations-js": "^2.3.1",
"zone.js": "^0.8.20"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.6.5",
"@angular/cli": "^6.0.5",
"@angular/compiler-cli": "^6.0.3",
"@angular/language-service": "^6.0.3",
"@types/jasmine": "^2.8.6",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~10.1.3",
"codelyzer": "^4.2.1",
"postcss-modules": "^1.1.0",
"protractor": "~5.3.0",
"ts-node": "~6.0.5",
"tslint": "~5.10.0"
}
}
1 回答
好吧,我想通了,这似乎你们中的一些人喜欢在我给出的问题中是一个未知的因此你不能猜到它因为我没有给你我的全部组件而且你们其余的人会看起来很明显,因为你知道mat table足够好,你可以从我的变量的命名中看出有些不对劲,
我有一组四个本地变量,用于处理从API到达时以及在mat-table中可视化显示的对象之间的四个步骤 .
行(对象)在1和4之间确实是相同的,但是从那以后很多都没有丢失 .
这并没有回答为什么javascript认为对象的两个副本不一样但它确实回答了为什么我正在提供我的
toggle()
方法的对象被认为与row
不同现在用
this.dataSource.filteredData
我实际上是在我的mat表中迭代同一个数组 .例如,这不会导致切换页面和按住Shift键点击的缺陷 .
(除了没有从第一页中选择项目之外,它不能再迭代,因为它们不在当前列表中,这是我想要在开始时避免的但是我将把这个错误带到这个上面)
如果某人有一个答案,为什么js看不到对象的副本与自己相同,我很乐意得到答案 .
如果有人能够看到这个对象如何无法满足mat table的选择模型的标准以及我如何欺骗它,我也很想知道 .
我愿意将你标记为答案并给予50分的赏金 .