Angular 2 Read More Directive

前端 未结 10 1723
一个人的身影
一个人的身影 2020-12-01 09:41

I need to build a readmore directive in Angular2. What this directive will do is for collapse and expand long blocks of text with \"Read more\" and \"Close\" links. Not on t

相关标签:
10条回答
  • 2020-12-01 10:06

    I think you'll need a Component rather then Directive. Components makes more sense since you need to add Read more button/link, i.e. update DOM.

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

    Usage:

    <read-more>
       <!-- you HTML goes here -->
    </read-more>
    
    0 讨论(0)
  • 2020-12-01 10:06

    Just a slight improvement of @Andrei Zhytkevich code (useful for markdown)

    import {
      Component,
      AfterViewInit,
      ViewChild,
      ElementRef,
      Attribute,
      ChangeDetectionStrategy } from '@angular/core';
    
    @Component({
      changeDetection: ChangeDetectionStrategy.OnPush,
      selector: 'ui-read-more',
      template: `
        <div [class.collapsed]="isCollapsed" [style.height]="_height">
          <div #wrapper>
            <ng-content></ng-content>
          </div>
        </div>
        <div class="read-more">
          <button
          type="button"
          class="btn btn-light" (click)="onIsCollapsed()">{{isCollapsed ? 'More' : 'Less'}}</button>
        </div>
      `,
      styles: [`
        :host{
          display: block;
        }
        .collapsed {
          overflow: hidden;
          padding-bottom: 1rem;
        }
        .read-more{
          display: flex;
          justify-content: flex-end;
        }
      `]
    })
    export class UiReadMoreComponent implements AfterViewInit{
      @ViewChild('wrapper') wrapper: ElementRef;
      isCollapsed: boolean = true;
      private contentHeight: string;
      private _height: string;
      constructor(@Attribute('height') public height: string = '') {
        this._height = height;
      }
      ngAfterViewInit() {
        this.contentHeight = this.wrapper.nativeElement.clientHeight + 'px';
      }
      onIsCollapsed(){
        this.isCollapsed = !this.isCollapsed;
        this._height = this.isCollapsed ? this.height : this.contentHeight;
      }
    }
    

    Usage

    <ui-read-more height="250px">
     <ngx-md>
        {{post.content}}
     </ngx-md>
    </ui-read-more>
    
    0 讨论(0)
  • 2020-12-01 10:09

    Again i solved these types of problem with dynamic data and full controlling.

     <div class="Basic-Info-para">
       <p>
         <span *ngIf="personalBasicModel.professionalSummary.length>200" id="dots"> 
             {{personalBasicModel.professionalSummary | slice:0:200}} ...
        </span>
         <span id="more">{{personalBasicModel.professionalSummary }}
    </span>
     </p>
    </div> 
    

    Here , personalBasicModel.professionalSummary contain string . like any text.
    slice:0:200 = use slice pipe for splice string with 200 character length . you can be change length according your requirement. id="dots" & id="more" two important thing.

    <div class="Basic-Info-SeeMore">
                <button class="SeeMore"(click)="showMore(paasValueOn_SeeMoreBtn)">
                    {{showLess_More}}
                </button>
            </div>
    

    Here we define a button with dynamic text (see more and see less ) with click event.

    //---------------------------------- ts file -----------------------------------//

    Define variable

    showLess_More : string = "SEE MORE...";
    paasValueOn_SeeMoreBtn : boolean = true;

    Event(Method) fire when user click on see more button

     showMore(data:boolean){
        if(data){
          $("#dots").css('display', 'none');
          $("#more").css('display', 'inline');
          this.showLess_More = "SEE LESS ...";
          this.paasValueOn_SeeMoreBtn = false;
        }else{
          $("#dots").css('display', 'inline');
          $("#more").css('display', 'none');
          this.showLess_More = "SEE MORE...";
          this.paasValueOn_SeeMoreBtn = true;
    
        }
    
      }
    
    0 讨论(0)
  • 2020-12-01 10:11
    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;
            }
        }
    }
    

    and usage

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

    0 讨论(0)
  • 2020-12-01 10:11

    If you want to display the text to the maximum number of chars without cutting any word, change this line of code:

    this.currentText = this.text.substring(0, this.maxLength) + "...";
    

    To:

    this.currentText = this.text.substring(0, this.maxLength);
    this.currentText = this.currentText.substr(0, Math.min(this.currentText.length, this.currentText.lastIndexOf(" ")))
    this.currentText = this.currentText + "..."
    
    0 讨论(0)
  • 2020-12-01 10:12

    lineheight approach:-

    lineheight and little calculation and some css text-overflow: ellipsis; does this job.

    .css

    .descLess {
      margin-bottom: 10px;
      text-overflow: ellipsis;
      overflow: hidden;
      word-wrap: break-word;
      display: -webkit-box;
      line-height: 1.8;      <==== adjust line-height...a/q to your need
      letter-spacing: normal;
      white-space: normal;
      max-height: 52px;  <==== 250px etc:-
      width: 100%;
      /* autoprefixer: ignore next */
      -webkit-line-clamp: 2; <==== clamp line 2...or 3 or 4 or 5...
      -webkit-box-orient: vertical;
    }
    

    .html

        <div class="col-12 rmpm">
              <div id="descLess" *ngIf="seeMoreDesc === 'false'" class="descLess col-12 rmpm">
                    {{inputData?.desc}}
               </div>
            <div *ngIf="seeMoreDesc === 'true'" class="col-12 rmpm" style="margin-bottom: 10px;line-height: 1.8;"> 
       <!--Use Line height here-->
                    {{inputData?.desc}}
                   </div>
            <span class="seeMore" *ngIf="seeMoreDesc === 'false' && lineHeightDesc > 21"
                 (click)="updateSeeMore('seeMoreDesc', 'true')">
                     See More
            </span>
            <span class="seeMore" *ngIf="seeMoreDesc === 'true'"
                   (click)="updateSeeMore('seeMoreDesc', 'false')">
                       See Less
            </span>
             </div>
    

    .ts

    declare const $:any;
    seeMoreDesc = 'false';
    seeMore = '';
    inputData = {
       'desc':'Lorem Ipusme dummy text..................'
     }
     constructor(
            private eRef: ElementRef,
            private cdRef : ChangeDetectorRef
        ) {}
        ngAfterViewChecked() {
           // pass line height here
            this.lineHeightDesc = (Number($('#descLess').height()) / 1.8);
            this.cdRef.detectChanges();
        }
    
    
         public updateSeeMore(type, action) {
             if (type === 'seeMoreDesc') {
                   this.seeMoreDesc = action;
                    this.cdRef.detectChanges();
                } else if (type === 'seeMore') {
                    this.seeMore = action;
                    this.cdRef.detectChanges();
                }
    
            }
    
    0 讨论(0)
提交回复
热议问题