skip to Main Content

The way i am getting data is little bit complicated. I have "tweets" array where data is stored and each tweet is a card where i successfully change style when card is clicked(markTweet function), but there are also replies for each tweet which are shown same as tweets(each reply has its own card). The way i am getting data from server:

let replies = []
for(const tweet of tweets) {
    let reply = await SQL('SELECT * FROM tweet_replies WHERE tweet_replies.conversation_id = ?', tweet.tweet_id)
    replies.push(reply)
}
    
const data = {
    tweets: tweets,
    page: parseInt(currentPage),
    numberOfPages: arr,
    replies
}

Then i have component in vue. You can see replies are stored in tweets array in each tweet as tweetReplies.
In markReply func, am succesfully adding id to array.

<template>
  <div class="container-full">
    <div class="tweets-container">
      <div
        v-for="(tweet, i) in tweets"
        :key="tweet.id"
      >
        <div
          class="tweet-card"
          :class="{ selected: tweet.isSelected }"
          @click="markTweet(tweet.tweet_id, i)"
        >
          <div class="text">
            <p
              v-html="tweet.tweet_text"
            >
              {{ tweet.tweet_text }}
            </p>
          </div>
        </div>
        <div class="replies">
          <div
            v-for="(reply, index) in tweet.tweetReplies"
            :key="reply.tweet_id"
            @click="markReply(reply.tweet_id, index)"
          >
            <div class="tweet-card tweet-reply">
              <div class="text">
                <p>
                  {{ reply.tweet_text }}
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
import { getUserToken } from '@/auth/auth'
import moment from 'moment'
import { BFormTextarea, BButton, BFormSelect } from 'bootstrap-vue'

export default {
  components: { BFormTextarea, BButton, BFormSelect },
  data() {
    return {
      tweets: [],
      tweetActionIds: [],
      categories: [],
    }
  },
  beforeMount() {
    this.getTweets()
  },
  methods: {
    getTweets() {
      this.tweets = []
      const API_URL = `${this.$server}/api/twitter/tweets`

      const params = {
        token: getUserToken(),
        page: this.$route.query.page,
        newCurrentPage: newCurrent,
      }
      axios.post(API_URL, null, { params }).then(res => {
        this.currentPage = res.data.page
        this.numberOfPages = res.data.numberOfPages

        if (res.data) {
          res.data.tweets.forEach(tweet => {
            const tweetData = {
              id: tweet.id,
              tweet_id: tweet.tweet_id,
              tweet_text: htmlText,
              tweet_text_en: htmlTextEn,
              twitter_name: tweet.twitter_name,
              twitter_username: tweet.twitter_username,
              added_at: moment(String(tweet.added_at)).format(
                'MM/DD/YYYY hh:mm',
              ),
              URL: tweet.URL,
              isSelected: false,
              tweetReplies: [],
            }
            this.tweets.push(tweetData)
          })
          res.data.replies.forEach(reply => {
            reply.forEach(r => {
              this.tweets.forEach(tweet => {
                if (tweet.tweet_id === r.conversation_id) {
                  tweet.tweetReplies.push(r)
                }
              })
            })
          })
        }
      })
    },
    markTweet(tweetId, i) {
      const idIndex = this.tweetActionIds.indexOf(tweetId)
      this.tweets[i].isSelected = !this.tweets[i].isSelected
      if (this.tweetActionIds.includes(tweetId)) {
        this.tweetActionIds.splice(idIndex, 1)
      } else {
        this.tweetActionIds.push(tweetId)
      }
    },
    markReply(replyId) {
      const idIndex = this.tweetActionIds.indexOf(replyId)
      if (this.tweetActionIds.includes(replyId)) {
        this.tweetActionIds.splice(idIndex, 1)
      } else {
        this.tweetActionIds.push(replyId)
      }
    },
  },
}
</script>

I have tried to add replySelected in data and then when click is triggered in markReply i changed replySelected to true, but every reply of a tweet was then selected, which is not what i want.

2

