Accessing subcomponents via ref in vu 2.5.2 with typescript 2.4.2 - vuejs2

I ran into a little problem trying to access subcomponents in vue 2.5.2 while using Typescript 2.4.2.
I am trying to access a Keen UI UiSelect component by adding it to $ref with the ref="selectfield" attribute and then access it in my Vue component with this.$refs.selectfield.
The UI-Select component is unrendered with the v-if="showSelect" directive.
onClickSpan(){
showSpan = false;
showSelect = true;
console.dir(this.$refs);
console.dir(this.$refs.selectfield);
}
I have referenced two different elements with ref.
I have already tried outputting this.$refs in the console and the Object selectfield is definitely there:
>{…}
|> currentNumField: <div style="width: 100%;">
|> selectfield: Object { _uid: 32, _isVue: true, "$options": {…}, … }
|> __proto__: Object { … }
undefined
Unfortunately trying to access it will always tell me that this.$refs.selectfield is undefined.
I am pretty new to Vue and Typescript and just don't know what could be causing this problem.
Thank you for your time.

You must give a little more information please.
Look at the example
https://jsfiddle.net/Jubels/50wL7mdz/78450/
this.$refs.paraG would return the node.
this.$refs.custom would return the vue component
<p ref="paraG">{{ message }}</p>
<custom-component ref="custom">{{ message }}</custom-component>
Hope this clear any uncertainty

I am not certain where the problem came from, but for everyone having similar issues here is a possible solution:
Use v-show instead of v-if.
It seems as though the problem is related to the way the DOM is rendered by using v-if.
The ref to the DOM Element is added to the $refs attribute of my component, but the variable $refs.mycomponent is empty since an element that is hidden with v-if is not only not rendered but not even added to the DOM.
I tried using a delay after making the object visible, but that did not solve the problem.
I can only assume that this is due to an issue with typescript that doesn't properly update the $refs attribute whenever the DOM is rerendered since this works with v-if when I am only using Vue.

Related

[Vue][SSR] Suppress hydration mismatch warning

I'm rendering a Vue component to HTML and it is expected that the DOM rendering/hydration doesn't completely match the HTML rendered version.
How can I supress the hydration mismatch warning?
In React there is https://reactjs.org/docs/dom-elements.html#suppresshydrationwarning (Is there any way to avoid "Text content did not match" warning in SSR with React?) — is there a Vue counterpart to this?
Context: I'm the author of vite-plugin-ssr and some of my users need that.
I wish that I can help by commenting on your post instead of posting answers. But you can give this a try:
There is no direct equivalent to React's react-dom/suppressHydrationWarning in Vue, but you can suppress the warning message in a few ways:
By setting the warning option to false in the Vue component:
<template>
<div>
<p v-warning="false">This will not generate a warning</p>
</div>
</template>
By setting the global Vue.config. warning option to false :
Vue.config.warning = false
By setting the environment variable VUE_WARNING_DISABLE to true :
export VUE_WARNING_DISABLE = true
Or by using the vue-cli-plugin-suppress-warnings plugin.
I don't know if there is a Vue counterpart to suppressHydrationWarning but one thing you may try is to manually remove the DOM content before you hydrate.
const rootId = 'app'
const root = document.getElementById(vueRootId)
root.innerHTML = ''
// Your hydration code
// ...
See Remove all child elements of a DOM node in JavaScript for alternative ways to remove the childs of a DOM element.

Vuejs:Why is render method returning dynamic `<component>` giving errors?

I am trying to return vue's builtin <component/> from the render method, but it is not recognizing the component. what could be the possible mistake?
Vue.component('comp1',{
template:'<h1>Component1</h1>'
});
Vue.component('comp2',{
template:'<h1>Component2</h1>'
});
let app=new Vue({
el:'#app',
data:function(){
return {
comp:'comp1'
}
},
mounted:function(){
setInterval(()=>{
if(this.comp=='comp1'){
this.comp="comp2"
}else{
this.comp="comp1"
}
},1000);
},
render (h) {
return h('component', this.comp)
}
})
linkto js bin: https://jsbin.com/wakivet/edit?html,js,console,output
Replace:
render(h){
return h('component',this.comp);
}
with
template: '<component :is="comp" />'
There is no built-in component called component in Vue.
Vue needed a syntax for creating dynamic components in a template. It also needed a way to solve the problems caused by in-DOM templates requiring specific elements as children of other elements. Both of these problems could be solved the same way, with the introduction of the is attribute.
But even though the desired tag name is specified via the is attribute we still need to include a tag name in the template. Any tag will work, but the convention is to use the tag <component>.
<component :is="comp">
Using this convention allows other developers to know that the tag is dynamic. It also makes it easier for the Vue template compiler to optimise the template.
Vue will log a warning if anyone tries to register a global component called component, just like it would for other reserved tag names. This helps to ensure there's no ambiguity when those tags are used.
However, it is just a convention. Using other tags will work just fine and with in-DOM templates it is sometimes necessary, see https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats.
But what about render functions?
The first argument passed to the function h is the tag name. We don't need to use tricks like the is attribute to make that dynamic, we can just pass it directly:
h(this.comp)
In fact, if you write a template containing <component :is="comp"> then Vue will compile it down to something very similar to this. The compiled render function doesn't keep the is attribute, it throws that away and just passes its value to the h function.
You can see this for yourself if you inspect a compiled template. For example, you can use the tool at https://v2.vuejs.org/v2/guide/render-function.html#Template-Compilation to see how templates are compiled to render functions. The function _c is what you called h.
So to reiterate, there is no such component as <component>. It is merely a placeholder in template syntax for some other component. When you're in a render function you should just use the desired component directly.

