2016-06-14 94 views
8

我需要在Angular2中構建一個readmore指令。這個指令的作用是通過「閱讀更多」和「關閉」鏈接來摺疊和擴展長文本塊。不是以字符數爲基礎,而是基於指定的最大高度。Angular 2更多指令

<div read-more [maxHeight]="250px" [innerHTML]="item.details"> 
</div> 

任何人都可以請指導什麼是最可靠的方式來獲取/設置此特定情況下元素的高度。

有關如何實施此特定指令的任何指導方針也將受到高度讚賞。

我需要建立這樣的事情https://github.com/jedfoster/Readmore.js

解決方案:

與Andzhik我能夠建立以下組件,它符合我的要求幫助。

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

@Component({ 
    selector: 'read-more', 
    template: ` 
     <div [innerHTML]="text" [class.collapsed]="isCollapsed" [style.height]="isCollapsed ? maxHeight+'px' : 'auto'"> 
     </div> 
      <a *ngIf="isCollapsable" (click)="isCollapsed =! isCollapsed">Read {{isCollapsed? 'more':'less'}}</a> 
    `, 
    styles: [` 
     div.collapsed { 
      overflow: hidden; 
     } 
    `] 
}) 
export class ReadMoreComponent implements AfterViewInit { 

    //the text that need to be put in the container 
    @Input() text: string; 

    //maximum height of the container 
    @Input() maxHeight: number = 100; 

    //set these to false to get the height of the expended container 
    public isCollapsed: boolean = false; 
    public isCollapsable: boolean = false; 

    constructor(private elementRef: ElementRef) { 
    } 

    ngAfterViewInit() { 
     let currentHeight = this.elementRef.nativeElement.getElementsByTagName('div')[0].offsetHeight; 
     //collapsable only if the contents make container exceed the max height 
     if (currentHeight > this.maxHeight) { 
      this.isCollapsed = true; 
      this.isCollapsable = true; 
     } 
    } 
} 

用法:

<read-more [text]="details" [maxHeight]="250"></read-more> 

如果有可能是任何改進,請隨時提出。

+0

的setTimeout的內部查找currentHeight(_ => {.....})將消除一些窗口在角度運行更改檢測時調整大小問題。看到http://stackoverflow.com/questions/38930183/angular2-expression-has-changed-after-it-was-checked-binding-to-div-width-wi – chenk

回答

11

我認爲你需要一個Component而不是DirectiveComponents更有意義,因爲您需要添加閱讀更多按鈕/鏈接,即更新DOM。

@Component({ 
    selector: 'read-more', 
    template: ` 
     <div [class.collapsed]="isCollapsed"> 
      <ng-content></ng-content> 
      <div (click)="isCollapsed =! isCollapsed">Read more</div> 
     </div> 
    `, 
    styles: [` 
     div.collapsed { 
      height: 250px; 
     } 
    `] 
}) 

export class ReadMoreComponent { 
    isCollapsed: boolean = true; 
} 

用法:

<read-more> 
    <!-- you HTML goes here --> 
</read-more> 
+0

非常感謝Andzhik的回覆。我做了一些修改組件:模板:'

Read more
' 風格:[' 格。摺疊{ height:150px; 溢出:隱藏; } '] 我還補充說明 @Input() text:string; 但我仍然需要一種方法來獲取包含文本的div的高度,以便在此基礎上我可以決定是顯示還是隱藏閱讀更多鏈接。 –

+0

您可以使用'ElementRef' http://ngcourse.rangle.io/handout/advanced-components/elementref.html直接訪問代表您的'Component'的DOM元素。 PS:如果您對我的原始答案感到滿意,請接受它,謝謝。 –

+0

我試過,但當我在構造函數中或在ngAfterContentChecked登錄控制檯時,它返回未定義的console.log(this.el.nativeElement.height);我也試過@HostBinding('style.height')private height:string;但其也未定義。 –

10

與Andzhik的幫助下,我能夠建立以下組件,符合我的要求。

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

