Changing Component Property from Directive in Angular2

前端 未结 3 1217
面向向阳花
面向向阳花 2021-01-02 04:49

I have an Angular 1 app that works with a simple contentEditable directive, which can be used like this in templates:



        
相关标签:
3条回答
  • 2021-01-02 05:19

    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.

    Update

    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.

    0 讨论(0)
  • 2021-01-02 05:23

    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!

    0 讨论(0)
  • 2021-01-02 05:35

    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

    0 讨论(0)
提交回复
热议问题