Answers


  1. If I understood you correctly try like following snippet:

    const app = Vue.createApp({
      data() {
        return {
          tweets: [{id: 1, tweet_id: 1, isSelected: true, tweet_text: 'aaa', tweetReplies: [{tweet_id: 11, tweet_text: 'bbb'}, {tweet_id: 12, tweet_text: 'ccc'}]}, {id: 2, tweet_id: 2, isSelected: false, tweet_text: 'ddd', tweetReplies: [{tweet_id: 21, tweet_text: 'eee'}, {tweet_id: 22, tweet_text: 'fff'}]}],
          tweetActionIds: [],
        }
      },
      methods: {
        markTweet(tweetId, i) {
          const idIndex = this.tweetActionIds.indexOf(tweetId)
          this.tweets[i].isSelected = !this.tweets[i].isSelected
          if (this.tweetActionIds.includes(tweetId)) {
            this.tweetActionIds.splice(idIndex, 1)
          } else {
            this.tweetActionIds.push(tweetId)
          }
        },
        markReply(replyId) {
          const idIndex = this.tweetActionIds.indexOf(replyId)
          if (this.tweetActionIds.includes(replyId)) {
            this.tweetActionIds.splice(idIndex, 1)
          } else {
            this.tweetActionIds.push(replyId)
          }
        },
        checkReply(r) {
          return this.tweetActionIds.includes(r) ? true : false
        }
      },
    })
    
    app.mount('#demo')
    .selected {color: red;}
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
    <div id="demo">
      <div class="container-full">
        <div class="tweets-container">
          <div v-for="(tweet, i) in tweets" :key="tweet.id">
            <div
              class="tweet-card"
              :class="{ selected: tweet.isSelected }"
              @click="markTweet(tweet.tweet_id, i)"
            >
              <div class="text">
                <p v-html="tweet.tweet_text">
                  {{ tweet.tweet_text }}
                </p>
              </div>
            </div>
            <div class="replies">
              <div
                v-for="(reply, index) in tweet.tweetReplies"
                :key="reply.tweet_id"
                @click="markReply(reply.tweet_id, index)"
              >
                <div class="tweet-card tweet-reply">
                  <div class="text" :class="{selected: checkReply(reply.tweet_id)}">
                    <p>{{ reply.tweet_text }}</p>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      {{tweetActionIds}}
    </div>
    Login or Signup to reply.
  2. You can build on Nikola’s answer by bypassing the extra step of adding isSelected to each individual Tweet by just checking if it’s in the tweetActionIds array, and then do the same with the replies to keep it clean

    <div id="demo">
      <div class="container-full">
        <div class="tweets-container">
          <div
            v-for="(tweet, i) in tweets"
            :key="tweet.id"
          >
            <div
              class="tweet-card"
              :class="{ selected: isActive(tweet) }"
              @click="markTweet(tweet.tweet_id, i)"
            >
              <div class="text">
                <p v-html="tweet.tweet_text">
                  {{ tweet.tweet_text }}
                </p>
              </div>
            </div>
            <div class="replies">
              <div
                v-for="(reply, index) in tweet.tweetReplies"
                :key="reply.tweet_id"
                @click="markReply(reply.tweet_id, index)"
              >
                <div 
                 :class="{ selected: isActive(reply) }"
                 class="tweet-card tweet-reply"
                >
                  <div class="text">
                    <p>{{ reply.tweet_text }}</p>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      {{tweetActionIds}}
    </div>
    
    const app = Vue.createApp({
      data() {
        return {
          tweets: []
          tweetActionIds: [],
          categories: [],
        }
      },
      methods: {
        markTweet(tweetId, i) {
          const idIndex = this.tweetActionIds.indexOf(tweetId)
          if (this.tweetActionIds.includes(tweetId)) {
            this.tweetActionIds.splice(idIndex, 1)
          } else {
            this.tweetActionIds.push(tweetId)
          }
        },
        markReply(replyId) {
          const idIndex = this.tweetActionIds.indexOf(replyId)
          if (this.tweetActionIds.includes(replyId)) {
            this.tweetActionIds.splice(idIndex, 1)
          } else {
            this.tweetActionIds.push(replyId)
          }
        },
        isSelected(tweet) {
          return this.tweetActionIds.includes(tweet.tweet_id);
        }
      },
    })
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search