How to specify when a Vue Component has extra functionality? - vue.js

I have a table component, and this table component has the ability to select attributes, however I only want this ability to be available when I need it to be, aka not every time it's rendered. How do I do this?
Functionality snippet from Component.vue to only be active when in a certain file ie Component2.vue
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<b-table-column field="columnValue" v-slot="props2" class="attr-column">
<b-table :bordered="false" class="attr-table" :striped="true" :data="props2.row.columnValues">
<b-table-column field="columnName" v-slot="itemProps">
<SelectableAttribute :attr-name="props2.row.fieldClass" :attr-id="itemProps.row.id" :model-id="itemProps.row.id" model-name="NewParticipant">
{{ itemProps.row.value }}
</SelectableAttribute>
</b-table-column>
</b-table>
</b-table-column>
</b-table>
Component.vue
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<b-table :striped="striped" :bordered="false" :data="participants" detailed class="participant-table" :row-class="() => 'participant-row'">
<b-table-column field="primaryAlias" :label="t('participant.table.primary_alias')" v-slot="props">
<template v-if="props.row.primaryAlias">
<SelectableAttribute attr-name="Alias" :attr-id="props.row.primaryAlias.id" :model-id="props.row.id" model-name="NewParticipant">
{{ props.row.primaryAlias.value }}
</SelectableAttribute>
</template>
<template v-else>-</template>
</b-table-column>
<b-table-column field="primaryEmail" :label="t('participant.table.primary_email')" v-slot="props">
<template v-if="props.row.primaryEmail">
<SelectableAttribute attr-name="Email" :attr-id="props.row.primaryEmail.id" :model-id="props.row.id" model-name="NewParticipant">
{{ props.row.primaryEmail.value }}
</SelectableAttribute>
</template>
<template v-else>-</template>
</b-table-column>
<b-table-column field="primaryAddress" :label="t('participant.table.primary_address')" v-slot="props">
<template v-if="props.row.primaryAddress">
<SelectableAttribute attr-name="Address" :attr-id="props.row.primaryAddress.id" :model-id="props.row.id" model-name="NewParticipant">
{{ props.row.primaryAddress.value }}
</SelectableAttribute>
</template>
<template v-else>-</template>
</b-table-column>
*<b-table-column field="primaryPhone" :label="t('participant.table.primary_phone')" v-slot="props">
<template v-if="props.row.primaryPhone">
<SelectableAttribute attr-name="Phone" :attr-id="props.row.primaryPhone.id" :model-id="props.row.id" model-name="NewParticipant">
{{ props.row.primaryPhone.value }}
</SelectableAttribute>
</template>
<template v-else>-</template>
</b-table-column>*
<b-table-column v-slot="props" cell-class="cell-action">
<slot v-bind="props.row">
</slot>
</b-table-column>
<template slot="detail" slot-scope="props">
<b-table class="attrs-detail-container" :data="tableDataToDataValueCells(props.row)" cell-class="with-bottom-border">
<b-table-column field="columnName" v-slot="props">
<b>{{ props.row.columnName }}</b>
</b-table-column>
<b-table-column field="columnValue" v-slot="props2" class="attr-column">
<b-table :bordered="false" class="attr-table" :striped="true" :data="props2.row.columnValues">
<b-table-column field="columnName" v-slot="itemProps">
<SelectableAttribute
:attr-name="props2.row.fieldClass"
:attr-id="itemProps.row.id"
:model-id="itemProps.row.id"
model-name="NewParticipant"
>
{{ itemProps.row.value }}
</SelectableAttribute>
</b-table-column>
</b-table>
</b-table-column>
</b-table>
</template>
</b-table>
</template>

You can achieve this by using props that you pass while calling that component. That prop could be anything you need. Here is a small example with simple true/false prop:
// Set the prop in your called component, in this case a boolean
props: {
myBoolean: Boolean
}
// Passing the prop from your parent to the component, where it has to be a property, in this case called myBooleanFromParent
<my-component :myBoolean="myBooleanFromParent"></my-component>
// In your component your template changes according to the passed prop from your parent
<template>
<div>
<div v-if="myBoolean">
If myBoolean is true
</div>
<div v-else>
Else, so if myBoolean is false
</div>
</div>
</template>
This is, as stated, a small and simple example. You can pass any kind of data with props. It could also be a object full of data to handle multiple conditions.

Related

How do i add action column with 'edit' and 'delete' buttons?

