Home » vue » Why getComputedStyle() method does not work properly in my Nuxt app?

Why getComputedStyle() method does not work properly in my Nuxt app?

Posted by: admin November 26, 2021 Leave a comment

Questions:

I am working in a Nuxt app and also use SSR mode and Vuex in my project. In one of my pages I have two column and the data of them (their text) comes from Vuex. here is the code of my page:

<template>
    <div>
        <v-container>
            <v-row no-gutters>
                <v-col cols = "12" md="7">
                    <v-sheet>
                        <v-card class="topCard mt-12">
                            <h1 class="headTitle pb-6 px-12">
                                {{ this.title1 }}
                            </h1>
                            <h2 class="headTitle pb-6 px-12">
                                {{ this.subtitle1 }}
                            </h2>

                            <p class="px-12 py-6 paraCard">
                                <span>برچسب(ها): </span>
                                <span class="tagSpan mx-2 px-4" v-for="item in finalTags" :key="item">
                                    {{ item }}
                                </span>
                            </p>

                            <p class="paraCard pt-2">
                                نویسنده:
                                <v-chip
                                outlined
                                large
                                class="pa-5 mr-4"
                                color="var(--color3)"
                                >
                                    {{ this.author1 }}
                                </v-chip> 
                            </p>
                            
                        </v-card>
                    </v-sheet>
                </v-col>

                <v-col cols = "12" md="5">
                    <v-sheet>
                        <v-card class="topCard mt-12">
                            <v-img
                            transition="scale-transition"
                            v-show="show"
                            max-width="250"
                            :src="require(`~/assets/imgs/books/${this.idPage}.webp`)"
                            >
                            </v-img>
                        </v-card>
                    </v-sheet>
                    
                </v-col>
            </v-row>

            <v-row no-gutters class="my-16">
                <v-col cols = "12" md="7">
                    <div class="tozihClass">
                        <div>
                            <h1 class="text-center pa-5">معرفی کتاب {{ this.title1 }}</h1>
                            <p class="pa-4">
                                {{ this.kamelTozih1 }}
                            </p>
                        </div>
                    </div>
                </v-col>

                <v-col cols = "12" md="5">
                    <div class="tozihClass">
                        <div>
                            <h1 class="text-center pa-5">
                                عناوین مهم کتاب
                            </h1>
                            <ul class="px-12">
                                <li :key="item" v-for="item in titleSet">
                                    {{ item }}
                                </li>
                            </ul>
                        </div>
                    </div>
                </v-col>
            </v-row>
        </v-container>
    </div>
</template>

<script>

export default {
    data() {
        return {
            allBooks: [],
            allTags: [],
            finalTags: [],
            idPage: 3,
            title1: "",
            author1: "",
            subtitle1: "",
            kamelTozih1: "",
            titleSet: [],
            show: false
        }   
    },
    methods: {
        findData: function(inputArr) {
            this.title1 = inputArr.find(x => x.id == this.idPage).title;
            this.author1 = inputArr.find(x => x.id == this.idPage).author;
            this.kamelTozih1 = inputArr.find(x => x.id == this.idPage).kamelTozih;
            this.subtitle1 = inputArr.find(x => x.id == this.idPage).tozih;
            this.titleSet = inputArr.find(x => x.id == this.idPage).titleList;
            /* finding tag names */
            // ------------------
            let tagIds = inputArr.find(x => x.id == this.idPage).tags;
            this.findTags(tagIds);
        },

        findTags(inputTags) {
            let arrInit = [];
            inputTags.forEach(element => {
                arrInit.push( this.allTags.find(x => x.id == element).name );
            });
            this.finalTags = arrInit;
        },

        setHeight() {
            let elem = document.querySelectorAll('.tozihClass');
            let finalHeight = window.getComputedStyle(elem[1]).getPropertyValue("height");
            console.log(finalHeight);
            document.documentElement.style.setProperty("--equHeigth", finalHeight);
            document.body.style.setProperty("--equHeigth", finalHeight);
        }
    },
    mounted() {
        this.allBooks = this.$store.state.books.list;
        this.allTags = this.$store.state.books.tags;
        this.findData(this.allBooks);

        if (document.readyState === "complete") { 
            this.setHeight(); 
        }
        
    },
    created() {
        this.show = true;
    }
}
</script>

