0

I have a component ResultPill with a tooltip (implemented via vuikit) for the main container. The tooltip text is calculated by a getter function tooltip (I use vue-property-decorator) so the relevant bits are:

<template>
    <div class="pill"
         v-vk-tooltip="{ title: tooltip, duration: 0, cls: 'some-custom-class uk-active' }"
         ref="container"
    >
        ..some content goes here..
    </div>
</template>
<script lang="ts">
    @Component({ props: ... })
    export default class ResultPill extends Vue {
    ...
        get tooltip (): string { ..calcing tooltip here.. }
        isContainerSqueezed (): boolean {
            const container = this.$refs.container as HTMLElement | undefined;
            if(!container) return false;
            return container.scrollWidth != container.clientWidth;
        }
    ...
</script>
<style lang="stylus" scoped>
    .pill
        white-space pre
        overflow hidden
        text-overflow ellipsis
    ...
</style>

Now I'm trying to add some content to the tooltip when the component is squeezed by the container's width and hence the overflow styles are applied. Using console, I can roughly check this using $0.scrollWidth == $0.clientWidth (where $0 is the selected element), but when I start tooltip implementation with

        get tooltip (): string {
            if(this.isContainerSqueezed())
                return 'aha!'

I find that for many instances of my component this.$refs.container is undefined so isContainerSqueezed doesn't help really. Do I have to somehow set unique ref per component instance? Are there other problems with this approach? How can I check whether the element is overflown?

PS to check if the non-uniqueness of refs may affect the case, I've tried to add to the class a random id property:

        containerId = 'ref' + Math.random();

and use it like this:

         :ref="containerId"
    >
    ....
            const container = this.$refs[this.containerId] as HTMLElement | undefined;

but it didn't help: still tooltip isn't altered.

And even better, there's the $el property which I can use instead of refs, but that still doesn't help. Looks like the cause is this:

An important note about the ref registration timing: because the refs themselves are created as a result of the render function, you cannot access them on the initial render - they don’t exist yet! $refs is also non-reactive, therefore you should not attempt to use it in templates for data-binding.

(presumably the same is applicable to $el) So I have to somehow recalc tooltip on mount. This question looks like what I need, but the answer is not applicable for my case.

tony19
  • 125,647
  • 18
  • 229
  • 307
YakovL
  • 7,557
  • 12
  • 62
  • 102
  • maybe its some of the typescript crust? Try directly debugging `this.$refs.container`, it should always be defined unless you somehow manage to call that function before mounting. – Flame Dec 18 '19 at 16:05
  • @Flame that is highly unlikely since TS is stripped in production so `isContainerSqueezed` doesn't really contain anything but `const container = this.$refs.container` and the comparisons. What might affect the case is the whole decorator stuff (it may be used without TS), some "smart caching" of the getter results inside vue (DOM refs are not observable, are they?) or the need of unique refs (I've tried to switch it to a random one, though, and it didn't work; I'll update the question accordingly) – YakovL Dec 19 '19 at 10:57
  • still sounds like an issue of call sequence. Try wrapping your function call in a `this.$nextTick(() => {});`. I cant see in your code sample where and when you actually cal the `isContainerSqueezed()` function. – Flame Dec 19 '19 at 14:23
  • @Flame yes indeed (usage of `isContainerSqueezed` is shown in the previous edit; I made it a bit more verbose and evident). I've ended up with using `mounted` instead of `$nexTIck`, I'll post the solution I use for now – YakovL Dec 19 '19 at 15:23

1 Answers1

1

So, like I've mentioned in one of the edits, docs warn that $refs shouldn't be used for initial rendering since they are not defined at that time. So, I've made tooltip a property instead of a getter and calcuate it in mounted:

export default class ResultPill extends Vue {
...
    tooltip = '';
    calcTooltip () {
        // specific logic here is not important, the important bit is this.isContainerSqueezed()
        // works correctly at this point
        this.tooltip = !this.isContainerSqueezed() ? this.mainTooltip :
            this.label + (this.mainTooltip ? '\n\n' + this.mainTooltip : '');
    }
    get mainTooltip (): string { ..previously used calculation.. }
    ...
    mounted () {
        this.calcTooltip()
    }
}
YakovL
  • 7,557
  • 12
  • 62
  • 102