简体   繁体   中英

Dynamically Update value of custom attribute in Angular2 Directive

I have written a Directive and a Component, I need to pass the value from the Component to the directive and accordingly hide the element. In simple words I'm trying to create an directive similar to ng-show and ng-hide of Angular1 in Angular2.

headermenu.component.ts

import {Component} from 'angular2/core';
import {DataService} from './data-service.service';
import {ShowHeaderDirective} from './show-header.directive';
@Component({
selector: 'header-menu',
template: `
    <header class="login-header">
    <div class="header-top">
        <div class="container">
          <nav class="navbar navbar-default">
            <div class="container-fluid">
             <div>
                <ul class="nav navbar-nav navbar-right">
                  <li [showHeader]="dispFlag"><a href="javascript:void(0)">Mr. Abc!</a></li>
                  <li><span>|</span></li>
                </ul>
              </div>
            </div><!--/.container-fluid -->
          </nav>
        </div>
    </div>
</header>
`,
directives: [ShowHeaderDirective],
providers:[DataService]
})

export class HeaderComponent {
    dispFlag;
constructor(dataService: DataService){
    this.dispFlag=dataService.headerDisplayFlag;
}
}

show-header.directive.ts

import {Directive, ElementRef, Renderer, Input} from 'angular2/core';

@Directive({
    selector: '[showHeader]'
})

export class ShowHeaderDirective{
private _el:HTMLElement;
constructor(private el: ElementRef, private renderer: Renderer){
    debugger;
    /* alert(this.el.nativeElement.attributes.showheader.value);
    if(this.el.nativeElement.attributes.showheader.value=="false"){
        this.el.nativeElement.style.display="none";
    } */
}
}

I need to pass the value of dataFlag value which is collected from dummy service and send it to directive and directive will accordingly show/hide the element.

Note: dataFlag - hold the value true/ false.

Currently I am not able to get any output from it so commented the code.

To be able to pass a value to a component or directive use @Input()

export class ShowHeaderDirective{

  @Input() isHidden:boolean = false;  

  private _el:HTMLElement;
  constructor(private el: ElementRef, private renderer: Renderer){
    debugger;
    /* alert(this.el.nativeElement.attributes.showheader.value);
    if(this.el.nativeElement.attributes.showheader.value=="false"){
        this.el.nativeElement.style.display="none";
    } */
  }
}

and use it like

<li showHeader isHidden="!showHeader"

You can also use the selector name for the input

@Input() showHeader:boolean = false;  

and use it like

<li [showHeader]="!showHeader"

But you can also use the hidden attribute that all elements have

<li [hidden]="!showHeader"

I don't understand why do you need a custom directive for hiding elements while you have [hidden] attribute and *ngIf (Where you can pass functions too). But anyway to get Information from attribute directive you have to use @Input() with the name of the selector in there like this:

export class ShowHeaderDirective implements OnInit{

@Input('showHeader') somealias:boolean;
construct(private el: ElementRef){}

 ngOnInit() {
    if(this.somealias === true){
       //do something with your element
    }
 }

You must use OnInit because the input value is not available in the constructor

I tried something, maybe this will help in showing that we can update the values of custom attributes in Angular.

Here I have created 2 components app-list-display and app-list-item-detail the idea is to use the former to show data in a list fashion, and when the user clicks on any of the item in the list an custom event is emitted which triggers an action on the main app component.

app component then changes a value of a variable , this variable is then fed as an custom property to the other app-list-item-detail component.

Here is the code for app-list-display.html

<ul class="list-group" style="float:left margin-left=0px;">
  <li (click)="showItem(item)" *ngFor="let item of items" class="list-group-item list-group-item-action text-justify">{{item.name}}</li>
</ul>

app-list-display.ts

import { Component, OnInit , Input , Output , EventEmitter } from '@angular/core';

@Component({
  selector: 'app-list-display',
  templateUrl: './list-display.component.html',
  styleUrls: ['./list-display.component.css']
})
export class ListDisplayComponent implements OnInit {

  @Input('itemsToBeDisplayed')items:any; 
  @Output('transferItem') transfer = new EventEmitter<{name:string}>();

  constructor() { }

  ngOnInit() {
  }

  showItem(item){
    console.log("in showItem "+JSON.stringify(item,null,2))
    this.transfer.emit(item)
  }

}

app-list-item-detail.html This just has a sample text to show data changing when the user clicks on different items in the list.

<h4>We are in list detail component
{{showSomething.something}}</h4>

app-list-item-detail.ts This is the supporting ts file of the component which indicates that it has a custom attribute shown by the @Input decorator.

import { Component, OnInit , Input} from '@angular/core';

@Component({
  selector: 'app-list-item-detail',
  templateUrl: './list-item-detail.component.html',
  styleUrls: ['./list-item-detail.component.css']
})
export class ListItemDetailComponent implements OnInit {

  @Input()showSomething:any;

  constructor() { }

  ngOnInit() {
  }

}

Now in the app.component.html , which uses the above two components, as shown below

<app-list-display [itemsToBeDisplayed]="someArrayData" (transferItem)="showSentItem($event)">

<app-list-item-detail [showSomething]="someTxData">
</app-list-item-detail>

If you notice here in the app-list-display component the custom event is supplied a function showSentItem . And to the other component app-list-item-detail a object called someTxData is being injected as a custom attribute. The object injected here can be changed by a simple function call, which can also mean a simple custom event which in our case will be showSentItem

So now in app.component.ts

import { Component } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
 someArrayData = [{name:"John"},{name:"Jane"}];
  someTxData:any;
  showSentItem(item){
    item.something = item.name
    this.someTxData = item;
  } 
}

If you see the last line this.someTxData is being given the object from the row of the list from the first component(thanks to custom events), and this same object is being fed to the second component custom attribute.

So here ideally, custom event on one component is talking to the custom attribute of the other via the implementor.

Apologies for the long answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM