我有一个Angular 1应用程序,它使用简单的contentEditable
指令,可以在模板中使用这样的指示:
<span contenteditable="true" ng-model="model.property" placeholder="Something">
编辑元素会触发$setViewValue(element.html()
并按预期工作。
我想在Angular2中使用类似的简洁模板语法。理想情况下,我希望模板看起来像这样:
<span contentEditable="true" [(myProperty)]="name"></span>
其中'name'是组件上的属性,并且在更改时使指令更新组件。我觉得我很接近这个(Plunker Link):
//our root app component
import {Component, Input, Output Directive, ElementRef, Renderer, OnInit} from 'angular2/core'
@Directive({
selector: '[contentEditable]',
host: {
'(blur)': 'update($event)'
}
})
export class contentEditableDirective implements OnInit {
@Input() myProperty;
constructor(private el: ElementRef, private renderer: Renderer){}
update(event){
this.myProperty = this.el.nativeElement.innerText;
}
ngOnInit(){
this.el.nativeElement.innerText = this.myProperty;
}
}
如果我传递像{name: "someName"}
之类的对象,这个想法是有效的,但是如果只传递一个属性,它似乎传递了值,而不是引用,因此绑定不会流回到组件。有没有办法做到这一点,仍然允许模板语法不冗长,但仍然允许轻松重用指令。
答案 0 :(得分:8)
该指令并不了解其父name
属性。但是,您可以从指令中发出事件并在父项中捕获它。检查此示例
@Directive({
selector: '[contentEditable]',
host: {
'(input)': 'update($event)' // I changed it to input to see the changes immediatly
}
})
export class contentEditableDirective implements OnInit {
// Output that will emit outside the directive
@Output() updateProperty: EventEmitter<any> = new EventEmitter();
// When 'update' is called we emit the value
update(event){
this.updateProperty.emit(this.el.nativeElement.innerText);
}
既然我们的指令正确地发出,我们必须捕获组件中的值。 为简洁起见,仅提供模板
<div contentEditable="true" [myProperty]="name" (updateProperty)="name = $event"></div>
updateProperty
是指令中的@Output
。当它被触发时,我们会抓住它,我们发现的值将被分配给$event
。之后,我们将$event
分配给我们的媒体资源name
,您的应用就可以了。
这是您的plnkr工作。我希望它有所帮助。
感谢answer我看到你要求的可能。
您可以将输出与语法[()]
被取消时调用的内容进行匹配。如果您使用[(myProperty)]="expr"
之类的语法,则会将其置于[myProperty]="expr" (myPropertyChange)="expr = $event"
所以将原来的答案改为如下
@Output() myPropertyChange: EventEmitter<any> = new EventEmitter();
update(event){
this.myPropertyChange.emit(this.el.nativeElement.innerText);
}
它将为您提供此模板,这是您从一开始就提出的问题。
<div contentEditable="true" [(myProperty)]="name"></div>
此处plnkr更新为真实的正确答案。
答案 1 :(得分:2)
我发现这个非常流畅的解决方案适用于我的情况(使用现有的UI添加只读角色)使用@Host装饰器来注入要在Directive中设置其属性的组件。就我而言,我有一个具有readonly属性的抽象类,然后所有自定义组件都对其进行了扩展。
@Directive({
selector: 'authCheck'
})
export class ComponentReadonlyDirective implements OnInit {
constructor(private authService: AuthorizationService,
@Host() private baseComponent: BaseComponent) {
}
ngOnInit() {
if (!this.authorizationService.canEdit()) {
this.baseComponent.readonly = true;
}
}
}
在选择器部分中,我直接放置实现BaseComponent的自定义组件的选择器(例如my-comp)。这是因为我希望将指令自动应用于my-comp的所有实例。我还有一个可以关闭指令的参数。
如果这是使用指令的单个组件,请将其放在BaseComponent的位置。
如果多个组件将使用同一指令-您需要通过在扩展类中指定提供程序来指定将在@Host参数上注入的内容:
@Component({
selector: 'my-comp',
...
providers: [{
provide: BaseComponent, useExisting: forwardRef(() => MyComp)
}]
})
export class MyComp extends BaseComponent { ... }
答案 2 :(得分:0)
如果您只想使用纯 JavaScript 来更改值,而 则不想转到 [(model] )路线,那么此路线适合您。
const input = this.el.nativeElement.querySelector('#myElement');
input.value = 'My Programmatic Value';
input.dispatchEvent(new Event('input'));
问题-https://github.com/text-mask/text-mask/issues/696
解决方案-https://github.com/text-mask/text-mask/issues/696#issuecomment-354887412
希望这对某人有帮助。
干杯!