Why is Vue stripping the style attribute in this one component

I have one Vue component in which any style attribute on any tag in the component template is stripped from the rendered output. Vue 2.6. No build step. The component template is defined in a js template string. Style is stripped whether it's bound or static. Style attributes on neighbouring components are rendered just fine. There are no carriage returns in my styles. Does this suggest anything to anyone ?
Here's the start of my component...
Vue.component("justif-choice", {
template: `
<div style="top:500">
qsdfqdf
</div>
`,
...
This is the line that calls my component...
<xsl:text disable-output-escaping="yes">
<justif-choice ref="justifChoice" ></justif-choice>
And here's the rendered output...
Ok found it. The style rule I was testing, top:500, needed 'px' to be valid. So it was the browser stripping it, not Vue? There may be more to this story because the same code works fine on another page, but adding 'px' has fixed it.

VueJS find element by key

I've just wanted to know if it is possible to find a DOM element by the key attribute of vue?
I'm currently working with a list. I'm displaying it via v-for directive on a div. I'm binding the key with the index of the elements.
v-for="(apk, index) in project.apks" v-bind:key="index"
It would really help me if i could compute something for each of these elements as soon as they are fetch from my server and displayed. It's just parsing a file and looking for keyword, and accordingly choosing a css class for the items.
The problem is I dont know how to call a method for each of these elements as soon as they are added to the DOM. They are a lot of html events but i couldnt find one representing the object beeing inserted to dom :(
The purpose of key is not selecting element. Even if it can be done, don't do it.
The proper way to do it is by using ref.
for example, add ref attribute to your html like this
v-for="(apk, index) in project.apks" v-bind:key="index" :ref="'sample-ref-'+index"
and then in your methods, you can get the DOM using this.$refs['sample-ref-0'],this.$refs['sample-ref-1'] and so on.
Hope this helps.
I found that if you give the 'ref' the same name in a v-for, like this:
<div v-for="data in list" :key="data.id" ref="bar"></div>
Then you will find they just store in an array called 'bar' and you can visit them by:
this.$refs['bar'][index]
something like this could allow you to find a component by key :
this.$children.forEach(child=>{
print("child.$vnode.key")
})
also use mounted , as it gets called when the component is added to the dom:
mounted:function(){
this.$el.querySelector("#ele1")...
}
The problem is I dont know how to call a method for each of these elements as soon as they are added to the DOM. They are a lot of html events but i couldnt find one representing the object beeing inserted to dom :(
You can create a new component with your v-for and just call the created() hook.
Example
/* On your main function */
<div v-for="apk in project.apks">
<apk :data="apk"></apk>
</div>
/* On your 'apk' component */
export default {
props: [ "data" ],
created() {
console.log("Created !");
}
}

vuejs 2 v-for :key not working, html being replaced?

I'm rendering some HTML in a v-for
But everytime I change any of the data, all my html gets replaced (input fields lose their values)
I tried giving the :key all kinds of different values
I didn't have this problem in vue v1, only in v2
http://jsbin.com/jomuzexihu/1/edit?html,js,output
I had a little play with this and it appears that Vue does not re-render the entire list when using <input /> or if you use a component but it does with v-html. Heres the fiddle for the comparison:
https://jsfiddle.net/cxataxcf/
The key actually isn't needed here because the list isn't being re-ordered, so your issue isn't to do with :key but rather with v-html. Heres what the docs say about v-html:
The contents are inserted as plain HTML - data bindings are ignored. Note that you cannot use v-html to compose template partials, because Vue is not a string-based templating engine. Instead, components are preferred as the fundamental unit for UI reuse and composition.
So I guess this is where the problem lies.
It might be worth raising an issue on Vue's github page to see whether this is the expected behavior for v-html, but Vue 2.0 is much more heavily focused on components than vue 1.x and doesn't appear to recommend using v-html, so it may just be that you need to re-factor your code to use components instead.
Edit
The solution to this problem is to simply wrap the code in a component and pass the HTML as a prop:
Vue.component('unknown-html', {
props: {
html: ""
},
template: '<div><div v-html="html"></div>'
})
The markup:
<unknown-html :html="thing.html"></unknown-html>
And the View model:
var app = new Vue({
el: '#app',
data: {
numInputs: 1,
stuff: [{
'html':'<input />'
}, {
'html':'<button>Foo</button>'
}]
}
})
Here's the JSFiddle: https://jsfiddle.net/wrox5acb/
You are trying to inject raw html directly into the DOM. Probably it was possible in earlier versions of Vue.js, but it is definitely not the recommended way.
You can instead have an array of objects and bind it to html as shown in this jsFiddle: https://jsfiddle.net/43xz6xqz/
Vue.js version: 2.0.3
In the example above, vue.js is responsible for creating the input elements and also for binding these input elements to the object values using v-model.
To extract these values, you may use a computed property as shown in the sample code.
I guess, for performance optimization, when the key is not change, Vue will not rerender the dom, but will update the data import through directive.So when your input element is import through an directive (v-html), it will be rerendered everytime when stuff changes.
Due to the vue is not a string template engines, but template based on dom, so in the case of #craig_h 's example , to use the incomming html in a string template within a component:
Vue.component('unknown-html', {
props: {
html: ""
},
template: '<div><div v-html="html"></div>'
})
view:
<unknown-html :html="thing.html"></unknown-html>
So when the stuff changes, it will not to rerender the template declare in string, for vue is not a string template engine.