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.
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!
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
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;
};
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.
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.
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.
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>
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
}
])
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.
(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
init()
process, it's classNames will be 'auto-folded auto-folded--folded'
.'auto-folded--folded'
and 'auto-folded--unfolded'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With