v u e 3

read only

by lid0

HTML

<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>
<div id="app">
<pre style="font-size:11px;">


Testing readonly custom implementation. 
!!! vue actually provide this functionality Vue.readonly()
The parent will pass the child {cities: this.cities}  object
the child will try to set the first city name to "new name child"
on initial render we should only see  the following for both parent and child
 - paris
 - london 
 
few seconds after the parent will update the name  to "new name parent"
and also push a new city.

both parent and child is expected to be updated.
 
</pre>

  <comp-womp :data="getDataReadOnly()"></comp-womp>

  -----
  <p>
    <b>Parent</b>
  </p>
  <p v-for="item in cities">
    {{item.name}}
  </p>


</div>

JavaScript

function createReadOnlyProxy(target) {

  var proxHandler = {
    set: (obj, prop, val) => {
      console.log("readonly denied set for prop: '" + prop + "' with value: '" + val + "'")
      return true
    },
    get: (obj, prop) => {
      if (Array.isArray(obj[prop])) {
        /* return obj[prop] */
        console.log("ARRAY", prop, obj[prop])
        let arrProx = new Proxy([...obj[prop]], proxHandler)
        return arrProx
        return [...obj[prop]]

      } else if (['object'].includes(typeof obj[prop])) {
        console.log("OBJECT", prop, obj[prop])
        let objProx = new Proxy({
          ...obj[prop]
        }, proxHandler)
        //return obj[prop]
        return objProx
      } else {
        console.log("OTHER", typeof(prop), prop, obj[prop])
        return obj[prop]
      }
    }
  }
  let readonlyProxy = new Proxy({
    ...target
  }, proxHandler)
  return readonlyProxy
}

// Child Component
const CompWomp = Vue.defineComponent({
  props: ['data'],
  template: `<b>Child</b>
  <p v-for="item in data.cities">
  {{item.name}}
   </p>
  `,
  mounted() {
    // try to set name  of readonly object.
    this.data.cities[0].name = "new name child"

    if ((this.data.cities[0].name) == "new name child") {
      throw error("should not have been able to update readyonly")
    }
    console.log("CHILD DATA", this.data.cities)
    this.data.cities.push({
      name: "Rome"
    })
  }
})

Vue.createApp({
  components: {
    CompWomp
  },
  data() {
    return {
      cities: [{
          name: 'London',
        },
        {
          name: 'Paris',
        }
      ],
      selected: null
    }
  },
  mounted() {
    //  update name after 5 seconds in parent 
    setTimeout(function() {
      // set/update value 
      this.cities[0].name = "new name parent"
      // push new value
      this.cities.push({
        name: "Rome"
      })
    }.bind(this), 6000)
  },

  methods: {
    getDataReadOnly() {
      let readonlyProxy = createReadOnlyProxy({
 ...