I want to add action column in the table with delete and edit buttons in it. Table in the image is output of the coded below. An action column is needed in the table in order to perform actions i.e edit and delete.
Table
Code for the table
<b-table
responsive
class="mb-0"
head-variant="light"
:items="items"
:current-page="currentPage"
:per-page="perPage"
>
<template #cell(id)="data"> #{{ data.item.id }} </template>
<template #cell(user)="data">
<b-img
:src="require('#/assets/images/users/' + data.item.user.image)"
rounded="circle"
:alt="data.item.user.image"
width="40"
/>
<span class="ml-2 fw-medium"
>{{ data.item.user.first }} {{ data.item.user.last }}</span
>
</template>
<template #cell(team)="data">
<b-img
:src="require('#/assets/images/users/' + data.item.team.teamimg1)"
rounded="circle"
:alt="data.item.team.teamimg1"
width="35"
class="mr-n2 border border-white"
/>
<b-img
:src="require('#/assets/images/users/' + data.item.team.teamimg2)"
rounded="circle"
:alt="data.item.team.teamimg2"
width="35"
class="mr-n2 border border-white card-hover"
/>
<b-img
:src="require('#/assets/images/users/' + data.item.team.teamimg3)"
rounded="circle"
:alt="data.item.team.teamimg3"
width="35"
class="border border-white"
/>
</template>
<template #cell(status)="data">
<b-badge
pill
:class="`px-2 text-white badge bg-${data.item.status.statusbg}`"
>
<i class="font-9 mdi mdi-checkbox-blank-circle"></i>
{{ data.item.status.statustype }}
</b-badge>
</template>
<template #cell(action)="data">
<b-button variant="light" #click="deleteUser(data.item.user.id)">
<feather type="delete" class="feather-sm"></feather>
</b-button>
</template>
</b-table>
I'd suggest you to use the b-dropdown element (more info here). Your table would then have one column with an "action" description and have a b-dropdown button for each row:
<b-table
responsive
class="mb-0"
head-variant="light"
:items="items"
:current-page="currentPage"
:per-page="perPage"
>
<template #cell(id)="data"> #{{ data.item.id }} </template>
<!--......-->
<template #cell(action)="data">
<b-dropdown
right
variant="primary"
>
<template v-slot:button-content>
Select One
</template>
<b-dropdown-item v-on:click="edit(data.item)">
Edit
</b-dropdown-item>
<b-dropdown-item v-on:click="delete(data.item)">
Delete
</b-dropdown-item>
</b-dropdown>
</template>
</b-table>
Then, in your methods, just add:
edit: function(myObject) {
console.log(myObject);
//Do something here
},
delete: function(myObject) {
console.log(myObject);
//Do something here
},
You could also add one column for each edit and delete feature. In this case, simply create a normal b-button and just call the v-on:click="edit(data.item)" and v-on:click="remove(data.item)" the same way it was implemented on the b-dropdown-items

Vue components: Using slots within slots

I have v-data-table as its own component to make it more generic for my components. I would like to have the option to provide that component how each item in the table is formatted. That would be done with a slot. But the problem is, that the provided slot has a slot for v-data-table. See the example, this is difficult to explain.
In my DataTable component I have:
<v-data-table
:headers="tableHeaders"
:items="items"
:item-key="itemKey"
:loading="isLoading"
v-model="selectedRows"
show-select
>
<!-- What do i put here? -->
</v-data-table>
And I use that data table from my other component like this:
<data-table
:table-headers="tableHeaders"
:items="messages"
:is-loading="isLoading"
:selected-rows="selectedRows"
:item-key="'MessageID'"
>
<template v-slot:item.actions="{ item }">
<v-btn :to="`messages/${item.MessageID}`" icon>
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
</template>
<template v-slot:item.CreatedDateTime="{ item }">
<span>{{ format(new Date(item.CreatedDateTime)) }}</span>
</template>
</data-table>
I need the result to be rendered as:
<v-data-table
:headers="tableHeaders"
:items="items"
:item-key="itemKey"
:loading="isLoading"
v-model="selectedRows"
show-select
>
<template v-slot:item.actions="{ item }">
<v-btn :to="`messages/${item.MessageID}`" icon>
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
</template>
<template v-slot:item.CreatedDateTime="{ item }">
<span>{{ format(new Date(item.CreatedDateTime)) }}</span>
</template>
</v-data-table>
So the problem is, how do I provide the templates within data-table tag to be rendered within v-data-table tag?
I had the exact same issue. I found a solution utilizing the $scopedSlotes object, like this:
<v-data-table
:headers="tableHeaders"
:items="items"
:item-key="itemKey"
:loading="isLoading"
v-model="selectedRows"
show-select
>
<template
v-for="slot in Object.keys($scopedSlots)"
:slot="slot"
slot-scope="scope"
>
<slot
:name="slot"
v-bind="scope"
></slot>
</template>
</v-data-table>
You will have to re-expose the slots in your "wrapper" component:
<v-data-table
:headers="tableHeaders"
:items="items"
:item-key="itemKey"
:loading="isLoading"
v-model="selectedRows"
show-select
>
<template v-slot:body="bodyParams">
<slot name="body" v-bind="bodyParams" />
</template>
<template v-slot:expanded-item="expandedParams">
<slot name="expanded-item" v-bind="expandedParams" />
</template>
<template v-slot:header="headerParams">
<slot name="header" v-bind="headerParams" />
</template>
<template v-slot:footer="footerParams">
<slot name="footer" v-bind="footerParams" />
</template>
<template v-slot:item="itemParams">
<slot name="item" v-bind="itemParams" />
</template>
<template v-slot:progress="progressParams">
<slot name="progress" v-bind="progressParams" />
</template>
<!-- put here the other slots you are interested in -->
</v-data-table>

