I want to dynamic create map layers in my template. Therefor I think I need access to the vue instance in my template
<template>
<MglVectorLayer
v-for="(layer, idx) in lLayers"
:key="idx"
:sourceId="'someid'"
:source="somevectorsourcedata"
:layerId="layer"
:layer="this[layer]" <<<<< I need to get the computed propery (layer1 & layer2) here
/>
</template>
export default {
data () {
layers: ['layer1', 'layer2']
},
computed: {
layer1 () {
return (..somelayerdata..)
},
layer2 () {
return (..someotherlayerdata..)
}
}
}
When I leave this out, I get the warning: Expected Object, got String ...
Does anyone know how I can access this? Or maybe there is another/better way of doing this?
Just use a method:
:layer="getLayer(layer)"
methods: {
getLayer(layer) {
return this[layer]
}
}
Since component instance isn't available as this inside v-for, it can be replaced with _self:
:layer="_self[layer]"
Or if specified dynamic property names were data, $data could be used:
:layer="$data[layer]"
Related
For some cases, I don't want to use mixins in my Plugin.
I am trying to add a custom Methods like created(), mounted(), methods{}, so I can access its property when the component is loaded & run my custom method.
example: "customMethod"
// #root/home.vue
<script>
export default {
name: 'Home',
props: {
msg: String
},
mounted(){
//
},
methods{
//
},
customMethod{
}
}
</script>
.vue file
<script>
export default {
customMethod () { // Custom option.
console.log('custom method executed!')
},
methods: {},
created () {},
mounted () {}
}
</script>
plugins/customMethods.js
const customMethods = {
install (Vue) {
// INSTALL
if (this.installed) return
this.installed = true
Vue.options = Vue.util.mergeOptions(Vue.options, {
created: function () {
if (this.$options.customMethod) { // If found in the component.
this.$options.customMethod() // Execute the customMethod.
}
}
})
}
}
export default customMethods
main.js
import customMethods from 'plugins/customMethods.js'
Vue.use(customMethods)
What this does is extend the default options for all Vue instances so
the behavior is applied to every single Vue instance created. This is
however undocumented at the moment.
Alternatively, this can also be achieved by the use of global mixin in the plugin. (which you don't want for some reason as per your use case.)
Moreover, one advanced use case is we may need special handling when merging custom option values during Vue.extend. For example, the created hook has a special merge strategy that merges multiple hook functions into an Array so that all of them will be called. The default strategy is a simple overwrite. If you need a custom merge strategy you will need to register it under Vue.config.optionMergeStrategies:
Vue.config.optionMergeStrategies.customMethod = function (parentVal, childVal) {
// return merged value.
}
Every component can access your customMethod if you inject it into Vue.prototype like this:
Vue.prototype.customMethod = function() {}
I'm trying to accomplish the following but I don't even know if it is even possible with Vue as I'm struggling to get the desired result:
I have an endpoint for an API which returns many objects within an array.
I am successfully rendering the data within my Vue application but I wanted to know if it is possible for Vue to "track" when the array has been updated with more objects and then render those in the view.
I am using setInterval to perform a GET request every 10 minutes and the new data is going into the object within my data() correctly but the changes are not reflected within the view.
At the moment I am changing a boolean from true to false at the beginning and end respectively so that the view is rendered again with v-if.
My goal is to create a simple Twitter feed app that performs a GET request every 10 minutes, collects the tweets, puts them into my Vue instance and show them in the view without having to reload the page/re-render the component. Like an automatic Twitter feed that just constantly loads new tweets every 10 minutes.
Is this even possible? I've tried using the Vue.set() method but that hasn't made any difference.
If it's not possible, what would be the best way to implement something similar?
Here is my code:
JavaScript:
new Vue({
el: '#app',
data: {
items: [],
},
created() {
this.load();
setInterval(() => this.load(), 5000);
},
methods: {
load() {
axios.get('https://reqres.in/api/users?page=2')
.then(response => {
this.items = response.data.data;
});
}
}
});
HTML
<div id="app">
<p v-for="item in items">
{{ item.first_name }}
</p>
</div>
CodePen: https://codepen.io/tomhartley97/pen/VwZpZNG
In the above code, if the array is updated by the GET request, the chances are not reflected within the view?
Yes it is possible. The way you need to set new reactive properties in your Vue instance is the following:
For Object properties: Vue.set(this.baseObject, key, value)
The baseObject cannot be a Vue instance or the base data() object, so you will have to declare a container property.
For Array entries use native array methods: e.g. Array.prototype.push().
Using Vue.set(array, arrayIndex, newArrayElement) does not work
Hence, your solution might look something line that:
<script>
export default {
data() {
return {
response: [],
};
},
mounted() {
setInterval = (() => this.getData), 600000);
}
methods: {
async getData() {
const res = await request();
const resLength = res.data.length;
for (let i = 0; i < resLength; i++) {
// check if entry is already in array
const entryExists = this.response.some((entry) => {
return entry.id === res.data[i].id
})
if (!entryExists) {
// this will make the array entries responsive, but not nested Objects
this.response.push(res.data[i]);
// to create nested responsive Objects you will have to set them explicitly
// e.g. Vue.set(this.response[this.response.indexOf(res.data[i])], nestedObjectKey, res.data[i].nestedObject)
}
}
}
}
};
</script>
Well, I view the codepen, I known why your view do not get update: the api response always return the same array!
Try to return different data.
The api returns an array, so the data defines
data() {
return {
array: [] // array that api returns
}
}
The template may look like this
<div v-for="item in array">
</div>
And the update methods
update() {
setInterval(async () => {
let resp = await api()
this.array = resp.data.concat(this.array)
}, TEN_MINUTES)
}
I feel like I am running out of ideas on how to solve this issue.
So I have a component that should read a file and display some data from that file. I want to pass only the filename to component so that it can handle reading and parsing the file. To do this I added a property to the component.
The issue I seem to have is that I can't really access that property from the data function, and if I add a watcher on the property I can parse the file as expected, but I can't seem to get that data into the DOM.
This is what I have right now:
<template>
<main :key="fileName">
fileName: {{fileName}}
<div class="post">{{data}}</div>
<div class="info">
<div v-for="item in info" v-bind:key="item.name">{{item.name}}</div>
</div>
</main>
</template>
<script>
const { parse } = require("#/service/parser");
const fs = require("fs");
let postInfo = { data: "abc", info: [] };
export default {
props: ["fileName"],
watch: {
fileName: {
immediate: true,
handler: (newVal, oldVal) => {
if (newVal) {
postInfo = parse(
fs
.readFileSync(__dirname + "/../../assets/" + newVal, "utf8")
.split("\n")
);
}
}
}
},
data: () => {
return postInfo;
}
};
</script>
I am obviously completely new to Vue, and I'm probably missing something stupid here.
So what am I doing wrong and how do I get the parsed data into my DOM?
Don't use an arrow function for your data function. Arrow functions bind this to whatever context the function is declared in. You need to let Vue properly bind this to the instance it is creating. So use
data() {
return postInfo;
}
or if for some reason you need to be old school:
data: function () {
return postInfo;
}
I'm using vue-meta to dynamically change my meta tags. I want to change it only on some particular pages.
I'm using metaInfo function and try to change, for example, a title. But data from my getter is undefined which is why I cannot change the title in meta tags. It seems like metaInfo function try to access data before the component actually has it.
Here is my code in the component:
<template>
...
</template>
<script>
export default {
metaInfo() {
return {
title: this.getViewPage.data.meta.title, // data is undefined
};
},
created() {
this.loadViewPage();
},
computed: {
...mapGetters(['getViewPage']),
},
methods: {
...mapActions(['loadViewPage']),
};
</script>
vue-meta just creates computed property from your metaInfo function (according to plugin source code), so I assume that your loadViewPage action fills data object asynchronously and your problem just transforms to null-checking problem.
So you should check data before using its properties, and when data will be loaded metaInfo will update object as well:
metaInfo() {
// don't know your return object structure,
// maybe you should check whole this.getViewPage
let data = this.getViewPage.data;
return {
title: data ? data.meta.title : "some placeholder title",
}
};
I am trying to replace all \n with <br> in a variable. Why I can't send variable as a function parameter to a method from template? Console says Uncaught TypeError: Cannot read property 'replace' of undefined.
I think it calls n2br method but can't send variable as a parameter.
Can anybody know how to solve this problem?
<template>
<div id="iletisim" class="page">
<div>{{ n2br(iletisim.address) }}</div>
</div>
</template>
<script>
export default {
name: "iletisim",
data() {
return {
iletisim: ""
}
},
methods: {
fetch: function() {
this.$http.get(this.site.apiPath + this.site.currentLangCode + "/" +this.$route.params[1]).then(response => {
this.iletisim = response.body.content;
},
response => {
// error callback
});
n2br: function(text) {
text = text.replace(/(?:\r\n|\r|\n)/g, '<br />');
return text;
}
},
beforeMount () {
this.fetch()
}
}
</script>
When this is initially instantiated your 'iletism' data is a string. The string does not have a property of address. So iletism.address is undefined.
When that arrives to your n2br function it calls undefined.replace. Which does not exist, hence the replace does not exist on undefined error.
So either guard for this in n2br method or set a default for iletism so that address exists but is empty string.
You could accomplish same thing with a computed property but same will be true that you will need a base case that is set in data or in the computed method.
Hmm I don't think you need to send it honestly. Sounds like you need a computed property.
Lets say your fetch method sets data property iletisim.
In your template you would do this:
<div>{{ computedIletisim }}</div>
And then in your component after methods add computed
export default {
...
methods: {
...
},
computed: {
computedIletisim: function() {
return this.iletisim.address.replace(/(?:\r\n|\r|\n)/g, '<br />');
}
}
...
}