3

I have been struggling to use Vue and MathLive to handle typesetting randomly generated numbers and their squares. The function of the program is to generate a random integer from 1 to 35, calculate the square, and typeset it with MathLive. There are two buttons that add one to the integer or create another random one. I have no problem typesetting the initial value but when I create a different integer or add 1 the page, it never re-typesets. I am trying to implement this program as a component in Vue. Here is my MWE (component only):

<template lang="html">
  <div class="problem">
    <p id="math">$${{num}}^2 = {{square()}}$$</p>
    <button @click="addOne">Add One</button>
    <button @click="randomInt">Random Number</button>
  </div>
</template>

<script>
import math from 'mathjs'
import MathLive from 'mathlive'

export default {
  name: 'Problem',
  data: function () {
    return {
      num: math.randomInt(1,35)
    }
  },
  watch: {
    num: function () {
      console.log("Data changed");
      // this.renderMath();
    }
  },
  created: function () {
    console.log("Hello This is created!");
    this.renderMath();
  },
  beforeMount: function () {
    console.log("This is beforeMount");
  },
  mounted: function () {
    console.log("This is mounted!");
  },
  beforeUpdate: function () {
    console.log("This is beforeUpdate");
    this.renderMath();
  },
  methods: {
    addOne: function() {
      this.num++
    },
    randomInt: function () {
      this.num = math.randomInt(1,35)
    },
    square: function () {
      return this.num**2
    },
    renderMath: function (event) {
      this.$nextTick(function(){
        MathLive.renderMathInElement("math");
      })
    }
  }
}
</script>

<style lang="css" scoped>
@import url("../../node_modules/mathlive/dist/mathlive.core.css");
@import url("../../node_modules/mathlive/dist/mathlive.css");
p {
  color: white;
}
</style>

Edit: To clarify when I load the page up, the initial value is typeset correctly using MathLive as shown below: enter image description here Then after I click either the Add One or Random Number button, the program should generate a new value, calculate its square, and update that value on the screen as shown below: enter image description here

tony19
  • 125,647
  • 18
  • 229
  • 307
1028
  • 129
  • 7

2 Answers2

3

It seems MathLive's DOM manipulation conflicts with Vue's virtual DOM, preventing Vue from patching the DOM with the updated text node.

A workaround is to apply a key to force the MathLive p element to be re-created when the key changes. We could use num as the key, since it changes with each button press:

<p :key="num">...</p>

The current watcher on num would need to be updated to call renderMath() to refresh the MathLive element:

watch: {
  num() {
    this.renderMath();
  }
},

You should also consider making square() a computed property for more efficient rendering:

// script
computed: {
  square() {
    return this.num ** 2
  }
}
// template
<p :key="num">$${{num}}^2 = {{square}}$$</p>

Edit MathLive in Vue component

tony19
  • 125,647
  • 18
  • 229
  • 307
2

You need to use vue.js computed properties

new Vue({
  name: 'Problem',
  data: function () {
    return {
      num: math.randomInt(1,35)
    }
  },
  watch: {
    num: function () {
      console.log("Data changed");
      this.renderMath();
    }
  },
  computed: {
     square: function () {
        return this.num**2;
     }
  },
  created: function () {
    console.log("Hello This is created!");
    this.renderMath();
  },
  beforeMount: function () {
    console.log("This is beforeMount");
  },
  mounted: function () {
    console.log("This is mounted!");
  },
  beforeUpdate: function () {
    console.log("This is beforeUpdate");
    //this.renderMath();
  },
  methods: {
    addOne: function() {
      this.num++
    },
    randomInt: function () {
      this.num = math.randomInt(1,35)
    },
    renderMath: function (event) {
      this.$nextTick(function(){
        MathLive.renderMathInElement("math");
      })
    }
  }
}).$mount("#app")
<script src="https://unpkg.com/mathjs/dist/math.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mathlive@0.26.0/dist/mathlive.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <span>$${{num}}^2 = {{square}}$$</span>
  <span id="math"></span>
  <button @click="addOne">Add One</button>
  <button @click="randomInt">Random Number</button>
</div>
tony19
  • 125,647
  • 18
  • 229
  • 307
Alex
  • 1,373
  • 8
  • 15
  • I have tried the code above and while it does make sense to use computed instead of a method, the program does not re-typeset the math on the page. The initial value is the one that is being displayed. Any idea on how to get that to work? – 1028 Mar 20 '19 at 04:59
  • What did you expect from `MathLive.renderMathInElement("math");`? What exactly should be rendered in element? Provide example or picture. It's not clear to me. – Alex Mar 20 '19 at 06:55
  • I have expanded on my question to clarify the desired output. I hope it helps! – 1028 Mar 21 '19 at 01:35