Angular 5 - 不按Ctrl键进行多选

时间:2018-01-18 10:04:48

标签: angular multi-select angular-reactive-forms

我正在处理表单而我正在使用Angular Reactive Forms。 我需要在我的表单中进行多选,我确实通过按ctrl并选择多个选项来完成它。 我希望能够在不按ctrl键的情况下使用多选。 可能吗?

表单组件:

this.productForm = new FormGroup({
  'items': new FormControl(this.product.items, Validators.required),
});

模板:

<div class="form-group">
  <select multiple="multiple" class="form-control" id="items" formControlName="items" required>
    <option *ngFor="let item of itemList" [value]="item.id">{{item.name}}</option>
  </select>
</div>

更新

我尝试了greg95000的解决方案,但它只是一个部分工作的解决方案。

<div class="form-group">
  <select multiple="multiple" class="form-control" id="items" formControlName="items" required>
    <option (mousedown)="onMouseDown($event)" (mousemove)="$event.preventDefault()" *ngFor="let item of items" [value]="item.id">{{item.name}}</option>
  </select>
</div>


public onMouseDown(event: MouseEvent) {
  event.preventDefault();
  event.target['selected'] = !event.target['selected'];
}

此解决方案突破了数据绑定

Multiselect view

2 个答案:

答案 0 :(得分:0)

我有一个可行的解决方案。因为我复制角度数组知道有变化,所以选择得到更新。 这是我的选择:

 <select class="form-control" multiple name="positionTypes" [(ngModel)]="freelancer.positionTypes" #select1>
  <option *ngFor="let positionType of positionTypes" [value]="positionType" (mousedown)="false" 
   (click)="positionTypMouseDown($event)">{{'PositionType.'+positionType | translate}}</option> 
 </select>

这是我组件中的功能:

positionTypMouseDown( event: any ) {
    event.stopPropagation();
    let scrollTop = 0;
    if ( event.target.parentNode ) {
        scrollTop = event.target.parentNode.scrollTop;
    }
    const stringValue = event.target.value.split( '\'' )[1];
    const index = this.freelancer.positionTypes.indexOf( stringValue, 0 );
    if ( index > -1 ) {
        this.freelancer.positionTypes.splice( index, 1 );
    } else {
        this.freelancer.positionTypes.push( stringValue );
    }
    // to make angular aware there is something new
    const tmp = this.freelancer.positionTypes;
    this.freelancer.positionTypes = [];
    for ( let i = 0; i < tmp.length; i++ ) {
        this.freelancer.positionTypes[i] = tmp[i];
    }
    setTimeout(( function() { event.target.parentNode.scrollTop = scrollTop; } ), 0 );
    setTimeout(( function() { event.target.parentNode.focus(); } ), 0 );
    return false;
}

我现在更新了答案,它在chrome中也可以正常工作。重要的部分是聚焦和滚动,使其不聚焦于选项而是聚焦于选择(即event.target.parentNode

答案 1 :(得分:-2)

我不知道这是否有帮助,但也许您可以使用JQuery来做到这一点。 请参考这个答案:

https://stackoverflow.com/a/27056015/9220387

以下是JQuery中的代码:

$("select").mousedown(function(e){
   e.preventDefault();

   var select = this;
   var scroll = select .scrollTop;

   e.target.selected = !e.target.selected;

   setTimeout(function(){select.scrollTop = scroll;}, 0);

   $(select ).focus();
}).mousemove(function(e){e.preventDefault()});

完整的Javascript:

element.onmousedown= function(event) {
    //this == event.target
    event.preventDefault();
    var scroll_offset= this.parentElement.scrollTop;
    this.selected= !this.selected;
    this.parentElement.scrollTop= scroll_offset;
}
element.onmousemove= function(event) {
    event.preventDefault();
}

在选择/取消选择选项之前,查看父元素(选择框)并记录垂直滚动偏移。然后在执行操作后手动重置它。

防止mousemove事件的默认行为背后的原因是因为如果您不阻止它并且您在移动鼠标时碰巧单击某个选项,则所有选项都将被取消选中。

<强>更新

你可以尝试这个解决方案,我不知道是否有更好的解决方案,但我的工作。将onMouseDown方法更改为:

  public onMouseDown(event: MouseEvent, item) {
    event.preventDefault();
    event.target['selected'] = !event.target['selected'];
    if(event.target['selected']) {
      this.productForm.value.items.push(item.id);
    } else {
      let index: number = -1;
      index = this.productForm.value.items.indexOf(item.id);
      if(index > -1) {
          this.productForm.value.items.splice(index);
      }
    }
  }

我认为您不能使用这种选择器获得完全和本机绑定数据(因为preventDefault)。 当然你必须将你的html更改为:

<div class="form-group">
    <select multiple="multiple" class="form-control" id="items" formControlName="items" required>
      <option (mousedown)="onMouseDown($event, item)" (mousemove)="$event.preventDefault()" *ngFor="let item of itemList" [value]="item.id">{{item.name}}</option>
    </select>
</div>