Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create read more link in AngularJS

I want to create a link with read more text. if there are more than 3 lines in a paragraph this link should be visible and clicking on this it show display all the lines.

like image 467
Krishna Bhatt Avatar asked Jan 28 '14 08:01

Krishna Bhatt


4 Answers

Based on some of the information here I've put together a nice show more/less implementation

Directive Definition showMore.js

.directive('showMore', 
function(){
    return {
        templateUrl: 'showMore.html',
        restrict: 'A',
        transclude: true,
        scope:{
            'showMoreHeight': '@'
        },
        controller: ['$scope', '$element', '$interval', function($scope, $element, $interval) {

            $scope.expanded = false;

            $interval(function(){
                renderStyles();
            }, 300);

            $scope.expandable = false;
            function renderStyles(){
                if($element.height() >= $scope.showMoreHeight && $scope.expanded === false){
                    $scope.expandable = true;
                }
            }

            $scope.showLessStyle = {
                'max-height': $scope.showMoreHeight + 'px',
                'overflow': 'hidden'
            };

        }]
    };
});

showMore.html

<span>
    <div ng-style='showLessStyle' ng-hide='expanded' ng-transclude>
    </div>
    <div ng-show='expanded' ng-transclude>
    </div>
    <a style='float:right;' ng-hide='expanded || !expandable' ng-click='expanded = !expanded' localize>show more</a>
    <a style='float:right;' ng-show='expanded && expandable' ng-click='expanded = !expanded'>show less</a>
</span>

The usage is fairly simple just transclude what ever you want to show more/less of

USEAGE:

<div show-more show-more-height='150'>
    <div class='showMoreContent'></div>
</div>

I hope this is somewhat helpful!

like image 132
Aaron Avatar answered Nov 13 '22 09:11

Aaron


I wanted to do the same thing, so I created a directive. Have a look here: https://gist.github.com/doukasd/0744566c5494ebc8643f

Usage is pretty simple:

<p data-dd-collapse-text="100">{{veryLongText}}</p>

Where 100 is the character limit you want to specify.

UPDATE: dd-text-collapse

like image 41
Dimitris Avatar answered Nov 13 '22 09:11

Dimitris


For read more , you can use angular limitTo filter for limiting your paragraph to character's length instead of limiting paragraph to line numbers .

You can use something like this :

in html

<p> {{myString | limitTo:numLimit}} </p>
<button type='button' ng-click="readMore()">read more</button>

in controller

$scope.numLimit=200;
$scope.readMore=function(){
$scope.numLimit=10000;
};
like image 10
FatemehFattahi Avatar answered Nov 13 '22 10:11

FatemehFattahi


There can be some workaround.

basic idea is like this

 1. at first, use javascript to calculate the original height
 2. if higher than 3 lines , set the overflow to hidden and show a button. The button is used to toggle state
 3.  if not,  do nothing

About the button.

