jeffreyguenther / vue-turbolinks

A Vue mixin to fix Turbolinks caching
MIT License
287 stars 20 forks source link

DOMException error #3

Closed PelagicDev closed 7 years ago

PelagicDev commented 7 years ago

I'm getting the following error in the console after implementing this plugin. I've confirmed that I'm on version 1.0.1. Any idea @jeffreyguenther? screen shot 2017-04-08 at 2 20 13 pm

jeffreyguenther commented 7 years ago

I need a little more information in order to understand what you're experiencing. Can you include basic code for the component and the HTML you're mounting it on?

I noticed Rollbar is in the stacktrace. Could it be messing this up?

PelagicDev commented 7 years ago

I removed the Rollbar gem altogether and the error persisted. Below is the component & HTML code:

// division_form.js
import Vue from 'vue/dist/vue.common'
import TurbolinksAdapter from 'vue-turbolinks'

document.addEventListener('turbolinks:load', function() {
  // let species = document.querySelector("#division-species").dataset.species
  const species = $("#division-species").data("species")
  new Vue({
    el: '#species-form',
    mixins: [TurbolinksAdapter],
    data: {
      species: species
    },
    methods: {
      addSpecies: function() {
        this.species.push({ id: '', species_id: '', points_value: '', min_weight: '' })
      },
      removeSpecies: function(i) {
        this.species.splice(i, 1)
      }
    }
  })
})
<!-- division_form.html.erb -->
<div id="species-form">
      <div v-for="(specie, index) in species" id="division-species" data-species="<%= @division_species %>">
        <div class="small-12 columns">
          <div class="callout secondary">
            <div class="row">
              <div class="small-12 medium-4 columns">
                <label for="division[division_species][][species_id]">Species: </label>
                <select name="division[division_species][][species_id]" id="division_species_id" v-model="specie.species_id">
                  <option value>- Select One -</option>
                  <% Species.all.each do |fish| %>
                    <option value="<%= fish.id %>"><%= fish.name.humanize %></option>
                  <% end %>
                </select>
              </div>
              <div class="small-12 medium-4 columns">
                <label for="division[division_species][][points_value]">Points Value: </label>
                <input name="division[division_species][][points_value]" type="number" v-model="specie.points_value">
                <div class="help-text">
                  Optional
                </div>
              </div>
              <div class="small-12 medium-4 columns">
                <label for="division[division_species][][min_weight]">Min. Weight: </label>
                <input name="division[division_species][][min_weight]" type="number" v-model="specie.min_weight">
                <div class="help-text">
                  Optional
                </div>
              </div>
              <a class="button alert pull-right" v-on:click="removeSpecies(index)">Remove</a>
            </div>
          </div>
        </div>
      </div>
      <div class="small-12 columns">
        <a class="button success" v-on:click="addSpecies">Add Species</a>
        <br><br>
      </div>
    </div>
jeffreyguenther commented 7 years ago

Thanks! It looks like there is a problem the restoration of the pre-mount div on destroy. Is it safe to assume that the view is rendered into a layout and is a direct child of <body>?

jeffreyguenther commented 7 years ago

I think the error you're seeing is because div#species-form doesn't have a parent node. We use outerHTML (See L9 of the source for reference) to restore the div to its original content before caching. Is there anything in your code that might be causing the parent node of #species-form to not exist?

I was not able to replicate the error using the code your provided. It works as intended.

PelagicDev commented 7 years ago

The div#species-form is wrapped within a fieldset tag and that is also wrapped inside of another div.

<div class="small-12 large-8 columns end">
    <fieldset class="fieldset">
        <div id="species-form">
            <!-- form fields w/ Vue logic -->
        </div>
    </fieldset>
</div>
jeffreyguenther commented 7 years ago

Odd. Back to basics then. 😕

Can you describe in detail the steps to recreate the issue? For example:

If you're able, it would be helpful if you can post a link to a minimal runnable example, so I can see the issue in action.

PelagicDev commented 7 years ago

First off, thanks for your time thus far @jeffreyguenther.

Sorry for not stating some of this before now. Also, I'll try to create a minimal example tonight after work.

excid3 commented 7 years ago

This should have already been addressed in my latest patch in 1.0.1 because of the removal the event listener upon destroy. What previously was happening was that if you navigated to other pages it would attempt to destroy the Vue app from the previous page because the turbolinks callback still referenced that.

I can't reproduce this anymore with the latest version of the gem and a couple test apps.

I'm sure you've already checked this, but I'd verify and make sure the node_modules/vue-turbolinks folder contains the 1.0.1 package source code. That seems likely the most likely thing that's breaking, but could definitely be something else. If that's not the issue, would love to see an example that can reproduce it. 👍

PelagicDev commented 7 years ago

Yeah, just checked and the node_modules folder does indeed reference version 1.0.1.

Haven't had a chance to do the demo app yet, but I'll try to get something up.

excid3 commented 7 years ago

Dang, was hoping it would be something easy like that. :P

excid3 commented 7 years ago

This was actually caused from the Vue app being loaded only for specific pages. The Vue app initialized the callbacks and tried to remove the element that didn't exist. The real solution for this is for people to only initialize their Vue app if the element exists on the page.

I've also published 1.0.2 that includes a guard for that case which should take care of the situation for anyone who forgot to do that as well. Vue will still warn the element doesn't exist in development but at least the Vue app shouldn't cause an error in production anymore.

🤘 Glad to see this working!

PelagicDev commented 7 years ago

Thanks for the help Chris.

jeffreyguenther commented 7 years ago

And just for fun, I'll plug a gem I wrote for writing page specific Javascript with a single JS file ala Rails conventions. Checkout https://github.com/LoamStudios/seed_tray for another possible approach to creating page specific JS.

Great job @excid3 on the fix!

Shoroh commented 7 years ago

I still have the same issue. It works perfect twice, and then falls with the errors above. I use version 1.02 from this repo.

vesper8 commented 6 years ago

I'm having this error using vue-turbolinks 2.0 in combination with https://github.com/matfish2/vue-tables-2

Whether I use the back button or just re-visit the same page some other way

I also use vue on every page, so far only pages that have a https://github.com/matfish2/vue-tables-2 table on them cause this issue.. would appreciate some help