PierreB
PierreB

Reputation: 1977

vue.js components : How to truncate the text in the slot element in a component?

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

Answers (7)

EranGrin
EranGrin

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

Jeff
Jeff

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

Maroun Melhem
Maroun Melhem

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

Kapitan Teemo
Kapitan Teemo

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

wisdom
wisdom

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

Isabel S. Rivero
Isabel S. Rivero

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

Filip Ajdačić
Filip Ajdačić

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

Related Questions