Skip to content

transition before-leave js-hook does not manipulate the DOM which will be transitioned #9573

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
plehnen opened this issue Feb 25, 2019 · 3 comments

Comments

@plehnen
Copy link

plehnen commented Feb 25, 2019

Version

2.6.7

Reproduction link

https://jsfiddle.net/8zcdpkv0/

Steps to reproduce

Please see jsfiddle.

Any changes in the before-leave hook won't affect the DOM which is transitioned.

My actual problem is that I try to transition an element which has aria-live="polite" or rule="alert", which will be read out by a screenreader.
Apparently the change of classes from the transition are noticed by the screenreader and the message will be read out again.
I tried to fix this for accessibility purposes with the before-leave hook, but that doesn't seem to work correctly.

What is expected?

It would either be great if the transitioned DOM will remove all attributes which will cause the screenreader to read it out again, or to allow the javascript hook "before-leave" to actually change the DOM before the transition happens.

What is actually happening?

The old DOM will be transitioned (and the screenreader will read the content again).

@DaKoala
Copy link
Contributor

DaKoala commented Apr 20, 2019

I modified your code a little and the HTML now is:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vue Dev</title>
  <link href="style.css" rel="stylesheet">
  <script src="vue.js"></script>
  <script src="script.js" defer></script>
</head>
<body>
<div id="app">
  <button @click="handleClick">
    toggle
  </button>

  <transition mode="out-in" name="fade" appear @before-leave="onBeforeLeave" @after-enter="role = 'alert'">
    <p v-if="isActive" :role="role" id="test">{{ message }}</p>
  </transition>
</div>
</body>
</html>

The JS is:

new Vue({
  el: '#app',
  data(){
    return {
      message: 'Hello Vue.js!',
      role: null,
      isActive: true,
    }
  },
  methods: {
    handleClick() {
      document.getElementById('test').textContent = 'new message';
      this.isActive = !this.isActive;
    },
    onBeforeLeave() {
      this.message = 'new message'; // this does not affect the DOM which will fade out
      this.role = 'document'; // this does not affect the DOM which will fade out ---> screenreaders will detect the class-changes and read out the content again :\
    }
  }
})

I added an id to the element to be modifed and in the click listener I used native JavaScript to change the textContent of the element. The code above works as you expect.

Actually I am not giving a solution to this situation but trying to figure out what is missed here. I also checked the devtool. I found that message property was changed immediately when I clicked the button, however it was not rerendered before the beginning of the animation.

I will continue paying attention to this problem. I am not sure if I can work it out later, but I will try.

@DaKoala
Copy link
Contributor

DaKoala commented Apr 20, 2019

UPDATE: If I use vm.$nextTick to set the isActive attribute it also works.

new Vue({
  el: '#app',
  data(){
    return {
      message: 'Hello Vue.js!',
      role: null,
      isActive: true,
    }
  },
  methods: {
    handleClick() {
      this.message = 'new message';
      this.$nextTick(() => {
        this.isActive = !this.isActive;
      });
    },
    onBeforeLeave() {
      this.message = 'new message'; // this does not affect the DOM which will fade out
      this.role = 'document'; // this does not affect the DOM which will fade out ---> screenreaders will detect the class-changes and read out the content again :\
    }
  }
})

@posva
Copy link
Member

posva commented Apr 21, 2019

This is indeed one of the limitations of current transition, I'm not sure if it's something that can be changed.
The current way to deal with this is changing the data used in the template in one function and then, after one tick, change the variable that triggers the animation like @DaKoala showed with nextTick

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

3 participants