Unable to append html element to the parent in Vue js directive - vue.js

I have a global directive in vue js
Vue.directive('customDirective',{
bind(el,binding,vnode){
// need to get the parent
// append a div after the input element
}
})
I have the following html code .
<div class="parentDiv">
<input type="text" name="firstName" v-customDirective="Some text"/>
</div>
<div class="parentDiv"> is loading dynamically via jquery. I need to get the parent of input tag and need to append some html after the input tag. I have tried with parent(), but it is showing as parent is not a function. Any suggestions ?

You should probably use the inserted hook instead of bind if you want to access the parent element.
You can get the parent element via el.parentElement.

You probably should use vnode, and Vue nextTick.
import Vue from 'vue';
Vue.directive('customDirective',{
bind(el,binding,vnode){
Vue.bextTick(() => {
let parent = vnode.elm.parentElement;
});
}
})
If you want to use parent() which is the jQuery function, you must get the element by jQuery.
Vue.directive('customDirective',{
bind(el,binding,vnode){
Vue.bextTick(() => {
let id = vnode.elm.id;
let parent = jQuery('#'+id).parent();
});
}
})
I'm not sure, that second code works, but it will be something like that.

Related

Unable to add elements using the setAttribute

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.

How to force Vue to update modified HTML

I use a custom directive to render LaTeX-code with KaTeX' renderMathInElement function. This, obviously, changes the component's innerHTML. I would like to re-run KaTeX once the content changes, but: The content never does!
A simple reproduction of the problem does not need KaTeX or directives and still shows, that reactivity works, but stops to work for the parts of a component with changed innerHTML:
<template>
<div>
{{content}}
<span ref="elem">{{content}}</span>
</div>
</template>
<script lang="ts">
import { Component, Ref, Vue } from "vue-property-decorator";
#Component({})
export default class Test extends Vue {
content = "Hello World!";
#Ref()
elem!: HTMLSpanElement;
mounted(): void {
// Without the following statement, Vue correctly re-renders the whole component after a second with the new content
// With this line, the update does not happen for the span element.
this.elem.innerHTML = "<b>Hello World!</b>";
setTimeout(() => {
this.content = "Greetings!";
}, 1000);
}
}
</script>
I suppose this is intended behavior - but that doesn't solve my problem. Is there some way to force Vue to replace all the component's DOM as soon as a re-render takes place?
You can use a key on your span, but if you don't want to tie it in with content, you can instead set it to a number, and increment it every time you want to make a change. Like so (I am not using TS here):
Set a key on your span:
<span :key="content_key">{{ content }}</span>
Then you can watch content and update the key accordingly:
watch: {
content() {
this.content_key ++;
}
}
In this way you can avoid setting the key to content directly.
Does this work for you?

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

Access HTML of DOM element?

With Vue 2 I have this in my template:
<table ref="test">
....
</table>
When I get this via this.$refs.test I get [object HTMLTableElement] is there a way to return the actual HTML?
It's hard to tell what's your purpose in doing this, but if you want to be able to for example display it's outerHTML you have to check if this.$refs.test exists and if it does - render it. This is because refs aren't reactive so using computed properties won't work.
<pre v-if="!!$refs.test">{{$refs.test.outerHTML}}</pre>
If you want to set it's outerHTML to a property or use querySelector or any other DOM operation on it, you need to wait for your component to be mounted.
mounted() {
this.testRowContent = this.$refs.test.querySelector('.test').innerHTML;
}
Example: http://jsfiddle.net/eywraw8t/323125/

Is it posible to delete `div` from template?

I have a component myHello:
<temlate>
<div>
<h2>Hello</h1>
<p>world</p>
</div>
</template>
And main component:
<h1>my hello:</h1>
<my-hello><my-hello>
After rendering shows this:
<h1>my hello:</h1>
<div>
<h2>Hello</h1>
<p>world</p>
</div>
How to delete <div> ?
With VueJS, every component must have only one root element. The upgrade guide talks about this. If it makes you feel better, you are not alone. For what it's worth the components section is a good read.
With the myriad of solutions to your problem, here is one.
component myHello:
<temlate>
<h2>Hello</h1>
</template>
component myWorld:
<temlate>
<p>world</p>
</template>
component main
<h1>my hello:</h1>
<my-hello><my-hello>
<my-world><my-world>
Vue gives you the tools to do so by creating templates or you can do it by having a parent div with two parent divs as children. Reset the data from the data function. Stick with convention (create templates). It's hard to get used to use Vue when you have a jQuery background. Vue is better
Ex.
data () {
message: 'My message'
}
When you click a button to display a new message. Clear the message or just set the message variable with a new value.
ex. this.message = 'New Message'
If you like to show another div. you should used the if - else statement and add a reactive variable. Ex. showDivOne
data () {
message: 'My message'
showDivOne: true,
showDivTwo: false
}
Add this reactive variables to the parent divs that corresponds to the div.
When clicking the button, you should have a function like...
methods: {
buttonClick () {
this.showDivOne = false
this.showDivTwo = true
}
}
I think you can use v-if directive to controll. Add a flag to controll status to show or hide