I have an Angular 1 app that works with a simple contentEditable directive, which can be used like this in templates:
The directive doesn't know about its parent name property. You can though emit an event from the directive and catch it in the parent. Check this example
@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);
}
Now that our directive is emitting correctly, we have to catch the value in the component. For brevity only the template
<div contentEditable="true" [myProperty]="name" (updateProperty)="name = $event"></div>
updateProperty is the @Output from the directive. When it gets triggered we catch it and the value we emied will be assigned to $event. After that we assign $event to our property name and you got your app working.
Here's your plnkr working. I hope it helps.
Thank to this answer I saw that it is possible what you asked for.
You can match the Output to what is called when the syntax [()] is desugared. If you have a syntax like [(myProperty)]="expr" it is desugared to [myProperty]="expr" (myPropertyChange)="expr = $event"
So changing the original answer to as follows
@Output() myPropertyChange: EventEmitter<any> = new EventEmitter();
update(event){
this.myPropertyChange.emit(this.el.nativeElement.innerText);
}
It will give you this template, which is what you asked from the beginning.
<div contentEditable="true" [(myProperty)]="name"></div>
Here's the plnkr updated to the real correct answer.
If you simply want to change the value using pure JavaScript and do not want to go towards the [(model]) route, then this is for you.
const input = this.el.nativeElement.querySelector('#myElement');
input.value = 'My Programmatic Value';
input.dispatchEvent(new Event('input'));
Issue - https://github.com/text-mask/text-mask/issues/696
Solution - https://github.com/text-mask/text-mask/issues/696#issuecomment-354887412
Hope this helps someone.
Cheers!
I found this very smooth solution that worked for my case (adding a readonly role to existing UI) using the @Host decorator for injecting the component you want to set property of in the Directive. In my case I have an abstract class with readonly property that is then extended by all custom components.
@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;
}
}
}
Where in the selector part I put directly the selectors of my custom components that implement the BaseComponent (e.g. my-comp). This is because I want the directive to be automatically applied to all instances of my-comp. I have an additional param that can turn the directive off.
If this is a single component to use the directive - put it on the place of BaseComponent.
If multiple components will use the same directive - you'll need to specify what will be injected on the @Host parameter by specifying a provider in the extending class:
@Component({
selector: 'my-comp',
...
providers: [{
provide: BaseComponent, useExisting: forwardRef(() => MyComp)
}]
})
export class MyComp extends BaseComponent { ... }
Source: https://github.com/angular/angular/issues/13776