我创建了一个指令并将其分配给一个元素,它的子元素是ngModel的输入,我想从父指令中重置子ngModel
我已经尝试过
HTML :-
<div wrapper [childModel]="childElm">
<input type="text" [ngModel]="name" #childElm>
</div>
包装器指令
@Input(childModel) childModel;
someFunc() {
this.childModel.control.setValue(null);
}
还有其他方法,而无需使用@Input。因为以这种方式,我必须创建本地模板变量并将其分配给@Input。
答案 0 :(得分:0)
尝试创建一个名为Output
的{{1}}属性。然后,Angular将自动更新父属性。然后,只要孩子更改值,我们就需要childModelChange()
事件:
您可以设置从子级到父级的事件发射器通信(输出)。例如这样的
从“ angular2 / core”导入{Component,EventEmitter,Input,Output}
emit()
您的父组件:
@Component({
selector: 'yourChild',
template: `
<p>yourChild yourSharedVariable: {{yourSharedVariable}}</p>
<input [ngModel]="yourSharedVariable" (ngModelChange)="change($event)">
`
})
export class yourChildComponent {
@Input() yourSharedVariable: string;
@Output() yourSharedVariableChange = new EventEmitter();
change(newValue) {
console.log('newvalue', newValue)
this.yourSharedVariable = newValue;
this.yourSharedVariableChange.emit(newValue);
}
}
答案 1 :(得分:0)
您可以使用ContentChild或ContentChildren。当您要查找NgModel时,您的指令将变为
@ContentChild(NgControl, { static: true }) input
someFunc() {
this.input.control.setValue(null);
}
(NgControl)是任何带有[ngModel]的输入或带有[formControl]的输入,如果我们正在使用ReactiveForm,则是formControlName
我们可以有一个类似app.component的
<div hello >
<input [ngModel]="value"/>
</div>
<button (click)="do()">clear</button>
export class AppComponent {
@ViewChild(HelloDirective,{static:true}) wrapper
do()
{
this.wrapper.someFunc()
}
}
请参见stackblitz
注意:真正要清除输入不是必须创建指令,但是我想这是更复杂的一部分
已更新,当我们想在Angular Material中使用“清除”按钮时,docs的第4个例子将是一个机会
<mat-form-field class="example-form-field">
<input matInput type="text" placeholder="Clearable input" [(ngModel)]="value">
<button mat-button *ngIf="value" matSuffix mat-icon-button aria-label="Clear" (click)="value=''">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
要了解如何通过选择功能发挥作用,请参见stackoverflow question and answer
但是问题是,我们可以制定一条指令来实现类似的目标吗? (答案是正确的)。但是我们的指令必须使用Renderer2,并且-我还没有找到其他方法-用.css创建十字架。
.css就像
.close {
position: absolute;
right: -1rem;
top: -2.5rem;
width: .8rem;
height: .8rem;
opacity: 0.7;
}
.close:hover {
opacity: 1;
}
.close:before, .close:after {
position: absolute;
left: .4rem;
content: ' ';
height: .7rem;
width: 1px;
background-color: #333;
}
.close:before {
transform: rotate(45deg);
}
.close:after {
transform: rotate(-45deg);
}
指令变为(请参见注释以获取简要说明)
@Directive({
selector: '[clear]',
host: { //we need an "extra" space to the rigth
'[style.margin-right]': '"1.5rem"',
}
})
export class ClearDirective implements OnInit {
div: any;
@ContentChild(NgControl) control; //we get the "input"
@HostListener('click', ['$event']) click($event) {
//we add a HostListener "click" and take account is we click
//in the "cross" we created, is a span with class="close"
if ($event.target.getAttribute('class') == 'close') {
this.control.control.setValue(null); //remember, the control is the NgControl
$event.stopPropagation();
}
}
constructor(private renderer: Renderer2, private el: ElementRef) { }
ngOnInit() {
//we need take account about when the value of the control is "something"
//or none
if (this.control)
this.control.valueChanges.subscribe((value) => {
if (!value) { //if no value
this.clearCross() //remove the cross
}
else {
if (!this.div) { //if not yet the cross
this.createCross() //create
}
}
})
}
createCross() {
//we wan create some like
/*
<div class="mat-form-field-suffix">
<span class="close"></span>
</div>
*/
this.div = this.renderer.createElement('div');
this.renderer.addClass(this.div, "mat-form-field-suffix")
const span = this.renderer.createElement('span')
this.renderer.addClass(span, "close")
this.renderer.appendChild(this.div, span);
this.renderer.appendChild(this.el.nativeElement, this.div);
}
clearCross() {
if (this.div) //simply remove the "cross"
{
this.renderer.removeChild(this.el.nativeElement, this.div)
this.div=null
}
}
例如,您可以使用
<mat-form-field clear>
<input matInput type="text" placeholder="Clearable input" [(ngModel)]="value">
</mat-form-field>
好吧,完整示例(基于@SammerKant的分叉堆栈闪电)是here
更新2 ,好吧,我不喜欢的是该指令超出了输入范围。我真的不喜欢因此,以相同的观点,更改css来调整位置,新指令位于this stackblitz
中export class ClearDirective implements OnInit {
div: any;
constructor(@Optional() private control:NgControl,private renderer: Renderer2, private el: ElementRef) { }
ngOnInit() {
if (this.control)
this.control.valueChanges.subscribe((value) => {
if (!value) {
this.clearCross()
}
else {
if (!this.div) {
this.createCross()
}
}
})
}
createCross() {
this.div = this.renderer.createElement('div');
this.renderer.addClass(this.div, "wrapper")
const span = this.renderer.createElement('span')
this.renderer.addClass(span, "close")
this.renderer.appendChild(this.div, span);
this.renderer.insertBefore(this.renderer.parentNode(this.el.nativeElement),this.div,this.el.nativeElement,);
this.renderer.listen(this.div, 'click', ($event) => {
this.control.control.setValue(null);
$event.stopPropagation();
});
}
clearCross() {
if (this.div)
{
this.renderer.removeChild(this.renderer.parentNode(this.el.nativeElement), this.div)
this.div=null
}
}
}
答案 2 :(得分:0)
谢谢大家的答复,
这可以在@ContentChildren
上使用,因为@ContentChild
总是给出第一个/父ngModel,但是我需要一个特定的ngModel,所以我使用了@ContentChildren
喜欢
@ContentChildren(NgControl) input;
this.input.last.control.setValue(null);
就我而言,目前只有一个孩子,所以暂时我以this.input.last.control.setValue(null);
的身份访问
如果有多个ngModel,怎么办?如何获取特定的ngModel
顺便说一句,我已经创建了对材料选择Stackblitz的搜索,在打开时,我将焦点放在输入字段(搜索框)上,并在关闭时,清除其ngModel
注意:我不想创建组件,因为这会增加大量的代码和逻辑