@Component({ 
    selector: 'read-more', 
    template: ` 
     <div [innerHTML]="text" [class.collapsed]="isCollapsed" [style.height]="isCollapsed ? maxHeight+'px' : 'auto'"> 
     </div> 
      <a *ngIf="isCollapsable" (click)="isCollapsed =! isCollapsed">Read {{isCollapsed? 'more':'less'}}</a> 
    `, 
    styles: [` 
     div.collapsed { 
      overflow: hidden; 
     } 
    `] 
}) 
export class ReadMoreComponent implements AfterViewInit { 

    //the text that need to be put in the container 
    @Input() text: string; 

    //maximum height of the container 
    @Input() maxHeight: number = 100; 

    //set these to false to get the height of the expended container 
    public isCollapsed: boolean = false; 
    public isCollapsable: boolean = false; 

    constructor(private elementRef: ElementRef) { 
    } 

    ngAfterViewInit() { 
     let currentHeight = this.elementRef.nativeElement.getElementsByTagName('div')[0].offsetHeight; 
     //collapsable only if the contents make container exceed the max height 
     if (currentHeight > this.maxHeight) { 
      this.isCollapsed = true; 
      this.isCollapsable = true; 
     } 
    } 
} 

用法:

<read-more [text]="details" [maxHeight]="250"></read-more> 
8

我做了使用字符長度,而不是格大小的版本。

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

@Component({  
    selector: 'read-more', 
    template: ` 
     <div [innerHTML]="currentText"> 
     </div> 
      <a [class.hidden]="hideToggle" (click)="toggleView()">Read {{isCollapsed? 'more':'less'}}</a> 
    ` 
}) 

export class ReadMoreComponent implements OnChanges { 
    @Input() text: string; 
    @Input() maxLength: number = 100; 
    currentText: string; 
    hideToggle: boolean = true; 

    public isCollapsed: boolean = true; 

    constructor(private elementRef: ElementRef) { 

    } 
    toggleView() { 
     this.isCollapsed = !this.isCollapsed; 
     this.determineView(); 
    } 
    determineView() { 
     if (this.text.length <= this.maxLength) { 
      this.currentText = this.text; 
      this.isCollapsed = false; 
      this.hideToggle = true; 
      return; 
     } 
     this.hideToggle = false; 
     if (this.isCollapsed == true) { 
      this.currentText = this.text.substring(0, this.maxLength) + "..."; 
     } else if(this.isCollapsed == false) { 
      this.currentText = this.text; 
     } 

    } 
    ngOnChanges() { 
     this.determineView();  
    } 
} 

用法:

<read-more [text]="text" [maxLength]="100"></read-more> 
+0

謝謝,那正是我需要的! – Rodney

+0

有關html標籤的內容呢? –

+0

我認爲它應該與html一起工作。它使用[innerHTML]指令 – jugg1es

0
import { Component, Input,OnChanges} from '@angular/core'; 
@Component({  
    selector: 'read-more', 
    template: ` 
     <div [innerHTML]="currentText"></div> 
     <span *ngIf="showToggleButton"> 
      <a (click)="toggleView()">Read {{isCollapsed? 'more':'less'}}</a> 
     </span>` 
}) 

export class ReadMoreDirective implements OnChanges { 

    @Input('text') text: string; 
    @Input('maxLength') maxLength: number = 100; 
    @Input('showToggleButton')showToggleButton:boolean; 

    currentText: string; 

    public isCollapsed: boolean = true; 

    constructor(
     //private elementRef: ElementRef 
    ) { 

    } 
    toggleView() { 
     this.isCollapsed = !this.isCollapsed; 
     this.determineView(); 
    } 

    determineView() { 

     if (this.text.length <= this.maxLength) { 
      this.currentText = this.text; 
      this.isCollapsed = false; 
      return; 
     } 

     if (this.isCollapsed == true) { 
      this.currentText = this.text.substring(0, this.maxLength) + "..."; 
     } else if(this.isCollapsed == false) { 
      this.currentText = this.text; 
     } 

    } 

    ngOnChanges() { 
     if(!this.validateSource(this.text)) { 
      //throw 'Source must be a string.'; 
      console.error('Source must be a string.'); 
     } 
     else{ 
      this.determineView(); 
     } 
    } 

    validateSource(s) { 
     if(typeof s !== 'string') { 
      return false; 
     } else { 
      return true; 
     } 
    } 
} 

和使用

<read-more [text]="this is test text" [maxLength]="10" [showToggleButton]="true"></read-more>