0

I am making a blog using React and MongoDB. I retrieve the data from MongoDB, here is my component:

import React, { Component } from 'react';
import axios from 'axios';

export default class Post extends Component {

  constructor(props) {
      super(props);
      this.state = {
       posts: []
      };
  }

  truncateText = text => {
    return text.substring(0, 500) + "...";
   }

    allPosts = () => {
      return this.state.posts.map(function(astroPost, i){
        return <div class="post-container">
            <img className="post-info-container__image" src={astroPost.picture} alt=""/>
            <div className="post" posts={astroPost} key={i}>
             <div class="post-container__text">
             <h2>{astroPost.title}</h2>
             <p className="date">{astroPost.date}</p>
             <p className="post-info-container__text">{this.truncateText(astroPost.postContent)}</p>
             <button>Read more</button>
            </div>
           </div>
           </div>
             })
           }

     componentDidMount() {
      axios.get('http://localhost:4000/')
           .then(response => {
               this.setState({posts: response.data})
               console.log(response)
           })
           .catch(function(error) {
               console.log(error)
           })
       }

  render() {
      return (
        <div>
          { this.allPosts() } 
       </div>
      )
  }
}

I want to truncate the text of my post so that a post shows only 500 symbols. I achieved this by doing so:

return this.state.posts.map(function(astroPost, i){
        return <div class="post-container">
            <img className="post-info-container__image" src={astroPost.picture} alt=""/>
            <div className="post" posts={astroPost} key={i}>
             <div class="post-container__text">
             <h2>{astroPost.title}</h2>
             <p className="date">{astroPost.date}</p>
             <p className="post-info-container__text">{astroPost.postContent.substring(0, 500) + "..."}</p>
             <button>Read more</button>
            </div>
           </div>
           </div>

But I want to do it with a function that get's called on the text, so I kept the same logic in a function called truncateText, but when I call it like this:

   return this.state.posts.map(function(astroPost, i){
        return <div class="post-container">
            <img className="post-info-container__image" src={astroPost.picture} alt=""/>
            <div className="post" posts={astroPost} key={i}>
             <div class="post-container__text">
             <h2>{astroPost.title}</h2>
             <p className="date">{astroPost.date}</p>
             <p className="post-info-container__text">{astroPost.postContent.truncateText()}</p>
             <button>Read more</button>
            </div>
           </div>
           </div>
             })
           }

It says that TypeError: astroPost.postContent.truncateText is not a function

How can I call that function and perform the truncation properly?

3
  • Can you try: this.truncateText(astroPost.postContent) Commented Oct 24, 2019 at 17:45
  • it says that truncateText is undefined, it doesn't work with this too Commented Oct 24, 2019 at 17:47
  • Oh duh, you either need to bind the function in your constructor or make it an arrow function. You can add this.truncateText = this.truncateText.bind(this); in your constructor. Or you can call the function like: {() => this.truncateText(astroPost.postContent}} Commented Oct 24, 2019 at 17:50

2 Answers 2

1

You have not bound truncatetext to the component: that causes problems with the context. In the constructor, you can use this.truncatetext = this.truncatetext.bind(this):

  constructor(props) {
      super(props);
      this.state = {
       posts: []
      };
      this.truncateText = this.truncateText.bind(this);
  }
Sign up to request clarification or add additional context in comments.

Comments

0

astroPost is just the element inside the array you are iterating.

Also, if you create a function in your class, you have to do one of this things: or bind the function to the "this" element, or create the function as an arrow function. I recommend second option. So, for your case, you would end with something like this:

truncateText = text => {
 return text.substring(0, 500) + "...";
}

and then, inside your map you can call it like this:

<p className="post-info-container__text">{this.truncateText(astroPost.postContent)}</p>

4 Comments

I changed my function to you suggestion and called it the same way and I now get Cannot read property 'truncateText' of undefined
because allPosts should be an arrow function too. change it to allPosts = () => {...}
@MahmaDeva that error is saying that your 'this' instance inside allPosts doesnt know "truncateText". if you make allPosts an arrow function, it has to work. Can you send me the new code? There is something you are making wrong there.
@MaximilianoPoggioYes I edited my question with the updated code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.