【问题标题】:Angular 5 - Multiselect without pressing the Ctrl keyAngular 5 - 多选而不按 Ctrl 键
【发布时间】:2018-01-18 10:04:47
【问题描述】:

我正在处理一个表单并且我正在使用 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'];
}

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

【问题讨论】:

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


    【解决方案1】:

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

     <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

    【讨论】:

      【解决方案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>
      

      【讨论】:

      • 我想只使用 Angular/Typescript 或纯 JavaScript,而不需要任何额外的库,如 jQuery。
      • 那么你可以使用这个答案:stackoverflow.com/a/30110103/9220387 这是普通的 Javascript
      • @greg95000 我已经尝试使用您建议的解决方案,但它无法正常工作。请看我的更新
      • @greg95000 我测试了您的解决方案,但它无法正常工作。无论如何,现在我通过将this.productForm.value.items.splice(index) 更改为this.productForm.value.items.splice(index, 1) 来修复这个小错误,所以这样只会删除一个元素。我刚刚接受了你的回答,谢谢
      • @greg95000 我仍然遇到的唯一问题与滚动偏移有关。我尝试使用let scrollOffset = event.target['parentElement']['scrollTop'];,然后使用event.target['parentElement']['scrollTop'] = scrollOffset;,但这并不能解决问题
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-10
      • 1970-01-01
      • 1970-01-01
      • 2019-05-02
      • 1970-01-01
      相关资源
      最近更新 更多