<style scoped>
.headTitle {
    color: var(--color4);
    font-size: 3rem;
    text-shadow: 2px 3px 5px var(--color1);
}

h2.headTitle {
    font-size: 1.8rem;
}

.topCard {
    min-height: 375px;
    background-color: var(--color5a);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-around;
}

.paraCard {
    color: var(--color3);
    font-size: 1.5rem;
    border-top: 1px solid var(--color3a);
}

.tagSpan {
    border: 2px solid var(--color2);
    cursor: pointer;
}

.tagSpan:hover {
    background-color: var(--color3a);
}

.tozihClass {
    background-color: var(--color6a);
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: var(--equHeigth);
}

.tozihClass h1 {
    color: var(--color2);
    font-size: 2.3rem;
}

.tozihClass p {
    color: var(--color4);
    font-size: 1.6rem;
    line-height: 1.7;
    text-align: justify;
}

.tozihClass ul {
    font-size: 1.5rem;
}
</style>

And here is the books.js file in my store folder:

import bookData from "~/assets/json-data/bookList.json";
import tagData from "~/assets/json-data/tagList.json";
export const state = () => ({
    tags: tagData,
    list: bookData
})

It simply gets data from json files and loaded them to document. I want to calculate the height of taller column (the column that contains ul element) with getComputedStyle() method in the setHeight() page method and then set a custom css property (–equHeigth) value to that. and this value must automatically sets to other column (because they have same class). But it does not calculate the height and return the default value of –equHeigth that I set (for example 625px).

But I noticed that If I set data without Vuex it works properly:

<template>
    <div>
        <v-container>

            <v-row no-gutters class="my-16">
                <v-col cols = "12" md="7">
                    <div class="tozihClass">
                        <div>
                            <h1 class="text-center pa-5">معرفی کتاب شیب</h1>
                            <p class="pa-4">
                                خلاصه کتاب شیب از ست گودین (ترجمه کتاب The Dip) راجع‌به پدیده‌ی شیب صحبت می‌کنه توی مسیر موفقیت برای هرکسی وجود داره. چه توی زندگی شخصی و چه توی زندگی کاری، معمولا اوایل خیلی ذوق و شوق داریم و همه‌چیز بر وفق مراده، اما به‌مرور زمان عبارت مشهور «که عشق آسان نمود اول ولی افتاد مشکل‌ها» خودش رو در عمل نشون میده و سروکله‌ی مشکلات و موانع پیدا می‌شه. ست گودین توی خلاصه کتاب شیب میگه که مواجه‌شدن با چنین چیزی اجتناب‌ناپذیره، اما مهم اینه که توی بازه‌ی شیب، به‌درستی موانع رو تشخیص بدی و ببینی که آیا این موانع عادیِ مسیر هستن یا چیزهای غیرقابل‌رفعی هستن که مستقیما به ماهیت کار یا زندگیت مربوط می‌شن.
                            </p>
                        </div>
                    </div>
                </v-col>

                <v-col cols = "12" md="5">
                    <div class="tozihClass">
                        <div>
                            <h1 class="text-center pa-5">
                                عناوین مهم کتاب
                            </h1>
                            <ul class="px-12">
                                <li :key="item" v-for="item in titleSet">
                                    {{ item }}
                                </li>
                            </ul>
                            
                        </div>
                    </div>
                </v-col>
            </v-row>
        </v-container>
    </div>
</template>

<script>

export default {
    data() {
        return {
            /* arrays that must fill the li */
            titleSet: ["موضوع کتاب راجع‌به چیه؟ چرا رهاکردنِ به‌موقعِ پروژه‌ها یه اقدام هنرمندانه هست؟", "هر هدفی که داشته باشی، وقوع پدیده‌ی شیب یا دوره‌ی چالش‌برانگیز اجتناب‌ناپذیره", "بهترین‌بودن  توأم با مزیت‌های آشکار و پنهان مهمی هست ", "تخصص‌داشتن و آگاهی از نحوه‌ی خروج استراتژیک برای موفقیت ضروریه ", "چه توی زندگی کاری و چه زندگی شخصی، قطعا با پدیده‌ی شیب روبه‌رو میشی ", "موفقیت از دل پدیده‌ی شیب بیرون می‌زنه ", "شیب می‌تونه مزیت رقابتی ایجاد کنه ", "برای دَووم‌آوردن در دوران شیب باید صبور و سرسخت باشی و کم نیاری "]
            
        }   
    },
    methods: {

        setHeight() {
            /* method that must calcilate the height of lists and set them to other part */
            let elem = document.querySelectorAll('.tozihClass');
            let finalHeight = window.getComputedStyle(elem[1]).getPropertyValue("height");

            console.log(finalHeight);

            document.documentElement.style.setProperty("--equHeigth", finalHeight);
            document.body.style.setProperty("--equHeigth", finalHeight);
        }
    },
    mounted() {
        if (document.readyState === "complete") { 
            this.setHeight(); 
        }
    },
}
</script>

