how to access refs in methods in vuejs - vue.js

I want to access template ref in functions inside method objects. Currently, it throws undefined when accessing the refs.
My Code Below:
<template>
<ul ref="lvl1_target" style="width: 440px" class="lvl1_target milestone_asset_data">
<li :style="{'width': getMileStonePercent(4,'lvl1_target')}" class="hybse_data">
<span></span>
<i></i>
<small>$4M</small>
</li>
</ul>
</template>
And My Code in Script tag is below:
export default {
methods: {
getMileStonePercent(num, secWrp) {
let ele = this.$refs[secWrp]
return ele.offsetWidth + '%'
},
},
created() {},
}
Kindly, provide solution to get the width by accessing the template reference in my function. Thanks in advance.

You need to add a ref attribute to the element you want to target.
I'm not really sure what exactly you are trying to do so here is a generic example instead:
<template>
<div ref="myElement"></div>
</template>
export default {
methods: {
setText() {
this.$refs.myElement.innerHTML = "Hello world"
},
},
}
Vue ref documentation

You can try
export default {
methods: {
this.$next(tick() => {
setText() {
this.$refs.myElement.innerHTML = "Hello world"
}
})
}}

Related

Is it possible to create a vue component to render a list of global components dynamically?

I have some global-registered base components to be listed & rendered on the UI as the user drag and drop it on the layout editor. Then, I want it to be processed on a <ComponentRenderer/> component.
Inside of <ComponentRenderer/>, I currently have this kind of logic:
<template>
<div class="component-renderer">
<radio-button
:pageId="pageId"
:input="input"
:preview="preview"
v-if="input.type == 'radio'"
></radio-button>
<check-box
:pageId="pageId"
:input="input"
:preview="preview"
v-if="input.type == 'checkbox'"
></check-box>
<standard-input
:pageId="pageId"
:input="input"
:preview="preview"
v-if="input.type == 'input'"
></standard-input>
...
...
</div>
</template>
Now instead of hard-coding & comparing it manually using v-if, I want it to dynamically compare itself and render it's element and properties so that I don't need to register the other one when a new component was added. Something that looks like this:
<template>
<div class="component-renderer" v-html="preRenderComponent"></div>
</template>
<script>
export default {
props: {
targetedComponent: {
type: Object,
required: true
}
},
computed: {
preRenderComponent() {
return this.$options.components.filter(
component =>
component.extendOptions.name.toLowerCase() == "base" + this.targetedComponent.type.toLowerCase() // E.g: 'input'
);
}
}
};
</script>
Is it possible? And if possible, how could I render the element and properties? Knowing that when I do console.log(Vue.options.components) and exploring it, it does not provide the element that gonna be rendered.
First thing first, I would say thanks for Steven Spungin & Phil for giving an information about this issue.
I tried to implements it on my code and it does work as I expected. For anyone who wondering what is it looks like, here I provides the code that have been implemented.
LayoutRenderer.vue :
<template>
<GridLayout
v-if="pageComponents.length != 0"
:layout.sync="pageComponents"
:col-num="12"
:row-height="30"
:is-draggable="true"
:is-resizable="true"
:is-mirrored="false"
:vertical-compact="true"
:margin="[10, 10]"
:use-css-transforms="true"
:responsive="true"
:auto-size="true"
>
<GridItem
v-for="component in pageComponents"
:key="component.i"
:x="component.x"
:y="component.y"
:w="component.w"
:h="component.h"
:i="component.i"
>
<!-- <ComponentRenderer :component="component"></ComponentRenderer> -->
<Component :is="named(component)"></Component>
</GridItem>
</GridLayout>
</template>
<script>
import VueGridLayout from "vue-grid-layout";
export default {
components: {
GridLayout: VueGridLayout.GridLayout,
GridItem: VueGridLayout.GridItem
},
data() {
return {
pageComponents: []
};
},
created() {
this.fetchComponents();
},
methods: {
fetchComponents() {
let pageId = this.$route.params.component.pageId;
this.$store.dispatch("components/fetchComponents", pageId).then(() => {
this.pageComponents = this.$store.getters["components/components"];
});
},
named(component) {
let componentName = this.$options.filters.capitalize(component.type);
return `Base${componentName}`;
}
}
};
</script>

Vue: Using input value in function

I am using Single File Components and I have a modal component that has an
input box but I can't get the value of the input in a function below using the v-modal name. It keeps coming back as 'name is not defined'. Am I using the v-model attribute incorrectly?
<template>
<input v-model="name" class="name"></input>
</template>
<script>
export default {
methods: {
applyName() {
let nameData = {{name}}
}
}
}
</script>
You're right, you're using the v-model property incorrectly.
First off you need to define a piece of state in your component, using data:
export default {
data: () => ({
name: '',
}),
methods: {
log() {
console.log(this.name);
}
}
}
You can then bind this piece of data in your component using v-model="name", just like you did. However, if you want to access this piece of state in your method, you should be using this.name in your applyName() method.
Your {{name}} syntax is used to get access to the data in your template, like so:
<template>
<span>
My name is: {{name}}!
</span>
</template>
You have to use this pointer to access the model:
<template>
<input v-model="inputName" class="name"></input>
</template>
<script>
export default {
data() {
return {
inputName: '',
}
},
methods: {
applyName() {
// Notice the use of this pointer
let nameData = { name: this.inputName };
}
}
}
</script>
Look at the doc https://v2.vuejs.org/v2/guide/forms.html#v-model-with-Components
In the template, you are referring by name to data, computed or methods. In this case, it refers to data. When the input changes the name then the data is updated.
It is possible to use in a function referring to this.
<template>
<input v-model="name" class="name"></input>
</template>
<script>
export default {
data() {
return { name: '' }
},
methods: {
applyName() {
let nameData = this.name
}
}
}
</script>

