DOM manipulation with VueJS and Jquery

1

I'm using pure materialize along with pure vue to make my own admin template, that is, I generated the project by vue init and put in the index.html the links to the css and js of materialize. The problem is that events called by js from materialize do not work on pages without first updating them. An example is the dropdown menu, it only works if I refresh the page (F5), if I access the page through the router-link, those events do not work.

I tried to start the functions on the mounted of the component but they still do not work. How to resolve these conflicts between jquery and the gift of vues?

    
asked by anonymous 08.07.2018 / 17:10

1 answer

2

For cases where you need to run an external JavaScript, especially the ones that manipulate the DOM, it is recommended that you encapsulate the DOM into a component.

Another important point is that the properties and options passed to the component must be reactive, in which case you should study the component to study the best approach.

And finally, just as important when starting the external component or mounting the Vue component is to destroy the external component by destroying the Vue component.

Below is an example of how to make a Component for Editing and Creating a Record within a Modal.

Vue.component('edit-or-create', {
  template: '#edit-or-create',
  props: ['show', 'nome', 'email', 'titulo'],
  data () {
    return {
      inner: {
        nome: '',
        email: ''
      }     
    }
  },
  mounted () {
    this.modal = M.Modal.init(this.$refs.modal);
    this.checkShow();
  },
  beforeDestroy () {
    this.modal.destroy()
  },
  watch: {
    show () {
      this.checkShow();
    }
  },
  methods: {
    checkShow () {
      if (this.show) {
        this.inner.nome = this.nome
        this.inner.email = this.email
        this.modal.open()
      } else {
        this.modal.close()
      }
    },
    cancelar () {
      this.$emit('update:show', false);
    },
    salvar () {
      this.$emit('update:nome', this.inner.nome);
      this.$emit('update:email', this.inner.email);
      this.$emit('update:show', false);
      this.$emit('salvar')
    }
  }
});

new Vue({
  el: '#app',
  data () {
    return {
      create: { show: false, nome: '', email: '' },
      contatos: [{
        edit: false, nome: 'Tobias Mesquita', email: '[email protected]'
      }]
    }
  },
  methods: {
    created () {
      this.contatos.push({ edit: false, nome: this.create.nome, email: this.create.email })
    },
    apagar (contato) {
      var index = this.contatos.indexOf(contato)
      this.contatos.splice(index, 1)
    }
  }
})
body {
  padding: 5px;
}
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/css/materialize.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/js/materialize.js"></script>

<div id="app">
  <button class="waves-effect waves-light btn-small" @click="create.show = true">
    <i class="material-icons left">note_add</i>Novo
  </button>
  <edit-or-create 
    titulo="Novo Contato"
    :show.sync="create.show" 
    :nome.sync="create.nome" 
    :email.sync="create.email"
    @salvar="created">
  </edit-or-create>
  <table>
    <thead>
      <tr>
          <th>Name</th>
          <th>Email</th>
          <th>Editar</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(contato, indice) in contatos">
        <td>{{contato.nome}}</td>
        <td>{{contato.email}}</td>
        <td>
          <button class="btn waves-effect waves-light btn-small" @click="contato.edit = true">
            <i class="material-icons left">edit</i>Editar
          </button>
          <button class="btn waves-effect waves-light btn-small" @click="apagar(contato)">
            <i class="material-icons left">delete</i>Delete
          </button>
          <edit-or-create 
            :titulo="'Editar ' + indice"
            :show.sync="contato.edit" 
            :nome.sync="contato.nome" 
            :email.sync="contato.email">
          </edit-or-create>
        </td>
      </tr>
    </tbody>
  </table>
</div>

<script type="text/x-template" id="edit-or-create">
  <div ref="modal" class="modal">
    <div class="modal-content">
      <h4>{{titulo}}</h4>
      <div>
        <div class="row">
          <div class="input-field col s12">
            <input id="first_name" type="text" v-model="inner.nome">
            <label for="first_name">Nome</label>
          </div>
          <div class="input-field col s12">
            <input id="last_name" type="text" v-model="inner.email">
            <label for="last_name">Email</label>
          </div>
        </div>
      </div>
    </div>
    <div class="modal-footer">
      <button class="btn waves-effect waves-light btn-small" @click="cancelar">
        Cancelar
      </button>
      <button class="btn waves-effect waves-light btn-small" @click="salvar">
        Salvar
      </button>
    </div>
  </div>
</script>

However, the most recommended would be to implement a modal-only component, and use a slot for it's content.

    
19.07.2018 / 15:38