Unable to add elements using the setAttribute - vue.js

I am using the VUE JS code and trying to add the setAttribute to some of the tags.
Here is the code I am using :
changetab() {
const demoClasses = document.querySelectorAll(".delCon__select");
demoClasses.forEach(button => {
button.setAttribute("tabindex", "0");
});
return true;
},
but when I view in the code inspector, It does not show added to it, I have added the above function in computed.
template is like this :
<template>
<el-container class="orders"></el-download>
</template>

You need to make this type of request in Vue's Lifecycles, like: created or mounted.
Something like:
mounted() {
this.changetab()
}
Computed would not be the most appropriate place for this type of action.

Related

Why in my nuxt-link doesn't reload page with same url?

If I’m on a page with the URL 'http://localhost:8080/item' and I’m clicking on the same link on this page, then the page does not reload.
I need to make that if I click on the same link, the page will reload.
My link:
<nuxt-link :to="/item">
Any insight will be welcome. Thanks!
Use key, something like:
<router-view :key="$route.params.yourCustomParam"/>
Also you can use something like:
<router-link :to="{ params: { yourCustomParam: Data.now } }" replace>link</router-link>
Remember to is passed router.push() and it accept an object also. Doing that, it is more declarative and controllable. I'm using this to decide if the page of component should be rerendered since they will based on id params obtained from URL entry, and my child component can still using nesting .
I recently tried to solve a similar issue and to overcome this I used Vuex with :key (ref).
Firstly, in your store you need a state property such as:
export const state = () => ({
componentUpdates: {
item: 0,
//can add more as needed
}
})
In general, you could use only one property across the app if you prefer it that way. Just remember that later on, the key value needs to be unique - that is in the case if you used this property for two or more components within one page, for example. In this case, you could do something like this :key="$store.getters.getComponentUpdates.item+'uniqueString'"
then a getter:
export const getters = {
getComponentUpdates(state) {
return state.updateComponent;
}
}
finally a mutatation:
export const mutations = {
updateComponent(state, payload) {
return state.componentUpdates[payload.update]++
}
}
Now we can utilise the reactive :key wherever needed.
But first in your nuxt-link lets add an event to trigger the mutation, note the usage of #click.native to trigger the click event:
<nuxt-link #click.native="$store.commit('updateComponent', { update: 'item'})" :to="/item">
Now in the item page, for example. Let's imagine there is a component that needs to be updated. In this case we would add :key to it:
<my-item :key="$store.getters.getComponentUpdates.item" />
That is it. As you can see this solution utilises the benefits of nuxt-link but also allows us to selectively update only parts of our page that need updates (we could update the entire page this way as well if needed).
In case if you needed to trigger the logic from mounted or initial load in general, then you could use computed property and :key to your div container, right inside the <template> of your page.
Add :key to the div:
<template>
<div :key="$store.getters.getComponentUpdates.item"></div>
</template>
Create computed property:
computed: {
updateItemPage() {
//run your initial instructions here as if you were doing it in mounted then return the getter
this.initialLoadMethod()
return this.$store.getters.getComponentUpdates.item
}
}
The final touch, which is not crucial but can be implemented in order to reset the state property:
export const mutations = {
updateComponent(state, payload) {
return state.componentUpdates[payload.update] >= 10
? state.componentUpdates[payload.update] = 0
: state.componentUpdates[payload.update]++
}
}

V-model binding to generated input text field

