I have a quasar table that displays some information fetched from an API, and I'm trying to define the columns in a way that makes sense. The API, among other things, returns this:
{
"scan_settings": {
"group_name": "default_group",
"profile_id": "Default Scan",
"scan_occurrence": "Daily",
"scan_window_duration": 3,
"scan_window_initial_time": "12:00:00",
"scan_window_timezone": ""
}
}
I want to display separately group_name, profile_id, scan_occurrence, scan_window_duration and scan_window_initial_time,
As I understand the docs, I could define columns like this:
const columns = [
{
name: 'group_name',
label: 'Qualys scan settings',
field: row => row?.group_name
},
{
name: 'profile_id',
label: 'Qualys scan type',
field: row => row?.profile_id
},
/* and so on */
]
and so each cell would display the value of scan_settings.group_name in that column. However, it's as if the table is looking for a property with the same name as the column, and then using that as the argument for the field function.
This would work with a plain q-table but I'm using the body slot, too, to change display depending on the type of info it's been shown (checkboxes for booleans and so forth)
This is how the body slot looks like (omitting some stuff for brevity):
<template #body="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
class="table-cell"
>
<span v-if="dateColumns.includes(col.name)">
{{ parseISODateStringToLocale(props.row[col.name]) }}
</span>
<!-- omitted for brevity -->
<span v-else>
{{ props.row[col.name] }}
</span>
</q-td>
</q-tr>
</template>
Notice how the template looks for the value - that is the problem, that's what introduces this behaviour. But I don't know what would be the best way to put that value inside of the template instead. What can I do?
If you are using a body slot then fields you can't use directly.
https://codepen.io/Pratik__007/pen/wvXRoWZ
Related
I have this data which is returning me the labels and every I need to create a component.
The component is already built when I pass the values. Now I want to create it as a for loop so that I can keep on adding entries, and it will create components as needed.
This is what I've tried:
data() {
return {
options: [{
heading: 'Welcome to the Card',
subheading: 'Manage your Profile here'
},
{
heading: 'Pay your bills',
subheading: 'Manage your bills and payments here'
}
]
}
}
I am trying to loop it over like this
<div v-for="(value, key) in options">
<componentName {{key}} = {{value}}/>
</div>
Previously, the above code was like this:
<componentName :heading='Welcome to the Card' :subheading='Manage your Profile here'/>
Which works well but to add more I have to recreate this <componentName which I want to avoid. I want to keep one entry and feed it with array of objects
I'm using Vue2. What am I doing wrong here?
You're very close. Given your data, the template would need to look like:
<div v-for="(option, index) in options" :key="index">
<h3>{{ option.heading }}</h3>
<p>{{ option.subheading}}</p>
</div>
Or, if you've got a custom component, which takes heading and subheading as props:
<componentName
v-for="(option, index) in options"
:key="index"
:heading="option.heading"
:subheading="option.subheading"
/>
If you can share a bit more of your code, I can create a runnable snippet, if that would be helpful.
I am in trouble with using duplicated tags in bootstrap Vue.
I am using the form tags in bootstrap Vue.
I cannot add the same value inside existing values.
['apple', 'orange', 'banana']
For example, I cannot add a new value of "apple" if the value of "apple" is already in the value array. This is because the form tag checks duplicated values and blocks to add them to the value array.
How can I add the same value to this array?
Here is the code I'm using:
<template>
<div>
<b-form-tags v-model="value" no-outer-focus class="mb-2">
<template v-slot="{ tags, inputAttrs, inputHandlers, tagVariant, addTag, removeTag }">
<b-input-group class="mb-2">
<b-form-input
v-bind="inputAttrs"
v-on="inputHandlers"
placeholder="New tag - Press enter to add"
class="form-control"
></b-form-input>
<b-input-group-append>
<b-button #click="addTag()" variant="primary">Add</b-button>
</b-input-group-append>
</b-input-group>
<div class="d-inline-block" style="font-size: 1.5rem;">
<b-form-tag
v-for="tag in tags"
#remove="removeTag(tag)"
:key="tag"
:title="tag"
:variant="tagVariant"
class="mr-1"
>{{ tag }}</b-form-tag>
</div>
</template>
</b-form-tags>
</div>
</template>
<script>
export default {
data() {
return {
value: ['apple', 'orange', 'banana']
}
}
}
</script>
This is because you are looping over a string array and using array elements as key. Please read this:
To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key attribute for each item
Notice "you need to provide a unique key attribute for each item", but you are doing opposite and using array element as key, to handle this case you can always use the index from the loop, because index is unique for each element so:
<b-form-tag
v-for="(tag, index) in tags"
#remove="removeTag(tag)"
:key="index"
:title="tag"
:variant="tagVariant"
class="mr-1"
>{{ tag }}</b-form-tag>
</div>
Now this will not give you duplicate items error :)
I'm writing a Vue.js app using BootstrapVue. I'm dynamically generating a form based on a simple "field" data structure (see code and screenshot below). The label for each <b-form-group> comes from a label attribute in my field object. It worked fine until I needed a subscript in the label. I'm using the <sub> HTML tag, but v-bind-ing the label treats the HTML as plain text. See the first column of inputs:
Next I tried using <b-form-group>'s label slot instead, using mustache templates. As documented, this also interprets the value as plain text, so I get the same result -- see the second column.
Finally, I was able to achieve the result I wanted using v-html in a span inside the label slot. This works (see the third column), but it seems a bit convoluted, and it's not making the linter happy (yes, I can always turn it off).
Is there a better way to achieve this? I'm relatively new to Vue.js.
(Note that I've simplified the example for brevity, omitting id's, etc.)
<template>
<div class="m-4">
<b-container>
<b-form-row class="round-border">
<b-col
cols="4"
>
<b-form class="mr-4">
<b-form-group
v-for="(field, index) in fields"
:key="index"
:label="field.label"
>
<b-form-input
v-model.number="form[field.model]"
v-bind="field.atts"
/>
</b-form-group>
</b-form>
</b-col>
<b-col
cols="4"
>
<b-form class="mr-4">
<b-form-group
v-for="(field, index) in fields"
:key="index"
>
<label>{{ field.label }}</label>
<b-form-input
v-model.number="form[field.model]"
v-bind="field.atts"
/>
</b-form-group>
</b-form>
</b-col>
<b-col
cols="4"
>
<b-form class="mr-4">
<b-form-group
v-for="(field, index) in fields"
:key="index"
>
<label><span v-html="field.label" /></label>
<b-form-input
v-model.number="form[field.model]"
v-bind="field.atts"
/>
</b-form-group>
</b-form>
</b-col>
</b-form-row>
</b-container>
</div>
</template>
<script>
export default {
components: {},
data () {
return {
form: {
Length: 1,
Width: 4,
Height: 9
},
fields: [
{ label: 'Label<sub>1</sub>', model: 'Length', atts: { type: 'number', step: 1 } },
{ label: 'Label<sub>2</sub>', model: 'Width', atts: { type: 'number', step: 1 } },
{ label: 'Label<sub>3</sub>', model: 'Height', atts: { type: 'number', step: 1 } }
]
};
}
};
</script>
As #Ian Cho says, if the content of field.label property is html as string, the only way to solve it in vue.js is using v-html.
If you are able to change the field item structure to something like {label: 'Label', sub: 1, ...}, you can use label slot as following:
<b-form-group v-for="(f, i) in fields">
<template slot="label">{{f.label}} <sub>{{f.sub}}</sub></template>
<!-- rest of your code -->
</b-form-group>
DEMO: https://jsfiddle.net/4xmr35p0/
If you have to use HTML tags as parameter, v-html is the only way.
If there's another way, please anyone let me know. ;)
I am using vue-select component as my dropdowns and giving it :options as the data to put in the dropdown. I am using it for a credit card dropdown right now and want to add the card type image in in each dropdown row. Is this possible?
You could use the scoped option slot that vue-select provides for creating custom dropdown templates.
Assuming that your options data looked like this:
options: [
{
title: "Visa",
cardImage: "https://codeclimate.com/github/sagalbot/linktoimage.png"
},
{
title: "Mastercard",
cardImage: "https://codeclimate.com/github/sagalbot/linktoimage.png"
}
];
Then you could use it as such:
<v-select :options="options" label="title">
<template slot="option" slot-scope="option">
<img :src="option.cardImage" />
{{ option.title }}
</template>
</v-select>
I am having a v-for loop in my vuejs application. i want each span to have a different class name. For example .spa0, .spa1, .spa3..... How do I do it using index in v-for loop?
I tried something like this:
:class="`spa${index}`"
Some of my code is:
<div>
<span v-for="(t, index) in table_data" :class="`spa${index}`">{{t}}</span>
</div>
I expect each span to have a different class.
If table_data is like this as you stated in the comments:
{
type: 'LDAP',
des: 'LDAP for Demo - Do not edit or delete this App',
api: 'show token',
scim: 'cloud.kapstonellc.com:8082/scim/v2/10VN44ZN',
endis: true,
act: true
}
You should probably iterate over table_data keys instead:
<div>
<span v-for="(key, index) in Object.keys(table_data)" :class="`spa${index}`">
{{ table_data[key] }}
</span>
</div>