Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing Component Property from Directive in Angular2

Tags:

angular

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

<span contenteditable="true"  ng-model="model.property" placeholder="Something">

Editing the element would fire $setViewValue(element.html() and it worked as expected.

I would like to make something in Angular2 with a similarly succinct template syntax. Ideally, I would like the template to look like this:

<span contentEditable="true" [(myProperty)]="name"></span>

where 'name' is a property on the component and have the directive update the component when changed. I feel like I'm close with this (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; 
    }
}

This idea works if I pass an object like {name: "someName"} but if just pass a property it seems like it's passing the value, but not the reference and so the binding doesn't flow back to the component. Is there a way to do this that will still allow a template syntax that isn't verbose but still allows easy reuse of the directive.

like image 505
Mark Avatar asked Jan 18 '16 02:01

Mark


People also ask

Can we use component as directive?

A component is a single unit that encapsulates both view and logic whereas directives are used to enhance the behavior of components or dom elements and it doesn't have any templates. Component extends directive so every component is a directive.

What is difference between directive and component?

The Component is used to break up the application into smaller components. That is why components are widely used in later versions of Angular to make things easy and build a total component-based model. The Directive is used to design reusable components, which are more behavior-oriented.

How do you use directive components?

This should be a component, and here's how it use: @Component({ selector: 'nb-menu', styleUrls: ['./menu. component. scss'], template: ` <ul class="menu-items"> <ng-container *ngFor="let item of items"> <li nbMenuItem *ngIf="!

Which directive definition option is used to replace the current element if true?

replace: true means that the content of the directive template will replace the element that the directive is declared on, in this case the <div myd1> tag.


2 Answers

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!

like image 152
Anjana Silva Avatar answered Sep 30 '22 07:09

Anjana Silva


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

like image 34
Albena Kertova Avatar answered Sep 30 '22 05:09

Albena Kertova