Does kendo grid vue wrapper supports vue column template

I am using vue kendo grid but whenever i use a column template i need to go with html and jquery if there are any method call instead can i use vue template for the column just like row template?.
Yes check this more informations in the forum post
Set a template to a column
<kendo-grid-column :template="itemTemplate"></kendo-grid-column>
Reference to vue file
import Template from "./Template.vue";
var itemTemplate = Vue.component(Template.name, Template);
and
export default {
...
methods: {
itemTemplate: function(e) {
return {
template: itemTemplate,
templateArgs: e
};
}
},
Example of a template
<template>
<span>
<a role='button' class='k-button k-button-icontext filter-clear' href='\\#' #click="buttonClick">
<span class='k-icon k-i-filter-clear'></span>
open
</a>
</span>
</template>
<script>
export default {
name: "template1",
methods: {
buttonClick: function(e) {
alert("Button click");
}
},
data() {
return {
templateArgs: {}
};
}
};
</script>

Why is my computed property not computing?

Below is a single-file Vue.js template. The note object is passed to the template as a prop, and includes audio_length and id.
<template>
<span v-show="note.audio_length > 0" class="audio-element-wrapper">
<audio controls preload="none">
<source :src="audioURL" type="audio/webm">
Your browser does not support the audio element.
</audio>
<span>
({{note.audio_length}}s)
</span>
</span>
</template>
<script>
module.exports = {
mounted: function() {
console.log("mounted audioelement", this.note.id);
},
props: ['note'],
computed: {
audioURL: function() {
return "/notes/getAudio/" + this.note.id;
}
}
};
</script>
However, when I load the component, the computed audioURL results in /notes/getAudio/undefined. Apparently, it runs before the note property is loaded. The code inside the curly braces is interpreted correctly. How can I bind the src property to the correctly computed url?
i suppose is not working because your audioURL computed value return a path without your file format.
try to change your computed:
computed: {
audioURL: function() {
return "/notes/getAudio/" + this.id + ".webm";
}
}
For a better debug i advise you to install vue-devtools
Thanks for everyone's help. It turns out that the problem isn't really with Vuejs per se. It's a browser issue. Even though the src element was actually modified, it doesn't update the action of the element until you call .load()
So, the solution that worked was as follows:
<template>
<span v-show="note.audio_length > 0" class="audio-element-wrapper">
<audio ref="player" controls preload="none">
<source :src="audioURL" type="audio/webm">
Your browser does not support the audio element.
</audio>
<span>
</template>
And then, in the scripts:
updated: function() {
this.audioURL = "/notes/getAudio/" + this.note.id;
this.$refs.player.load();
},
Solution 1 (vue 2.x)
If you want to pass the object properties as a props then you have to use v-bind directive, see the docs here.
I suppose in your parent component you have something like that for data property:
data: function () {
return {
note: {
audio_lenght: 100,
id: 12
}
}
Then write your component as:
<your-component v-bind='note'></your-component>
And in YourComponent.vue:
...
props: ['id', 'audio_lenght']
...
computed: {
audioURL: function() {
return "/notes/getAudio/" + this.id;
}
}
Solution 2
Write your component as:
<your-component :note='note'></your-component>
In YourComponent.vue:
props: {
note: {
type: Object
}
},
computed: {
audioURL: function() {
return "/notes/getAudio/" + this.note.id;
}
}

vue.js get innerhtml from contenteditable element on input

I'm trying to bind a vue.js event to detect a change on an element via contenteditable=true.
<div id="test" contenteditable="true" v-on-input="trigger" v-model="test"></div>
This triggers the trigger method in my vue.js vue, but I can't seem to grab the model value.
Does anyone know how I can grab the innerHTML/innerText after the input event?
Okay short description:
Template:
<div contenteditable="true"
v-html="myHtmlCode"
#input="onDivInput($event)">
</div>
Script:
methods: {
onDivInput: function(e) {
this.myHtmlCode = e.target.innerHTML;
console.log('Text: %o', this.myHtmlCode );
},
},
Solved it by using event.target.innerText in my vue.js component
export default {
data() {
return {
content: null
}
},
methods: {
onFocusOut: function(e) {
this.content = e.target.innerHTML
}
}
}
<div contenteditable="true" v-html="content" #focusout="onFocusOut($event)"></div>
one line only
use #blur instead of #input
<div contenteditable="true" #blur="test = $event.target.innerText">{{test}}</div>