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({
...