Vuetify - How can I use the Data-Table search feature to filter by a dynamically calculated field value?

Trying to use Vuetify's Data-Table to search/filter based on the computed value of a field. As feel free to jump into the codepen and type in some values for yourself. For example, I have it setup in such a way that the email address field can be searched by; however, the name of the employee and phone record fields are not functional.
Codepen
https://codepen.io/Jasilo/pen/PooLjbE
VUE:
<div id="app">
<v-app id="inspire">
<v-card>
<header>How can I search by the computed Name and Phone fields?</header>
<v-card-title>
<header>Employee List</header>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="search" label="Search" single-line hide-details></v-text-field>
</v-card-title>
<v-data-table v-bind:headers="headers" v-bind:items="employeesArray" v-bind:search="search">
<template v-slot:item.email="{ item }">
<div>
{{ item["email"] }} </div>
</template>
<template v-slot:item.name="{ item }">
<div>
{{ getName(item) }}
</div>
</template>
<template v-slot:item.phone="{ item }">
<div> {{ getPhone(item) }}</div>
</template>
<template v-slot:no-data>
<div icon="warning">
{{ gridEmpty }}
</div>
</template>
</v-data-table>
</v-card>
</v-app>
</div>
HTML:
<div id="app">
<v-app id="inspire">
<v-card>
<header>How can I search by the computed Name and Phone fields?</header>
<v-card-title>
<header>Employee List</header>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="search" label="Search" single-line hide-details></v-text-field>
</v-card-title>
<v-data-table v-bind:headers="headers" v-bind:items="employeesArray" v-bind:search="search">
<template v-slot:item.email="{ item }">
<div>
{{ item["email"] }} </div>
</template>
<template v-slot:item.name="{ item }">
<div>
{{ getName(item) }}
</div>
</template>
<template v-slot:item.phone="{ item }">
<div> {{ getPhone(item) }}</div>
</template>
<template v-slot:no-data>
<div icon="warning">
{{ gridEmpty }}
</div>
</template>
</v-data-table>
</v-card>
</v-app>
</div>
Simplest way is to use a computed property:
computed: {
employeeTableData() {
return this.employeesArray.map(e => {
return {
email: e.email,
name: this.getName(e),
phone: this.getPhone(e),
};
});
},
},
Then change v-data-table to use employeeTableData instead and directly reference the attributes.
Working codepen
You can then search XD or 666- and it will correctly filter on name and phone number.

VUETIFY - How to pass slot to nested select component

I'm using last version of vuetify and trying to figure out how to make slots work. Documentation about select may be find here
VSelectWithValidation
<v-select v-model="innerValue" :error-messages="errors" v-bind="$attrs" v-on="$listeners">
<template slot="selection" slot-scope="data">
{{ data.item.name }}
</template>
<template slot="item" slot-scope="data">
{{ data.item.name }} - {{ data.item.description }}
</template>
</v-select>
TestComponent
<VSelectWithValidation
rules="required"
:items="items"
v-model="select"
label="Select">
// I WOULD LIKE SLOTS TO BE AT THIS LEVEL
</VSelectWithValidation>
Basically, I would like the slots to be customized so I need to move them out of the VSelectWithValidation component to be set on the TestComponent
I tried different variations with no success.
https://codesandbox.io/s/veevalidate-components-vuetify-u11fd
VSelectWithValidation
You need to create slot inside your template slot item and bind scope data to able to use from other component ..
<template slot="item" slot-scope="data">
<slot name="item" v-bind="data"></slot>
</template>
TestComponent
You can access that slot by writing v-slot:YourSlotName="hereIsBindData"
<template v-slot:item="data">
{{ data.item.name }} // you can code here whatever you like
</template>

How to create a wrapper component in vuejs

I am trying to create a wrapper component around an existing component (q-table from the quasar-framework).
<!-- MyTable.vue -->
<template>
<q-table :title="title" ...>
<template v-slot:top="props">
...
</template>
<template v-slot:body="props">
<q-tr :props="props">
...
</q-tr>
</template>
</q-table>
</template>
<template v-slot:body="props"> and <template v-slot:top="props"> are slots of the q-table component.
How to overwrite these slots in the App.vue:
<!-- App.vue -->
<template>
<div>
<my-table>
???
</my-table>
</div>
</template>