Angular 5 - 多选而不按 Ctrl 键
Angular 5 - Multiselect without pressing the Ctrl key
我正在处理一个表单,我正在使用 Angular 响应式表单。
我需要在我的表单中包含 multi-select,我确实通过按 ctrl 和 selecting 多个选项来完成它。
我希望能够在不按 ctrl 键的情况下使用 multiselect。
有可能吗?
表单组件:
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'];
}
此解决方案打破了数据绑定
我不知道这是否有帮助,但也许您可以使用 JQuery 来做到这一点。
请参考这个回答:
这是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();
}
查看父元素(select 框)并记录 selecting/deselecting 选项之前的垂直滚动偏移量。然后在执行操作后手动重置它。
阻止 mousemove 事件的默认行为背后的原因是,如果您不阻止它并且您在移动鼠标时碰巧单击了一个选项,所有选项都将被取消selected。
更新
你可以试试这个解决方案,我不知道是否有更好的解决方案,但我的有效。将您的 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);
}
}
}
我认为您无法使用这种 selector 获得完全原生的绑定数据(因为 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 知道有变化所以 select 得到更新。
这是我的 select:
<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 中也能正常工作。重要的部分是焦点和滚动不关注选项而是关注 select(即 event.target.parentNode
我正在处理一个表单,我正在使用 Angular 响应式表单。 我需要在我的表单中包含 multi-select,我确实通过按 ctrl 和 selecting 多个选项来完成它。 我希望能够在不按 ctrl 键的情况下使用 multiselect。 有可能吗?
表单组件:
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'];
}
此解决方案打破了数据绑定
我不知道这是否有帮助,但也许您可以使用 JQuery 来做到这一点。 请参考这个回答:
这是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();
}
查看父元素(select 框)并记录 selecting/deselecting 选项之前的垂直滚动偏移量。然后在执行操作后手动重置它。
阻止 mousemove 事件的默认行为背后的原因是,如果您不阻止它并且您在移动鼠标时碰巧单击了一个选项,所有选项都将被取消selected。
更新
你可以试试这个解决方案,我不知道是否有更好的解决方案,但我的有效。将您的 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);
}
}
}
我认为您无法使用这种 selector 获得完全原生的绑定数据(因为 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 知道有变化所以 select 得到更新。 这是我的 select:
<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 中也能正常工作。重要的部分是焦点和滚动不关注选项而是关注 select(即 event.target.parentNode