1

I use Vue.js modal inside my Vue app. It's part of a Vue component. The template part consists of the modal only:

<template>
    <!-- Modal: Edit exercise -->
    <modal name='edit-exercise-modal'
           :draggable='true'
           height='auto'>

        <form @submit.prevent='storeEdits'>
            <div ref='myDiv'>Some text</div>
            <!-- Also tried:
            <div id='my-div'>Some text</div>
            -->
        </form>

    </modal>
</template>

I need to access DOM elements to user the Rangy library and highlight some text inside my-div. But whenever I try to get it in a method, I get undefined or null instead, depending on whether I use pure JS or Vue refs:

console.log(this.$refs.myDiv); // undefined
console.log(document.getElementById('my-div'); // null

When I do console.log(this.$refs), I get myDiv inside the refs property. But when I stop code execution with debugger directly after console.log, refs seems to be empty.

What's the problem here? What can I do to get a reference to the div I need to modify?

edit: Here's a more complete snippet

<template>
    <!-- Modal: Edit exercise -->
    <modal name='edit-exercise-modal'
           :draggable='true'
           height='auto'>

        <form @submit.prevent='storeEdits'>
            <div ref='myDiv'>Some text</div>
            <!-- Also tried:
            <div id='my-div'>Some text</div>
            -->
        </form>

    </modal>
</template>

<script>

    import Vue from 'vue';

    import VModal from 'vue-js-modal';
    Vue.use(VModal);

    import rangy from 'rangy';
    import 'rangy/lib/rangy-classapplier';

    export default {

        props: [ 'exercise' ],

        /**********************************************
        ********************* Data ********************
        **********************************************/

        data: function() {
            return {
                selected:    [],
                category_id: undefined,
                text:        undefined,
                mistakes:    undefined
            };
        },


        /**********************************************
        ******************** Methods ******************
        **********************************************/

        methods: {
            sampleMethod: function() {
                console.log(this.$refs.textWithMistakes);
                console.log(document.getElementById('text-with-mistakes'));
            }
        },


        /**********************************************
        ******************* Watchers ******************
        **********************************************/

        watch: {
            /**
             * Sets up and shows modal when exercise data is loaded from parent.
             */
            exercise: function() {
                this.category_id = this.exercise.category_id;
                this.text = this.exercise.text;
                this.mistakes = this.exercise.mistakes;

                this.$modal.show('edit-mistakes-exercise-modal');

                // Not working
                this.applyClass(sampleMethod);
                
                // Working, but not a way I'd like to go
                setTimeout(() => {
                    this.applyClass(sampleMethod);;
                }, 3000);
            }
        }
    }
</script>

6
  • 1
    There is no closing quote for your ref <div ref='myDiv> Commented Aug 13, 2019 at 15:36
  • Thanks, that was just a typo in Stackoverflow. Commented Aug 13, 2019 at 16:24
  • 1
    The problem is that you don't have your div in DOM at moment when console.log $refs. It would be very helpful to us if you can provide snippet of code where you log refs along with the modal component. Commented Aug 13, 2019 at 17:05
  • Thanks, I added a snippet. As you can see, everything is working when I delay the function call using setTimeout, but that feels like a hacky solution. Commented Aug 13, 2019 at 17:51
  • Did you try this.$nextTick()? Commented Aug 13, 2019 at 20:45

1 Answer 1

2

The content inside the modal is not accessible for you as long as the modal is closed. But the vue-js-modal component emits an 'opened' event when the modal is toggled visible. You can call your code the when modal is open and finished rendering.

<modal 
  name='edit-exercise-modal'
  @opened="onModalOpened"
  :draggable='true'
  height='auto'
>
   ...
</modal>
Sign up to request clarification or add additional context in comments.

4 Comments

1: This does not apply, at least there's no v-if inside the template. 2: I don't understand this approach. When should I emit an event, how should I handle it? 3: I do pass the data as a prop, it's just that just before the modal opens, this data is undefined. There's a watcher on this prop which shows the modal when the prop changes. So I understand why setTimeout solves my problem, I just need a solution without having to guess the interval I need to wait.
Sorry, didn't notice that the modal is not your own code. Look at this: github.com/euvl/vue-js-modal/blob/master/src/Modal.vue#L25 That's v-if I was talking about. It means, that the HTML inside the modal is not there until the modal is visible.
Option 2 could be a solution: github.com/euvl/vue-js-modal/blob/master/src/Modal.vue#L524 An event gets emitted when the modal is opened. <modal @opened="onModalOpened">
@opened solved my problem. I was actually aware of this event, but I was confused because in my case the modal is inside a nested component and I thought this event couldn't help me. Thanks!

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.