If the button is out of text area, it's no problem for you I think. If you need the button inline within the element, there are 2 possibilitis.

  1. if you want it position fixed at right-bottom, create a gradient background for the button, fade-out effect. It looks nice and very simple.

    here is jsfiddle: http://jsfiddle.net/sunderls/HYHZ6/ . Everytime toggling the state, you actually change the class of the element.

  2. if you want it right after the end of text? it's a little tricky, since even if text height is 3 lines, you cannot be sure whether it remains 3 lines height , after appending a button next to it.

    I think one way is to use Range API, to calculate the paragraph dimensions, (I've used the api in my collamark.com, it's powerful but different browsers have different behaviors). Actually you can get the dimensions of every lines dynamically. And by some backwards loops, you can get the appropriate substring of the text, to show in collapsed mode, which is just right for 3 lines height with a button. (the api doc is here: https://developer.mozilla.org/en-US/docs/Web/API/range)

    So now every time you toggle the state, you actually is change the text. not the class.

Here begins the Code when do it in Angular

template

first, this kind of feature is a standalone module which you can reuse everywhere, so in your template, we create a new directive autoFolded, sth like this:

<auto-folded>
    <p>Some text here, maybe long maybe short</p>
</auto-folded>

directive.coffee

then we handle all the logic in directive definition( sorry for writing in coffee though)

directive('autoFolded',[
 '$window'
($window) ->
    return {
        restrict: 'E'
        transclude: true
        template: '<div class="auto-folded"><div ng-transclude></div><a href ng-click="toggleFoldedState()" class="auto-folded--more"></a></div>'
        link: (scope, element, attrs)->
            $$window = $ $window
            content = $(element).find('.auto-folded')

            toggleFoldedState = ->
                if content.hasClass 'auto-folded--folded'
                    content.removeClass('auto-folded--folded').addClass('auto-folded--unfolded')
                else if content.hasClass 'auto-folded--unfolded'
                    content.removeClass('auto-folded--unfolded').addClass('auto-folded--folded')

                return

            scope.toggleFoldedState = toggleFoldedState


            init = ()->
                contentHeight = content.outerHeight()
                if contentHeight > 48
                    content.addClass 'auto-folded--folded'
                content.show()

            $$window.on 'ngcontentloaded',init

    }
])

here is the explaination

for this directive contains text it doesn't know, so it's a translucent direcitve. Like a modal popup, it contains the Text and a toggle button.

restrict: 'E'
transclude: true
template: '<div class="auto-folded"><div ng-transclude></div><a href ng-click="toggleFoldedState()" class="auto-folded--more"></a></div>'

when clicking the button, it actually do the toggling. If unfolded, then fold it; If foled, then unfolded. We accomplish this by toggling the classNames, the cold is straightforward

            toggleFoldedState = ->
                content.css 'color','red'

                if content.hasClass 'auto-folded--folded'
                    content.removeClass('auto-folded--folded').addClass('auto-folded--unfolded')
                else if content.hasClass 'auto-folded--unfolded'
                    content.removeClass('auto-folded--unfolded').addClass('auto-folded--folded')

                return

and we use ng-click="toggleFoldedState()" to bind this action to the toggling button

We have to do some initial work to fold the text if it's tall enough at page loaded. However, link function of directive is to create the actual Dom, before dom rendering.So in link, we cannot know the height, that's why we register the init() to ngcontentloaded event:

            init = ()->
                contentHeight = content.outerHeight()
                if contentHeight > 48
                    content.addClass 'auto-folded--folded'
                content.show()

            $$window.on 'ngcontentloaded',init

here I use 48px as 3-line-height, you can define your own, or calculate dynamically from the dom, like content.css('lineHeight').

since this is done after dom rendering, so the text is already displayed before init(). There will be a ugly slideUp effect. That's why we first hide the dom using css(as following), and content.show() in init

So we are done with directive, the folded/unfoled state are controlled by className. here we go.

css.sass

(sorry I wrote it in sass)

.auto-folded
    display: none  //only display after init()
    position: relative

    .auto-folded--more //the button is placed at right-bottom, and default to hidden
        display: none
        position: absolute
        right: 0
        bottom: 0

    &.auto-folded--folded //when folded, set maxHeight, and overflow to hidden
        max-height: 48px
        overflow: hidden
        .auto-folded--more // toggling button is displayed,
            display: block
            &:before // and it's text is "more"
                content: "more"

    &.auto-folded--unfolded //when unfoled, s
        .auto-folded--more  // toggling button is displayed
            display: block
            &:before // and it's text is "hide"
                content: "hide" 

So the text of toggling button and visibility of it , are all controlled by the class of its parent.

for the parent 1. if text is not 3-line height, it will only have 'auto-folded' as css class, so the button is hidden

  1. if text is over 3-line height, in init() process, it's classNames will be 'auto-folded auto-folded--folded'.
    then the button is shown. clicking it will toggle parent's classNames between 'auto-folded--folded' and 'auto-folded--unfolded'
like image 5
sunderls Avatar answered Nov 13 '22 08:11

sunderls