How can I set up a dynamic attribute within vuejs3. Vanilla js is a lot easier, but within Vue this is apparently not obvious.
I want to be able to use a variable as an attribute.
Something like this:
<q-input
outlined <---(This must be variable "item.design" without any value)
v-model="data.value"
maxlength="12"
class="super-small subshadow-25"
/>
I've read some examples and documentation but the examples are mainly for vuejs2.
Do I miss something?
You can bind data vars to attributes just as easily using v-bind: on the attribute (or the shorthand :):
<q-input
:outlined="outlined"
:filled="filled"
v-model="data.value"
maxlength="12"
class="super-small subshadow-25"
/>
// script (options api)
data() {
return {
item: {
design: 'filled',
},
data: {
value: null,
},
};
},
computed: {
filled() {
return this.item.design === 'filled';
},
outlined() {
return this.item.design === 'outlined';
},
}
Take a look at following snippet you can pass true/false to binded attributes:
const { ref, computed } = Vue
const app = Vue.createApp({
setup () {
const data = ref({value: null})
const item = ref({design: 'filled'})
const design = (type) => {
return item.value.design === 'filled' ? 'outlined' : 'filled'
}
return { data, item, design }
}
})
app.use(Quasar)
app.mount('#q-app')
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/quasar#2.5.5/dist/quasar.prod.css" rel="stylesheet" type="text/css">
<div id="q-app">
<div class="q-pa-md">
<q-btn color="white" text-color="black" label="toogle design" #click="item.design = item.design === 'filled' ? 'outlined' : 'filled'" >
</q-btn>
<q-input
:filled="design(item.design)"
:outlined="design(item.design)"
v-model="data.value"
maxlength="12"
class="super-small subshadow-25"
/>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#2.5.5/dist/quasar.umd.prod.js"></script>
Related
I am trying to initiate a function from methods while an input is keyup, But it's not working. My codes from template are :
<q-input type="number" min="1" dense borderless debounce="300" class="q-ma-xs" v-
model="invoice_product.item_qty" placeholder="quantity" filled
#keyup="calculateLineTotal(invoice_product)" />
My method :
<script>
export default {
setup() {
return {
invoice_product: {
item_qty: ''
}
}
},
methods: {
calculateLineTotal(invoice_product) {
alert(invoice_product.item_qty)
}
}
}
</script>
I also tried with v-on:keyup
enter code hereYou can use watch property using your v model variable and there you can write your logic.
When your model value change it will called watch property
watch:{
“Variable” : function(val) {
//method
}
}
Try to replace setup with data:
new Vue({
el: '#q-app',
data() {
return {
invoice_product: {item_qty: ''}
}
},
methods: {
calculateLineTotal(invoice_product) {
alert(invoice_product.item_qty)
}
},
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/quasar#1.19.5/dist/quasar.min.css" rel="stylesheet" type="text/css">
<div id="q-app">
<q-input type="number" min="1" dense borderless debounce="300" class="q-ma-xs" v-
model="invoice_product.item_qty" placeholder="quantity" filled
#keyup="calculateLineTotal(invoice_product)" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.19.5/dist/quasar.umd.min.js"></script>
I am new to the version of Vue that introduced the "script setup" tag. I would like to trigger a watcher to update the season property and then calculate a new value based on that input. You can see it happening here:
watch(season, () => {
getStandings(season)
}, { immediate: true })
I am trying to trigger the watcher from within a function that is triggered by a child component emitting an event with data. You can see it here:
// in the template
<SeasonSelect :season="season" #changedOption="onChangeSelection"/>
// and then in the script
function onChangeSelection(selection: number) {
console.log(selection, 8);
this.season = selection; // i tried this, this is what I expected to work
}
What I want is for the selection parameter to make it into the watcher. If it goes there, the watcher should take care of the computation as I intend.
Please tell me directly how to handle this. There isn't a lot of findable info about how to handle the special case where "script setup" is used.
Here is the full code for this component, which is the main component called index.vue:
<script setup lang="ts">
import { useDPC } from '#/composables/useDPC';
import { CONFIGS } from '#/configs';
import SeasonSelect from '../components/SeasonSelect.vue';
function onChangeSelection(selection: number) {
console.log(selection, 8);
this.season = selection;
}
const season = $ref<number>(CONFIGS.SEASONS.THE_INTERNATIONAL_11)
const { standings, getStandings, isLoading } = useDPC()
watch(season, () => {
getStandings(season)
}, { immediate: true })
</script>
<template>
<div>
<SeasonSelect :season="season" #changedOption="onChangeSelection"/>
<h1>DPC Standings for {{ season }} season</h1>
<h2 v-if="isLoading">
Loading...
</h2>
<ul v-else>
<div v-for="team in standings" :key="team.team_id">
<Team :team="team"/>
</div>
</ul>
</div>
</template>
edit: please note that the official documentation page about "script setup" doesn't mention how to implement a watcher or update a watcher, and everything is different in a "script setup" file
edit2: Per request of Boussadjra Brahim here is the code for SeasonSelect
<script>
import { CONFIGS } from '../configs';
console.log(CONFIGS, 4);
export default {
data() {
return {
seasons: Object.assign({},CONFIGS.SEASONS)
}
},
props: {
season: Number
},
methods: {
onChange(event) {
console.log(event.target.value, 16)
this.$emit("changedOption", event.target.value);
}
}
}
</script>
<template>
<select v-model="season" name="season" #change="onChange($event)">
<option v-for="(value, key) in seasons" :key="key" :value="value">
{{ key }}
</option>
</select>
</template>
Third edit: Like yo even this detailed breakdown doesnt mention anything about using watched properties in the "script setup" version of a SFC
When you are using <script setup>, it does not mean that you don't need to import necessary stuffs to your codes. You did not import watch in your parent component that uses <script setup>. Also this.season is not correct in <script setup>. Here is a basic example on how to manage your <select> operation in a <script setup> way:
parent component:
<template>
<div>
<SeasonSelect :season="season" #changedOption="onChangeSelection"/>
<h1>DPC Standings for {{ season }} season</h1>
<!-- <h2 v-if="isLoading">-->
<!-- Loading...-->
<!-- </h2>-->
<!-- <ul v-else>-->
<!-- <div v-for="team in standings" :key="team.team_id">-->
<!-- <Team :team="team"/>-->
<!-- </div>-->
<!-- </ul>-->
</div>
</template>
<script setup>
// import { useDPC } from '#/composables/useDPC';
// import { CONFIGS } from '#/configs';
// -------------------------------------------
/* importing things that are necessary from vue */
// -------------------------------------------
import {watch, ref} from "vue";
import SeasonSelect from '../components/SeasonSelect.vue';
const season = ref("value1");
function onChangeSelection(selection) {
console.log(selection, 8);
season.value = selection;
}
// const season = $ref<number>(CONFIGS.SEASONS.THE_INTERNATIONAL_11)
// const { standings, getStandings, isLoading } = useDPC()
watch(season, () => {
console.log("season watch")
})
</script>
<style scoped>
</style>
child component:
<template>
<select v-model="season" name="season" #change="onChange($event)">
<option v-for="(value, key) in seasons" :key="key" :value="value">
{{ key }}
</option>
</select>
</template>
<script>
// import { CONFIGS } from '../configs';
// console.log(CONFIGS, 4);
export default {
name: "SeasonSelect",
data() {
return {
/* I used a simple object to demonstrate the way you can implement this code. */
seasons: {
key1: "value1",
key2: "value2",
key3: "value3"
}
}
},
props: {
season: String
},
methods: {
onChange(event) {
console.log(event.target.value, 16)
this.$emit("changedOption", event.target.value);
}
}
}
</script>
<style scoped>
</style>
I also removed some features like using lang="ts", because they are not related to your question here.
Here are the simplified html and javascript files of the page. It has a button and component which is a text displays the data of the component. I want the component's data to be changed when I click the button. But how to access the component's data from a script?
index.html
<body>
<div id="app">
<my-component></my-component>
<button id="btn"> change data </button>
</div>
<script src="https://unpkg.com/vue#next"></script>
<script src="./main.js"></script>
</body>
main.js
let app = Vue.createApp({});
app.component('my-component', {
data: function() {
return {
component_data : "foo"
}
},
template: '<p> data = {{ component_data }} </p>'
}
);
app.mount("#app");
document.querySelector("btn").onclick = function() {
// HOW TO CHANGE component_data TO "bar"
}
One possibility is to incorporate the button into the HTML within the component's template. If that's feasible for your app then you can add a function to the component and bind the function to the button's click event.
E.g. (Note this is untested so may have typos)
app.component('my-component', {
data: function() {
return {
component_data : "foo"
}
},
methods: {
changeData() {
this.component_data = "The data changed";
}
},
template: `<p> data = {{ component_data }} </p>
<button #click="changeData">Change data</button>`
}
);
If the button can't be incorporated into my-component then I'd recommend using the Vuex datastore. Vuex is a reactive datastore that can be accessed across the entire application.
You can use component props change data between components.
index.html
<body>
<div id="app">
<my-component :component-data="text"></my-component>
<button #click="handleBtnClick"> change data </button>
</div>
<script src="https://unpkg.com/vue#next"></script>
<script src="./main.js"></script>
</body>
main.js file
let app = Vue.createApp({
data() {
return { text: 'foo' }
},
methods: {
handleBtnClick() {
this.text = 'bar';
}
}
});
app.component('my-component', {
props: {
componentData: {
type: String,
default: 'foo'
}
}
template: '<p> data = {{ componentData }} </p>'
}
);
app.mount("#app");
I think you new in Vuejs. You have to first read Vue documentation
To get the reference of a component outside of it, you can use the template refs
Here is the refactor of the code provided in the above question to access the components data from the script.
<div id="app">
<my-component ref="my_component"></my-component>
<button #click="onBtnClick()"> change data </button>
</div>
let app = Vue.createApp({
methods: {
onBtnClick() {
this.$refs.my_component.component_data = "bar";
}
}
});
I have an html string that contains some variables wrapped in {{}}. Is there a way to trigger the parsing of the html to replace {{}} with values that are present in the teamplate already
<div v-html="desc"></div>
desc = "<p>Some text {{aVar}}</p>"
I would like to be able to do something like
v-html="parse(desc)"
and {{aVar}} be replaced with the actual value that is available
Hopefully there is Vue method to do this, but I can definitely use a custom method and replace the values myself.
Thank you
For now I solved it with
function parseHtml(html = "") {
const expose = {
player,
};
return html.replace(/{{(.+?)}}/g, (_, g) => {
return _get(expose, g);
});
}
where _get is the lodash _.get
Like this?
<script setup>
import { ref } from 'vue'
const msg = ref('Hello World!')
const parse = (text) => (`<span style=\"color:red\">${text}<span>`)
</script>
<template>
<input type="text" v-model="msg">
<div v-html="parse(msg)"></div>
</template>
With inspiration from your example #orbitory
What about this?
Options API
<script>
export default {
data() {
return {
template: `<p> {{ message }} {{ message2 }}</p>`,
message: "hello",
message2: "world",
};
},
methods: {
parse(html) {
return html.replace(/{{(.+?)}}/g, (_, g) => {
return this[g.trim()];
});
},
},
};
</script>
<template>
<input v-model="message">
<input v-model="message2">
<div v-html="parse(template)" />
</template>
Demo with reactive input fields example.
https://codesandbox.io/s/how-do-i-render-data-inside-an-html-string-in-vue-before-it-is-displayed-x8oq1?file=/src/App.vue
Composition API
<script setup>
import { ref } from 'vue'
let template = "<p> {{ message }} {{ message2 }} </p>"
let message = ref('hello')
let message2 = ref('world')
let data = { message, message2 }
function parse(html) {
return html.replace(/{{(.+?)}}/g, (_, g) => {
return this[g.trim()].value;
});
}
parse = parse.bind(data)
</script>
<template>
<input v-model="message">
<input v-model="message2">
<div v-html="parse(template)"></div>
</template>
Demo with reactive input fields - based on #tauzN example.
link
I am trying to do a very simple vue example and it won't display. I've done similar things before, but this won't work.
It is an extremely simple task list. It is an input with a submit button that adds an item to a list. For some reason the component does not render at all. I am very lost am supposed to give a presentation on vue. I was hoping to use this as an example.
I'm really not sure what else to say about this, but stack overflow won't let me submit this without typing more information about the issue.
<div id="app">
<task-list></task-list>
</div>
Vue.component('task-list-item', {
props: ["task"],
template: '#task-list-item-template'
})
Vue.component('task-list', {
data: function () {
return {
taskList: [],
newTask: ''
}
},
methods: {
addTask: function () {
var self = this;
if (self.newTask !== ""
&& self.newTask !== null
&& typeof self.newTask !== "undefined") {
this.taskList.push(self.newTask);
this.newTask = "";
}
}
},
template: '#task-list-template'
})
new Vue({
el: '#app',
data: function () {
return {
}
}
})
<script id="task-list-template" type="text/x-template">
<input v-model="newTask" />
<button v-on:click="addTask()">Add Task</button>
<ul>
<task-list-item v-for="taskItem in taskList"
v-bind:task="taskItem">
</task-list-item>
</ul>
</script>
<script id="task-list-item-template" type="text/x-template">
<li>{{task}}</li>
</script>
I am getting no error messages of any kind.
I think the problem is there should be only 1 child under <script id="task-list-template" type="text/x-template"></script>. In task-list-template, you have multiple children. Try to wrap them in 1 div
<script id="task-list-template" type="text/x-template">
<div>
<input v-model="newTask" />
<button v-on:click="addTask()">Add Task</button>
<ul>
<task-list-item v-for="taskItem in taskList"
v-bind:task="taskItem">
</task-list-item>
</ul>
</div>
</script>
Demo on codepen
According to A Single Root Element
Every component must have a single root element
To fix you can do some thing like:
<script id="task-list-template" type="text/x-template">
<div>
<input v-model="newTask" />
<button v-on:click="addTask()">Add Task</button>
<ul>
<task-list-item v-for="taskItem in taskList" v-bind:task="taskItem">
</task-list-item>
</ul>
</div>
</script>