如何同时将一个值插入多个选定的输入?

How to insert a value into multiple selected inputs simultaneously?

我有一个 html table 包含输入标签,我想要一种机制允许我同时将相同的值插入多个 table 单元格,而无需手动在每个单元格中键入它。

例如像这样的 table :

id | attr1 | attr2 | attr3
1     "x"    "x"      "x"
2     "x"    "z"      "y"
3     "a"    "w"      "x"

x 是我想插入到那些特定单元格中的值,我不想手动输入它。

编辑:这就是我的 table 的样子:

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
    
  <!--- Note that these columns can be defined in any order.
            The actual rendered columns are set as a property on the row definition" -->
    
  <!-- Position Column -->
  <ng-container matColumnDef="position">
    <th mat-header-cell *matHeaderCellDef> No. </th>
    <td mat-cell *matCellDef="let element"> <input type"text" value="{{element.position}}"></td>
  </ng-container>
    
  <!-- Name Column -->
  <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef> Name </th>
    <td mat-cell *matCellDef="let element"> <input type"text" value="{{element.name}}"> </td>
  </ng-container>
    
  <!-- Weight Column -->
  <ng-container matColumnDef="weight">
    <th mat-header-cell *matHeaderCellDef> Weight </th>
    <td mat-cell *matCellDef="let element"> <input type"text" value="{{element.weight}}"> </td>
  </ng-container>
    
  <!-- Symbol Column -->
  <ng-container matColumnDef="symbol">
    <th mat-header-cell *matHeaderCellDef> Symbol </th>
    <td mat-cell *matCellDef="let element"> <input type"text" value="{{element.symbol}}"> </td>
  </ng-container>
    
  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}
    
const ELEMENT_DATA: PeriodicElement[] = [
  {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
  {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
  {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
  {position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
  {position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
  {position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'},
  {position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N'},
  {position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'},
  {position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'},
  {position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'},
];
    
/**
 * @title Basic use of `<table mat-table>`
 */
@Component({
  selector: 'table-basic-example',
  styleUrls: ['table-basic-example.css'],
  templateUrl: 'table-basic-example.html',
})
export class TableBasicExample {
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;
}

分步指南

我希望你现在已经自己找到了一些东西,但我决定也想试一试。因此,这是我如何成功实现这一目标的分步指南。

第 1 步

首先创建一个数组来保存所选字段。

selected: string[] = [];

第 2 步

然后使用 'fromEvent()' 来监听按住一个键,你可能希望它在按下键时清除数组。在这种情况下,您可能希望同时收听 keyup 和 keydown 事件。

keyDowns$ = fromEvent(document, 'keydown');
keyUps$ = fromEvent(document, 'keyup');

ctrlPresses$ = merge(this.keyDowns$, this.keyUps$).pipe(
  filter((e: KeyboardEvent) => e.keyCode === CTRL), // <-- Keycode for CTRL = 17
  debounceTime(100),
  tap((x: KeyboardEvent) => {
    if (x.type === 'keydown') {
      this.selected = [];
      this.ctrlPressed = true;
      console.log('CTRL is down');
    }
  }),
  tap((x: KeyboardEvent) => {
    if (x.type === 'keyup') {
      this.ctrlPressed = false;
      console.log('CTRL is up');
    }
  })
);

步骤 3

然后创建第二个可观察对象,获取被点击的单元格。现在组合这些可观察对象并存储一些可以标识您在数组中选择的单元格的内容。为了简单起见,我只是在第一个 observable 中翻转了一个布尔值,但实际上你想避免使用 higher-order observable 那样的 side-effects 。我们从将点击事件推送到我们自己的主题中获得的第二个可观察值。

selectionSubject = new Subject();

get selection$() {
  return this.selectionSubject.asObservable().pipe(
    tap((x: string) => {
      if (this.ctrlPressed && this.selected.indexOf(x) === -1) {
        this.selected.push(x);
      }
    })
  );
}

onClicked(event: MouseEvent) {
  const target = event.currentTarget as HTMLInputElement;
  this.selectionSubject.next(target.id);
}

第 4 步

如果单元格在数组中,则使用 ngClass 渲染一些 css。

isSelected(id: string) {
  if (this.selected.indexOf(id) !== -1) {
    return 'selected';
  }
}

添加一些基本样式:

input {
  margin: 2px;

  &:focus {
    outline: none;
  }
}

.selected {
  border: none;
  box-shadow: 0 0 3pt 2pt cornflowerblue;
}

第 5 步

将每个输入的更改事件绑定到一个函数,该函数还设置数组中具有其标识符的所有其他输入。绑定 keyup 事件最适合我。

onChange(e) {
  this.selected.forEach((id) => {
    this[id].nativeElement.value = e;
  });
}

终于

html 中的输入应如下所示:

<input
  #tf1
  [ngClass]="isSelected('tf1')"
  id="tf1"
  (click)="onClicked($event)"
  (keyup)="onChange($event.target['value'])"
  type="text"
/>

这是 Stackblitz.

中的示例代码

代码可能还可以优化一点。我还添加了鼠标点击清除选择,以及一些样式魔术,以便能够在 Stackblitz 项目中拥有多个(假)插入符号。 它有点混乱了基本逻辑,所以我没有把它包括在这里。