<style scoped>


.tozihClass {
    background-color: var(--color6a);
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: var(--equHeigth);
}

.tozihClass h1 {
    color: var(--color2);
    font-size: 2.3rem;
}

.tozihClass p {
    color: var(--color4);
    font-size: 1.6rem;
    line-height: 1.7;
    text-align: justify;
}

.tozihClass ul {
    font-size: 1.5rem;
}
</style>

In the above code I set an array to the titleSet data and did not use Vuex and it works. but why this problem occurs (why when using Vuex it could not calculate the height?). Also when I refresh the page "setHeight()" method does not run, and only when routing between pages it runs, I don’t know why this happen?

This is the structure of one data in bookList.json file:

{
        "id": 3,
        "title": "شیب",
        "tozih": "کی باید رها کنی و کی باید بچسبی",
        "author": "ست گودین",
        "tags": [10, 13],
        "kamelTozih": "خلاصه کتاب شیب از ست گودین (ترجمه کتاب The Dip) راجع‌به پدیده‌ی شیب صحبت می‌کنه توی مسیر موفقیت برای هرکسی وجود داره. چه توی زندگی شخصی و چه توی زندگی کاری، معمولا اوایل خیلی ذوق و شوق داریم و همه‌چیز بر وفق مراده، اما به‌مرور زمان عبارت مشهور «که عشق آسان نمود اول ولی افتاد مشکل‌ها» خودش رو در عمل نشون میده و سروکله‌ی مشکلات و موانع پیدا می‌شه. ست گودین توی خلاصه کتاب شیب میگه که مواجه‌شدن با چنین چیزی اجتناب‌ناپذیره، اما مهم اینه که توی بازه‌ی شیب، به‌درستی موانع رو تشخیص بدی و ببینی که آیا این موانع عادیِ مسیر هستن یا چیزهای غیرقابل‌رفعی هستن که مستقیما به ماهیت کار یا زندگیت مربوط می‌شن.",
        "titleList": ["موضوع کتاب راجع‌به چیه؟ چرا رهاکردنِ به‌موقعِ پروژه‌ها یه اقدام هنرمندانه هست؟", "هر هدفی که داشته باشی، وقوع پدیده‌ی شیب یا دوره‌ی چالش‌برانگیز اجتناب‌ناپذیره", "بهترین‌بودن  توأم با مزیت‌های آشکار و پنهان مهمی هست ", "تخصص‌داشتن و آگاهی از نحوه‌ی خروج استراتژیک برای موفقیت ضروریه ", "چه توی زندگی کاری و چه زندگی شخصی، قطعا با پدیده‌ی شیب روبه‌رو میشی ", "موفقیت از دل پدیده‌ی شیب بیرون می‌زنه ", "شیب می‌تونه مزیت رقابتی ایجاد کنه ", "برای دَووم‌آوردن در دوران شیب باید صبور و سرسخت باشی و کم نیاری "]
    },

Answers:

The reason it doesn’t work after a page refresh is because neither the window nor the document objects exist on the server side. You need to check if you’re on the client side first to use window and document.

I see two options here:

  1. Check that you’re on the client side and wrap your logic in the mounted hook in nextTick() to ensure everything had a chance to load. Remove the if statement about the document readyState. This may give you other issues though.
  2. Better option: forget computing the height and make it work using CSS. Style the row wrapping the cols containing your tozihClass divs to be display: flex; align-items: stretch. This should make them equal heights. You may need to make the cols height: 100%.