Dynamic V-models created during an ajax request doesn't update when I try inputting a value
I'm using vue2.x and axios. I want to get the value set in generated input when user submit the form. I managed to set v-model on this input during ajax request
I receive this HTLM as response:
<input type="text" value="" v-model="generatedcode">. But after submitting the form the value is still empty. Looks like Vue ignore the v-model directive. How can I fix it ?
Here is my code :
VUE
var app = new Vue({
el: '#subcribtionform',
data: {
generatedform:'',
generatedcode:''
},
methods:{
OnSuccess(response){
this.generatedform = response.data;
},
OnclickSub(){
axios.post('/submitformURL',{
lastname: this.lastname,
generatedcode: this.generatedcode,
})
}
created: function () {
axios.get('/generate_inputURL').then(this.OnSuccess);
}
HTML
<div v-html="generatedform"></div>
GENERATED INPUT
<input type="text" value="" v-model="generatedcode"/>
Try:
created: function () {
axios.get('/generate_inputURL').then(res => this.OnSuccess(res));
}
Component data must be function not object. You should be seeing warning about this in console. I guess your component is not reactive data then, which means that is not redrawn after on request done.
data(): {
return {
generatedform:'',
generatedcode:''
}
}
As I can see, you want to change the vue-app template using v-html attr - I think this is not possible. While mounting the application, the template compiles into render function, so your trick does not make any sense. You can try to do the following:
Construct the template (using html recieved from server as you want ) as string or as hidden el in the DOM
Set it in your app object - template:your_html_template
Create vue app

VueJS - Update Parent Data After Ajax

I'm trying out VueJS, with the aim of incrementally updating a jQuery project, but I'm having issues with props in a child component passed through data from a parent component.
My parent component is
// parent_component.js
var parentData = {};
var parentComponent = Vue.component('parentComponent', {
data: function() {
return {
parentData: _parentData
}
},
delimiters: ['((', '))']
})
$.ajax({
url: '/someUrl/',
success: function(response) {
_parentData = response
}
My Child component is:
// child_component.js
Vue.component('child-component', {
template: '<div>((data.someProp))</div>'
props: ['data'],
delimiters: ['((', '))']
})
My HTML is:
// index.html
<parent-component inline-template>
<child-component v-bind:data="parentData"></child-component>
</parent-component>
This all works fine when I update _parentData right after initializing the childComponent. But I actually need to do an Ajax call and update the _parentData, it is not updated in the childComponent.
Nb. I checked that the _parentData object is there in the callback of the Ajax call.
Also, I tried putting the Ajax call in the created option of the childComponent, but this didn't help.
What am I missing?
Update
I guess I made the classic beginner's mistake! As stated here, Vue cannot detect property addition. So I need to define the someProp property on the _parentData before making the async call.
So if I define var parentData = { someProp: '' }; it will work.
See this fiddle: https://jsfiddle.net/maaikeb/anr1e88n/
If you share the AJAX part of code, maybe I can help better, but IMHO I think that the easiest way is emiting a event from children, and catch it with the parent element when the AJAX call is done (success or error).
Events provide a way to inform your parent components of changes in children.
Template Usage:
<my-component v-on:myEvent="parentHandler"></my-component>
<!-- Or more succinctly, -->
<my-component #myEvent="parentHandler"></my-component>
Firing an Event:
...
export default {
methods: {
fireEvent() {
this.$emit('myEvent', eventValueOne, eventValueTwo);
}
}
}
Additionally, you can create global event buses to pass events anywhere in your app
Extracted from here.
Edit
Ok, I didn't understand you well, if you have problems sending data down from parent to children when updating the parent the proper way is the double data binding.
Maybe your problem is that the data is only evaluated in component creation, and your child will be created with the initial value of the parent component...
You can try some different things to solve this, like:
1 - Maybe your issue is related to a change detection caveat
Maybe you're creating a new property in an object...
_parentData = response
...when you should do...
_parentData.$set('someObject.someProperty', someValue)
2 - Use watch on parent instead of created:
watch:{
yourData() {
$.ajax({
url: '/someUrl/',
content_type: 'application/json',
data_type: 'json',
success: function(response) {
_parentData = response
}
})
},
3 - Try using .sync ( deprecated in 2.0 ):
<component :something.sync="variable"></component>
4 - Bind .this to the anonymous AJAX call or use arrow functions as #Bert commented:
success: () => (response) {
_parentData = response
}
Hope it helps!

vuejs handsontable official and calling handsontable method

I'm a beginner, this is probably more of a javascript problem than vue but anyway:
there a plugin for spreadsheet named handsontable and in the normal use you make the table by doing this
hot = new Handsontable(container, {option})
and then you can use the method like hot.loadData() etc..
To use handsontable with vuejs, there a wrapper we can find here https://github.com/handsontable/vue-handsontable-official. With the wrapper you make a table like this :
<template>
<div id="hot-preview">
<HotTable :root="root" :settings="hotSettings"></HotTable>
</div>
</template>
<script>
import HotTable from 'vue-handsontable-official';
import Vue from 'vue';
export default {
data: function() {
return {
root: 'test-hot',
hotSettings: {
data: [['sample', 'data']],
colHeaders: true
}
};
},
components: {
HotTable
}
mounted () {
localforage.config({
driver: localforage.INDEXEDDB,
name: 'matchlist-database'
})
localforage.getItem('DB').then(function (value) {
console.log('then i fetch the DB: ' + JSON.stringify(value))
if (value !== 'null') {
console.log('dB contain something')
**root**.loadData(value)
}
</script>
So it work fine when i give an array but to load the data from a DB you must call the handsontable method hot.loadData(data).
i cannot find how to call this method in vuejs i always get the error
TypeError: root.loadData is not a function
i tried with all i could think of instead of root ex: HotTable.loadData(value)
but to no avail
Can someone point me out how i would call handsontable methods from the vuejs wrapper. Or point me out what kind of reading i should do to understand my mistake. Thank a lot
There are two problems here, not bad ones :)
1st problem:
If you want to refer to your data inside Vue's methods/computed properties/watchers/lifecycle events, you should use the this keyword. If you have data: function() { return { root: "root-value" }} and you would like to console.log that "root-value" string, you should write console.log(this.root) inside your mounted handler.
If you had something like:
data: function() {
return {
hot = new Handsontable(container, {option})
....
};
You could call hot.loadData() like so:
mounted() {
this.hot.loadData();
...
}
So this refers to the Vue instance which exposes your data properties.
2nd problem:
If I understand the component wrapper correctly, you are supposed to pass data to it as props, not call any Handsontable methods directly.
<HotTable :root="root" :settings="hotSettings"></HotTable>
This means that Vue passes whatever you have as root in your data to the HotTable component. It also passes whatever you have as settings in your data. In the example, HotTable receives these:
root: 'test-hot',
hotSettings: {
data: [['sample', 'data']],
colHeaders: true
}
Now if you want to change/update/modify/add data that should be passed to the HotTable component, you should update your data in the Vue instance. You should do something like this.hotSettings = something new and this.root = something else and the HotTable component would receive those.
To understand what's really happnening with the HotTable, read all of the component documentation. Really. You will save lots of time if you read through the documentation. It all makes sense after that!
https://v2.vuejs.org/v2/guide/components.html

vue-i18n : how to use inside vue instance filter

I want to use a filter to perform translations.
Problem is that 'this' doesn't point to my vue instance inside my filter function.
This is what I currently have.
inside my template I have this:
<p>{{ parking.status | translate }} </p>
inside my component I have this:
new Vue({ ...
filters: {
translate: function(value, vue) {
return this.$i18n.t('MLAA-47');
}
The error I get is that this == undefined.
How do i point it to my vue instance inside my filter function ?
As points #vitaly-mosin in the comment in that answer explains that you couldn't use this inside the filter functions.
filters are primarily designed for text transformation purposes. For
more complex data transforms in other directives, you should use
Computed properties instead.
I had the same issue and I resolved moving the translation with $i18n to a computed method, like:
Inside your template, instead of this:
<p>{{ parking.status | translate }} </p>
Change it to:
<p>{{ translateStatus(parking.status) }} </p>
And in the methods:
methods: {
translateStatus (status) {
return this.$t(status)
}
},
I guess that you have a dynamic status (not returning always: 'MLAA-47') and you should assert that you have translations for all of them. It worked for me!
Hope it helps to you too
We can import file exporting i18n instance like this
import i18n from '#/i18n.js'
And use it like this
i18n.t('your.message')
I am not sure if this is a good idea, but so far it is doing what I want.
Define the filters like
// the instance.vue will be set on App.vue
export const instance = {
vue: null
};
// little helper
const t = (key) => instance.vue?.$t?.(key);
export default {
filter: (v) => v + t('somekey')
}
Then in App.vue (or whatever it is you use), do
import {instance} from '#/filters'
export default {
mounted() {
instance.vue = this; // set the instance here