Reputation: 1977
Is there a way to apply a filter to the slot content in a Vue component?
To clarify, I would like to truncate the text included manually in the HTML. For example I would like to transform this:
<!-- In the view -->
<my-component>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cumque,
laboriosam quasi rerum obcaecati dignissimos autem laudantium error
quas voluptatibus debitis?
</my-component>
into this:
<!-- Generated component -->
<div>
Lorem ipsum dolor sit amet, consectetur adipisicing ...
</div
I can't seem to find this information in the documentation.
Thank you.
Upvotes: 33
Views: 62137
Reputation: 930
You can achieve your goal by using a custom Vue component that accepts the slot content and applies a text truncation filter. The advantage of this approach is that 'text-clipper'can parse the HTML which means that you can pass any component that renders html or even html with v-html or also just normal text
For example:
<template>
<div>
<slot></slot>
<span>{{ truncatedText }}</span>
</div>
</template>
<script>
import clipper from 'text-clipper';
export default {
name: 'TruncateText',
props: {
maxLength: {
type: Number,
default: 50,
},
},
computed: {
truncatedText() {
const content = this.$slots.default[0].text;
return clipper(content, this.maxLength, { html: true });
},
},
};
</script>
and then use it like this:
<template>
<div>
<TruncateText :maxLength="50">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cumque, laboriosam quasi rerum obcaecati dignissimos autem laudantium error quas voluptatibus debitis?
</TruncateText>
</div>
you can have a look at the implementation I did in a similar plugin I created https://github.com/EranGrin/vue-read-more-truncate
Upvotes: 1
Reputation: 25221
You can use a filter to truncate it.
//credit to @Bill Criswell for this filter
Vue.filter('truncate', function (text, stop, clamp) {
return text.slice(0, stop) + (stop < text.length ? clamp || '...' : '')
})
Then give the filter the length you want the string to be
<my-component>
{{'Lorem ipsum dolor sit amet, consectetur adipisicing' | truncate(50) }}
</my-component>
Within the child component, content from a slot is passed through as-is, and isn't available as a variable that you could truncate from the child end.
Upvotes: 27
Reputation: 4260
A small fix to @community answer:
Within component:
export default {
data: () => {
return {}
},
created() {
},
filters: {
truncate: function (text, length, suffix) {
if (text.length > length) {
return text.substring(0, length) + suffix;
} else {
return text;
}
},
}
}
or globally:
/** Vue Filters Start */
Vue.filter('truncate', function (text, length, suffix) {
if (text.length > length) {
return text.substring(0, length) + suffix;
} else {
return text;
}
});
/** Vue Filters End */
It still can be used the same way:
<div id="app">
<span>{{ text | truncate(10, '...') }}</span>
</div>
Upvotes: 24
Reputation: 2164
you can also do it like this:
export default {
data: () => {
return {
}
},
created(){
},
filters: {
truncate: function (text, length, suffix) {
if (text.length > length) {
return text.substring(0, length) + suffix;
} else {
return text;
}
},
}
}
or
Vue.filter('truncate', function (text, length, suffix) {
if (text.length > length) {
return text.substring(0, length) + suffix;
} else {
return text;
}
});
then use it like this:
<div id="app">
<span>{{ text | truncate(10, '...') }}</span>
</div>
If you want to know more vue filters, I suggest you read this: How to Create Filters in Vue.js with Examples
Upvotes: 12
Reputation: 230
For nuxt applications this worked for me :
<div v-html="$options.filters.truncate(post.body)"></div>
And this is my Filter
filters: {
truncate: function (text, length) {
if (text.length > 30) {
return text.substring(0, 30) + '...'
} else {
return text
}
},
},
Upvotes: 7
Reputation: 71
You can just use slice js method indicating begin
and end
positions of the string. More info
<my-component>{{ lorem.slice(0, 180) }}...</my-component>
<script>
export default {
data() {
return {
lorem:
"Lorem ipsum dolor sit amet, mel at clita quando. Te sit oratio vituperatoribus, nam ad ipsum posidonium mediocritatem, explicari dissentiunt cu mea. Repudiare disputationi vim in, mollis iriure nec cu, alienum argumentum ius ad. Pri eu justo aeque torquatos."
};
}
};
</script>
Upvotes: 7
Reputation: 500
The same thing on similar way can be:
in your main.js file:
var filter = function(text, length, clamp){
clamp = clamp || '...';
var node = document.createElement('div');
node.innerHTML = text;
var content = node.textContent;
return content.length > length ? content.slice(0, length) + clamp : content;
};
Vue.filter('truncate', filter);
in your template:
{{data.content | truncate(300, '...')}}
Upvotes: 41