在 Angular 2 \ 4 表中向上键

Posted

技术标签:

【中文标题】在 Angular 2 \\ 4 表中向上键【英文标题】:Key up down in Angular 2 \ 4 table在 Angular 2 \ 4 表中向上键 【发布时间】:2018-02-24 13:15:42 【问题描述】:

如何在 Angular 的表格单元格中编写按键向上和向下按键的功能? (就像我们如何使用向上和向下箭头键在 Excel 工作表中的单元格上移动键一样)。

这是我的代码: http://plnkr.co/edit/vk937A1VWNPIFQYkoPsM?p=preview

<table>
      <thead>
            <tr>
                 <th class="under-below" *ngFor="let col of columns">col.display</th>
            </tr>
        </thead>

        <tbody>
            <tr *ngFor="let row of rows">
                <td *ngFor="let col of columns">

                <div *ngIf="!col.editable">colLabelFunction(row, col)</div>
                <input type="text" value="colLabelFunction(row, col)" *ngIf="col.editable">

                </td>

            </tr>


        </tbody>
      </table>

我想使用 keyup 和 keydown 键在“第 2 列”文本输入(单元格)上上下移动。

【问题讨论】:

【参考方案1】:

我刚刚注意到我比您想要的更进一步,并添加了右/左功能。如果你愿意,你可以把它们剪掉。

为此,您需要完成几件事:

    绑定到关键事件并在其上运行函数 跟踪您的索引并将它们传递给函数 获取元素的引用并调用它们的焦点方法 把它们放在一起

第1项:绑定按键事件和运行函数

Angular 提供了易于使用的事件绑定,如下所示:

<input #inputs type="text" value="colLabelFunction(row, col)" [class.hidden]="!col.editable" 
      (keyup.arrowdown)="shiftFocusDown(rowIdx, colIdx)"  
      (keyup.arrowup)="shiftFocusUp(rowIdx, colIdx)"
      (keyup.arrowright)="shiftFocusRight(rowIdx, colIdx)"
      (keyup.arrowleft)="shiftFocusLeft(rowIdx, colIdx)">

keyup 事件是通用的,然后 arrowdown 等是 angular 提供的简写。然后您只需使用任何参数设置要触发的功能。

第 2 项跟踪您的索引并传递给函数

您可以在上面看到,我在这些事件上调用了一个函数并传递了 rowIdx 和 colIdx,要获取这些变量,您可以在 ngFor 中声明它们,如下所示:

<tr *ngFor="let row of rows; let rowIdx = index">
     <td *ngFor="let col of columns; let colIdx = index">

index 是 ngFor 中提供的一个特殊变量,它给出了当前项目的索引。它们还公开了一些其他内容,例如您可以声明和使用的 first 和 last。

第三项:获取元素引用

为此,我们必须做几件事情,你可能已经注意到上面我没有在输入上使用 ngIf,而是设置了 class.disabled,然后我添加了 CSS 来隐藏组件中隐藏类的元素声明如下:

 styles: [`.hidden  display: none; `]

我这样做是为了让元素引用永远不会改变,原因稍后会很明显,我做的另一件事是为每个输入项添加#inputs,这是我可以在组件代码中访问的模板引用:

@ViewChildren('inputs') inputs;

子视图可以接受几种不同类型的参数,在这种情况下,它接受一个字符串,它将在模板中搜索与字符串匹配的任何模板引用,并将它们返回到查询列表中。

第 4 项:放在一起

我现在有了在所需的键事件上执行的适当函数,带有所需的参数,以及我所有输入元素引用的平面列表。

现在我只需要编写代码来完成这项工作:

focusInput(rowIdx: number, colIdx: number) 
  console.log(rowIdx, colIdx);
  // convert ViewChildren querylist to an array to access by index
  let inputEls = this.inputs.toArray();
  // get the flat index from row/cols
  let flatIdx = (rowIdx * this.columns.length) + colIdx;
  // get that reference from the input array and use the native element focus() method
  inputEls[flatIdx].nativeElement.focus();


shiftFocusDown(rowIdx:number, colIdx:number) 
  console.log("DOWN", colIdx, rowIdx)
  // add 1 but don't go beyond my row range
  rowIdx = Math.min(rowIdx + 1, this.rows.length - 1);
  this.focusInput(rowIdx, colIdx);


shiftFocusUp(rowIdx:number, colIdx:number) 
  console.log("UP", colIdx, rowIdx);
  // up 1, but not less than 0
  rowIdx = Math.max(0, rowIdx - 1);
  this.focusInput(rowIdx, colIdx);


shiftFocusLeft(rowIdx:number, colIdx:number) 
  console.log("LEFT", rowIdx, colIdx);
  // left one column, and correct for non editable columns to left
  colIdx = colIdx - 1 - this.columns.slice(0, colIdx).reverse().findIndex(c => c.editable);
  // don't need edge check bc findIndex returns -1 if none found or no items, so that corrects us back to start col automatically
  this.focusInput(rowIdx, colIdx);


shiftFocusRight(rowIdx:number, colIdx:number) 
  console.log("RIGHT", rowIdx, colIdx);
  // right one column, and correct for non editable columns to right
  colIdx = colIdx + 1 + this.columns.slice(colIdx + 1).findIndex(c => c.editable);
  // don't need edge check bc findIndex returns -1 if none found or out of range, so that corrects us back to start col automatically
  this.focusInput(rowIdx, colIdx);

这里的代码主要是查找下一个适当的 col/row 索引然后将 x,y 转换为平面索引的逻辑,以便我可以在我的 viewchildren 列表中找到正确的引用并在其上调用 focus()。我需要所有元素引用始终存在的原因是因为否则将更难从 x,y 中找出正确的平面索引。如果您真的需要它们不在那里,那么您可以修改此逻辑以使其工作。并非不可能。您还可以对其进行修改以允许非常轻松地“环绕”行。

完成plunkr:http://plnkr.co/edit/m4BRi5rh5gYuvlKfwhqk?p=preview

【讨论】:

非常感谢 Bryan,非常感谢您花时间将它们放在一起。我不知道我们实际上也可以使用动态元素的 id 来引用元素,在循环下运行,就像这样:&lt;input #inputs type="text" ...。但是您的完整解决方案确实帮助我了解了它是如何工作的。再次感谢。干杯! 是的,我觉得 # 语法给人的印象是它们需要是唯一的,因为 # 是 Vanilla 文档查询中的元素 ID 前缀。但模板引用并非如此。重要的是要记住它们不是 id,它们是 Angular 独有的模板引用。仅供参考,关注输入元素是直接访问元素引用是实现目标的最佳方法的极少数情况之一。在大多数其他情况下,有更好/更清洁的方法! 如果您使用 ViewChild,则数组不起作用,它仅适用于 ViewChildren 我们也可以在角度材料表中使用上面的代码吗.. @Eswar 不,我不相信这适用于材料表。您需要一些基于服务的方法和自定义组件/指令

以上是关于在 Angular 2 \ 4 表中向上键的主要内容,如果未能解决你的问题,请参考以下文章

Angular 4 和 Laravel 5.4 的刷新路由问题

如何从 Angular 4 更新/升级到 Angular 5+

Angular 2:找不到名称“订阅”

如何在 Angular 2 / Typescript 中声明全局变量? [关闭]

angularJS初学篇-1添加随笔

在 Angular 2 中为多个动态剑道网格导出 excel