Angular不能循环ElementRef列表



我有一个ElementRef列表,用于所有输入,但当我尝试向它们添加侦听器时,它使textInputs为空,但它不是。


@ViewChildren('text_input') textInputs!: QueryList<ElementRef>;
ngAfterViewInit(): void {
this.initTextInputsListeners();
}
private initTextInputsListeners() {
this.textInputs.forEach(input => {
const inputElement = input.nativeElement;
const parentNode = inputElement.parentNode;
inputElement.addEventListener('focus', () => {
parentNode.classList.add('user-input-active')
});
inputElement.addEventListener('focusout', () => {
if (inputElement.value === '') parentNode.classList.remove('user-input-active');
});
});
}
<div class="user-input send-message" [formGroup]="userInputForm" (ngSubmit)="onSendMessage()">
<div class="user-input-box">
<label for="message">Send message</label>
<input id="message" class="form-control" type="text" name="message" #text_input formControlName="message" (keyup.enter)="onSendMessage()">
<button class="submit-btn" type="submit" value="" (click)="onSendMessage()">
<svg width="32" height="32" viewBox="0 0 24 24">
<path
d="m3.4 20.4l17.45-7.48a1 1 0 0 0 0-1.84L3.4 3.6a.993.993 0 0 0-1.39.91L2 9.12c0 .5.37.93.87.99L17 12L2.87 13.88c-.5.07-.87.5-.87 1l.01 4.61c0 .71.73 1.2 1.39.91z"/>
</svg>
</button>
</div>
</div>

你的代码看起来像工作。所以问题是,当你执行initTextInputsListeners时textInputs没有所有的输入

所以当然,你可以订阅this.textInputs.changes

ngAfterViewInit(): void {
this.textInputs.changes.pipe(startWith(null)).subscribe((_) => {
this.initTextInputsListeners();
});
}

还有一种方法可以达到你想要的效果,那就是使用指令

你可以使用一个指令应用到你的输入,如

@Directive({
selector: '[specialfocus]'
})
export class AddClassParentDirective {
@Input('specialfocus') class="user-input-active"
@HostListener('focus') addClass(){
this.el.nativeElement.parentNode.classList.add(this.class)
}
@HostListener('blur') removeClass(){
this.el.nativeElement.parentNode.classList.remove(this.class)
}
constructor(private el:ElementRef) { }
}

和as

<div class="user-input-box">
<label for="message">Send message</label>
<input [specialfocus] class="form-control" type="text" />
</div>

或者使用应用于div的指令(请参阅,在本例中我使用'.user-input-box2'作为选择器,因此每个div都有一个类"user-input-box2"是一个UserInputBoxDirective

@Directive({
selector: '.user-input-box2'
})
export class UserInputBoxDirective implements AfterViewInit,OnDestroy {
focus:boolean=false;
subscription:any=null
@HostBinding('class.user-input-active') get _(){
return this.focus?true:null
}
@ContentChild(HTMLInputElement) input:HTMLInputElement
constructor(private el:ElementRef) { }
ngAfterViewInit()
{
const inputs=this.el.nativeElement.getElementsByTagName('input')
if (inputs && inputs.length)
this.subscription=merge(fromEvent(inputs[0],'focus').pipe(map(_=>true)),
fromEvent(inputs[0],'blur').pipe(map(_=>false)))
.subscribe(res=>{
this.focus=res
})
}
ngOnDestroy()
{
this.subscription && this.subscription.unsubscribe
}
}

使用like

<div class="user-input-box2">
<label for="message">Send message</label>
<input class="form-control" type="text" />
</div>

你有三种方法(your's和this about指令)在这个stackblitz

最简单的解决方案是根本不使用JS。这是标准的CSS内容,在现代浏览器中有很好的支持:

使用focus-within来确定容器中是否有活动的焦点。

对于CSS,第二种方法是使用:has() CSS伪类,但这对CSS的支持较差。如果您只希望在输入被选中时激活此规则,则可以修改HTML标记,以便仅在输入处于焦点时触发焦点。

在下面的例子中,如果焦点在.user-input-box元素内,我将文本涂成粉红色,并将SVG填充为蓝色

.user-input-box:focus-within {
color: pink
}
.user-input-box:focus-within svg {
fill: blue
}
<div class="user-input-box">
<label for="message">Send message</label>
<input id="message" class="form-control" type="text" name="message" #text_input formControlName="message">
<button class="submit-btn" type="submit" value="">
<svg width="32" height="32" viewBox="0 0 24 24">
<path
d="m3.4 20.4l17.45-7.48a1 1 0 0 0 0-1.84L3.4 3.6a.993.993 0 0 0-1.39.91L2 9.12c0 .5.37.93.87.99L17 12L2.87 13.88c-.5.07-.87.5-.87 1l.01 4.61c0 .71.73 1.2 1.39.91z"/>
</svg>
</button>
</div>

最新更新