Adjust the select box when option value is bigger using element ui
How this is possible please guide
It should not cut the string after selection
<template>
<el-select v-model="value" placeholder="Select">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
var Main = {
data() {
return {
options: [{
value: 'OptionFirstWithBigCharacter',
label: 'OptionFirstWithBigCharacter'
}, {
value: 'Option2',
label: 'Option2'
}, {
value: 'Option3',
label: 'Option3'
}, {
value: 'Option4',
label: 'Option4'
}, {
value: 'Option5',
label: 'Option5'
}],
value: ''
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
#import url("//unpkg.com/element-ui#2.7.2/lib/theme-chalk/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.7.2/lib/index.js"></script>
<div id="app">
<template>
<el-select v-model="value" placeholder="Select">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
"OptionFirstWithBigCharacter" should display properly
Add some padding to the select input as follows :
.el-select>.el-input {
display: block;
padding-right: 2px;
}
var Main = {
data() {
return {
options: [{
value: 'OptionFirstWithBigCharacter',
label: 'OptionFirstWithBigCharacter'
}, {
value: 'Option2',
label: 'Option2'
}, {
value: 'Option3',
label: 'Option3'
}, {
value: 'Option4',
label: 'Option4'
}, {
value: 'Option5',
label: 'Option5'
}],
value: ''
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
#import url("//unpkg.com/element-ui#2.7.2/lib/theme-chalk/index.css");
.el-select>.el-input {
display: block;
padding-right: 8px;
}
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.7.2/lib/index.js"></script>
<div id="app">
<template>
<el-select v-model="value" placeholder="Select">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
That's an interesting question.
Obviously, the solution would be to calculate the text width of selected value and adjust select to this width, but that's a tricky task.
Under the hood el-select uses <input> element to show selected item, and <input> can't adjust its width based on its value, so we'd need to use another element that can do that. For example, <span> is good choice.
Here is what I've got:
Vue.config.productionTip = false;
var Main = {
data() {
return {
options: [{
value: 'OptionFirstWithBigCharacter',
label: 'OptionFirstWithBigCharacter'
}, {
value: 'Option2',
label: 'Option2'
}, {
value: 'Option3',
label: 'Option3'
}, {
value: 'Option4',
label: 'Option4'
}, {
value: 'Option5',
label: 'Option5'
}],
value: ''
}
},
mounted() {
// pass true to make input use its initial width as min-width
this._addShadow();
},
methods: {
_getElements() {
// helper method to fetch input and its shadow span
const input = this.$refs.resizeable.$el.querySelector('.el-input__inner');
const span = input.previousSibling;;
return { input, span };
},
_addShadow(useMinWidth = false) {
// this method adds shadow span to input
// we'll use this span to calculate text width
const { input } = this._getElements();
const span = document.createElement('span');
span.classList.add('resizeable-shadow');
input.parentNode.insertBefore(span, input);
// copy font, padding and border styles from input
const css = input.computedStyleMap();
span.style.font = css.get('font');
span.style.padding = css.get('padding');
span.style.border = css.get('border');
if (useMinWidth) {
span.style.minWidth = `${input.getBoundingClientRect().width}px`;
}
},
_adjustSize() {
this.$nextTick(() => {
const { input, span } = this._getElements();
span.textContent = input.value;
input.style.width = `${span.getBoundingClientRect().width}px`;
});
},
},
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
#import url("//unpkg.com/element-ui#2.7.2/lib/theme-chalk/index.css");
span.resizeable-shadow {
display: inline-block;
box-sizing: border-box;
position: absolute;
left: -99999px;
top: -99999px;
}
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.7.2/lib/index.js"></script>
<div id="app">
<template>
<el-select v-model="value" placeholder="Select"
ref="resizeable" #change="_adjustSize">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
Code is pretty simple and I've added some comments, so it shouldn't be hard to adjust it to your needs: move it to mixin, add support for multiple selects etc.
Popper works weird in SO snippet, so here is working jsfiddle.
Related
I am using the wizard component, which is a step by step, I am placing a select in each tab, but I have the problem that only the select of the first tab is shown, how could I solve this problem?
component:https://bahadirsofuoglu.github.io/form-wizard-vue3/guide/installation.html
I attach my code:
<template>
<div id="app">
<div>
<h1>Customize with Props</h1>
<Wizard
squared-tabs
card-background
navigable-tabs
scrollable-tabs
:nextButton="{
text: 'test',
icon: 'check',
hideIcon: true, // default false but selected for sample
hideText: false, // default false but selected for sample
}"
:custom-tabs="[
{
title: 'Step 1',
},
{
title: 'Step 2',
},
]"
:beforeChange="onTabBeforeChange"
#change="onChangeCurrentTab"
#complete:wizard="wizardCompleted"
>
<template v-if="currentTabIndex === 0">
<h5>Tab 0</h5>
<v-select
:items="options"
label="Select an option"
v-model="selectedOption"
></v-select>
</template>
<template v-if="currentTabIndex === 1">
<h5>Tab 1</h5>
<v-select
:items="options"
label="Select an option"
v-model="selectedOption"
></v-select>
</template>
</Wizard>
</div>
</div>
</template>
<script>
import "form-wizard-vue3/dist/form-wizard-vue3.css";
import Wizard from "form-wizard-vue3";
export default {
name: "App",
components: {
Wizard,
},
data() {
return {
currentTabIndex: 0,
options: ["Option 1", "Option 2", "Option 3"],
selectedOption: "",
};
},
methods: {
onChangeCurrentTab(index, oldIndex) {
console.log(index, oldIndex);
this.currentTabIndex = index;
},
onTabBeforeChange() {
if (this.currentTabIndex === 0) {
console.log("First Tab");
}
console.log("All Tabs");
},
wizardCompleted() {
console.log("Wizard Completed");
},
},
};
</script>
attached image:
tab 1:
tab2:
From quick look at the documentation it seems that you need all of the steps content to be wrapped with <template #activeStep>. And then inside your v-if logic probably.
In a b-table, each cell in a column should have different text color. Not the background of the cell, but the actual text color. I am able to change the text color of the column header, but not the individual cell texts.
The b-table code:
<b-card title="Total">
<b-table sticky-header="600px" hover :items="total" :fields="groupByFields"></b-table>
</b-card>
The fields where the column header color change is:
groupByFields: [
{
key: 'name',
sortable: true,
},
{
label: 'Total',
key: 'count',
},
{
key: 'interested',
thStyle: { color: '#3eef33' },
sortByFormatted: false,
formatter: (value) => {
const res = value;
return (`($${res})`);
},
},
],
The thStyle color attribute changes the header text color, but not the text of values in the cells of that column. How would I match that color to the cell text (not background) of that column too?
Here's an example, using the #cell() slot:
new Vue({
el: '#app',
data: () => ({
items: [],
fields: [
'id',
{ key: 'title', style: { fontStyle: 'italic' } },
{ key: 'price', style: { color: 'red', textAlign: 'right' } }
]
}),
mounted() {
fetch('https://dummyjson.com/products')
.then(_ => _.json())
.then(_ => this.items = _.products);
}
})
<link href="https://unpkg.com/bootstrap#4.6.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.22.0/dist/bootstrap-vue.css" rel="stylesheet"/>
<script src="https://unpkg.com/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.22.0/dist/bootstrap-vue.js"></script>
<div id="app">
<b-table :items="items" :fields="fields">
<template #cell()="{field, value}">
<div :style="field.style" v-text="value" />
</template>
</b-table>
</div>
If you only need to style a few columns, you might want to use appropriate #cell({key}) slots.
Documentation here.
Probably the most common technique is to add classes to cells. It provides granular control over the applied styling, without sacrificing flexibility.
I made a vue.js bootstrap table for loading some data from local JSON files.
I'm trying to implement show/hide columns via checkboxes.
I think I've solved most of the problem, but the problem is when I hide a column and then press on that same checkbox again (to make column visible again) I lose the order of table (that column becomes last column) and so on.
For example if I hide "Timestamp" column which is first table header in my table and then press to show it again it is no longer on first place, instead it gets created on last place.
https://imgur.com/BaTfgci --> this is how app looks right now
https://codepen.io/frane_caleta/pen/KKPMKrL --> codepen of my code, you won't be able to load it without JSON file though
https://imgur.com/a/23jx0lZ --> JSON data example
First time asking question here, so feel free to ask me if you need some more information to solve the problem :)
<b-form-group label="Hide columns: ">
<b-form-checkbox-group id="checkbox-group-1" v-model="selected" :options="fields" name="flavour-1">
</b-form-checkbox-group>
</b-form-group>
//my table
<b-table id="myTable"
:small="small"
:bordered="bordered"
hover head-variant="dark"
stacked="md"
:items="cptItems"
:fields="selected"
:current-page="currentPage"
:per-page="perPage"
:filter="filter"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
#filtered="onFiltered"
:tbody-tr-class="rowClass"
v-if="selected.length > 0">
</b-table>
//Javascript file
function initializeVue() {
return new Vue({
el: '#app',
data() {
return {
items: data.logdatas,
selected: [],
fields: [{
text: 'Origin',
value: {
key: 'origin',
label: 'Origin',
sortable: true,
class: 'text-center',
index: 0
}
},
{
text: 'Timestamp',
value: {
key: 'timeStamp',
label: 'Timestamp',
sortable: true,
class: 'text-center',
index: 1
}
},
{
text: 'Level',
value: {
key: 'level',
label: 'Level',
sortable: true,
class: 'text-center',
index: 2
}
}, ...there are 4 more fields here like this...
//my method for creating those checkboxes
created() {
this.selected = this.fields.map(field => field.value);
}
the selected data is your culprit. b-checkbox-group :selection lists items in order of selection.
example2
b-table :fields lists columns in the order of the items.
better make a static fields-list and filter by selection.
// make this data or property
let columnNames = ["one", "two", "three", "infinity", "pi"];
// make this data
let selected = []
//make this computed // can be optimized
let activeFields = columNames.filter(name => selected.includes(name))
// more like this
export default {
data(){
return {
selected: [],
columnNames: ['name1', 'name2']
},
computed(){
activeColumns(){
return this.columnNames.filter(this.selected.includes) || []
}
}
const app = new Vue({
data(){
return {
currentPage: 0,
perPage: 10,
fields: ['age', 'first_name', 'last_name'],
//selected: [],
selected: ['age', 'first_name', 'last_name'],
items: [
{ age: 40, first_name: 'Dickerson', last_name: 'Macdonald' },
{ age: 21, first_name: 'Larsen', last_name: 'Shaw' },
{ age: 89, first_name: 'Geneva', last_name: 'Wilson' },
{ age: 38, first_name: 'Jami', last_name: 'Carney' }
]
}
},
computed: {
activeFields(){
return this.fields.filter(name => this.selected.includes(name))
}
}
}).$mount("#app");
<!-- Add this to <head> -->
<!-- Load required Bootstrap and BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.css" />
<!-- Load polyfills to support older browsers -->
<script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver" crossorigin="anonymous"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="//unpkg.com/vue#latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-form-group label="Hide columns: ">
<b-form-checkbox-group id="checkbox-group-1" v-model="selected" :options="fields" name="flavour-1">
</b-form-checkbox-group>
</b-form-group>
<b-table id="myTable"
:bordered="true"
hover head-variant="dark"
stacked="md"
:items="items"
:fields="selected"
:current-page="currentPage"
:per-page="perPage"
tbody-tr-class="row-class"
v-if="selected.length > 0">
</b-table>
<b-table id="myTable"
:bordered="true"
hover head-variant="dark"
stacked="md"
:items="items"
:fields="activeFields"
:current-page="currentPage"
:per-page="perPage"
tbody-tr-class="row-class"
v-if="selected.length > 0">
</b-table>
</div>
I have a <filter> component in a .vue file that has some properties to control the filter of a query.
This <filter> can be added / removed on-the-fly as the user needs. It's behavior is very similar to the Google Analytics segmentation filter, or Advanced Custom Fields from WordPress.
The only solution I see is instantiating this component dynamically and iterate over an array of these components inside my main app, but I don't exactly know how to do it.
Vue.component("my-filter", {
template: "#filterTemplate",
data: function() {
return {
field: null,
value: null
}
},
mounted: function() {
this.$emit("filter-created", this);
},
methods: {
removeFilter: function() {
console.log("Remove this filter");
}
}
});
var app = new Vue({
el: "#app",
data: {
filtersCount: 5,
filters: [] // PROBLEM! I can't decrement on my filtersCount and remove the correct filter. Iteration should be over my "filtersCount" property.
},
methods: {
filterCreated: function(filterObj) {
this.filters.push(filterObj);
},
addFilter: function() {
this.filtersCount += 1;
}
}
});
* {
font-family: "Helvetica", "mono";
font-size: 16px;
}
.filterContainer + .filterContainer {
margin-top: 10px;
}
.filterContainer {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<!-- I shouldn't iterate over an integer value, but over an array of objects to remove the right ones -->
<my-filter v-on:filter-created="filterCreated" v-for="(index, filter) in filtersCount" :key="index"></my-filter>
<br>
<button #click="addFilter">Add filter</button>
</div>
<script type="text/x-template" id="filterTemplate">
<div class="filterContainer">
<input type="text" :value="field" placeholder="Field" />
<input type="text" :value="value" placeholder="Value" />
<button #click="removeFilter">Remove filter</button>
</div>
</script>
A few things can be changed to get it working (I'm just assuming what you are looking for!)
First, you don't need a data property for counting filters (filtersCount), you can loop through the filters property.
Second, adding this to the filters property can cause unexpected behaviour because this references the entire Vue component. I would recommend adding plain objects that represent the filter data and pass the data as props. Note: that the index is also passed as a prop which can be referenced and allow the filter to be removed through emitting
And lastly, your v-for seems to be reversed. It should be (filter, index) instead of (index, filter).
Vue.component("my-filter", {
template: "#filterTemplate",
props: [
'field',
'value', // filter data
'id',
'index' // index that allows this filter to be removed
],
data: function() {
return {
field: this.field,
value: this.value
}
},
methods: {
removeFilter: function() {
this.$emit('remove-filter', this.index);
},
handleInput: function(prop, e) {
this.$emit('update-filter', { index: this.index, prop, value: e.target.value });
}
}
});
window.vm = new Vue({
el: "#app",
data: {
filters: [
{ id: 1, field: null, value: null },
{ id: 2, field: null, value: null },
{ id: 3, field: null, value: null },
{ id: 4, field: null, value: null },
{ id: 5, field: null, value: null }
]
},
methods: {
addFilter: function() {
var id = Math.max.apply(Math,this.filters.map(function(o){return o.id;})) + 1;
this.filters.push({ id, field: null, value: null });
},
removeFilter: function(index) {
this.filters.splice(index, 1);
},
updateFilter: function(payload) {
this.filters[payload.index][payload.prop] = payload.value;
}
}
});
* {
font-family: "Helvetica", "mono";
font-size: 16px;
}
.filterContainer + .filterContainer {
margin-top: 10px;
}
.filterContainer {
display: block;
border: 1px solid black;
padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<button #click="addFilter">Add Filter</button>
<br><br>
<my-filter v-for="(filter, index) in filters" :key="index" :field="filter.field" :value="filter.value" :id="filter.id" :index="index" #remove-filter="removeFilter" #update-filter="updateFilter"></my-filter>
</div>
<script type="text/x-template" id="filterTemplate">
<div class="filterContainer">
<div>Index: {{ index }}, ID: {{ id }}</div>
<input type="text" :value="field" placeholder="Field" #input="handleInput('field', $event)" />
<input type="text" :value="value" placeholder="Value" #input="handleInput('value', $event)" />
<button #click="removeFilter">Remove filter</button>
</div>
</script>
I'm working on a HTML5 and JavaScript website.
Is it possible to have a hidden column in Kendo UI Grid and access the value using JQuery?
Using JavaScript
See the Kendo UI API reference.
Hide a column during grid definition
You can add hidden: true:
$("#gridName").kendoGrid({
columns: [
{ hidden: true, field: "id" },
{ field: "name" }
],
dataSource: [ { id: 1, name: "Jane Doe" }, { id: 2, name: "John Doe" } ]
});
Hide a column by css selector
$("#gridName").find("table th").eq(1).hide();
Hide a column by column index
var grid = $("#gridName").data("kendoGrid");
grid.hideColumn(1);
Hide a column by column name
var grid = $("#gridName").data("kendoGrid");
grid.hideColumn("Name");
Hide a column by column object reference
var grid = $("#gridName").data("kendoGrid");
grid.hideColumn(grid.columns[0].columns[1]);
Using React
See the Kendo UI for React API reference
Hide a column during grid definition
You can set show: false:
class App extends React.Component {
columns = [
{
title: 'Product Id',
field: 'ProductID',
show: false
},
{
title: 'Product Name',
field: 'ProductName',
show: true
},
{
title: 'Unit Price',
field: 'UnitPrice',
show: true
}
]
constructor() {
super();
this.state = {
columns: this.columns,
show:false
};
}
render() {
return (
<div>
<Grid data={products} >
{this.state.columns.map((column, idx) =>
column.show && (<Column key={idx} field={column.field} title={column.title} />)
)}
</Grid>
</div>
);
}
}
Using Angular
See the Kendo UI for Angular API reference
Hide a column during grid definition
You can add [hidden]="true"
#Component({
selector: 'my-app',
template: `
<kendo-grid [data]="gridData" [scrollable]="scrollable" style="height: 200px">
<kendo-grid-column [hidden]="true" field="ID" width="120">
</kendo-grid-column>
<kendo-grid-column field="ProductName" title="Product Name" width="200">
</kendo-grid-column>
<kendo-grid-column field="UnitPrice" title="Unit Price" width="230">
</kendo-grid-column>
</kendo-grid>
`
})
Programmatically hide a column
#Component({
selector: 'my-app',
template: `
<div class="example-config">
<button (click)="restoreColumns()" class="k-button">Restore hidden columns</button>
</div>
<kendo-grid [data]="gridData" style="height:400px">
<ng-template ngFor [ngForOf]="columns" let-column>
<kendo-grid-column field="{{column}}" [hidden]="hiddenColumns.indexOf(column) > -1" >
<ng-template kendoGridHeaderTemplate let-dataItem>
{{dataItem.field}}
<button (click)="hideColumn(dataItem.field)" class="k-button k-primary" style="float: right;">
Hide
</button>
</ng-template>
</kendo-grid-column>
</ng-template>
</kendo-grid>
`
})
export class AppComponent {
public gridData: any[] = sampleCustomers;
public columns: string[] = [ 'CompanyName', 'ContactName', 'ContactTitle' ];
public hiddenColumns: string[] = [];
public restoreColumns(): void {
this.hiddenColumns = [];
}
public hideColumn(field: string): void {
this.hiddenColumns.push(field);
}
}
Using Vue
See the Kendo UI for Vue API reference
Hide a column during grid definition
You can add :hidden="true"
<kendo-grid :height="600"
:data-source-ref="'datasource1'"
:pageable='true'>
<kendo-grid-column field="ProductID" :hidden="true"></kendo-grid-column>
<kendo-grid-column field="ProductName"></kendo-grid-column>
<kendo-grid-column field="UnitPrice" title="Unit Price" :width="120" :format="'{0:c}'"></kendo-grid-column>
<kendo-grid-column field="UnitsInStock" title="Units In Stock" :width="120"></kendo-grid-column>
</kendo-grid>
Using ASP.NET MVC
See the Kendo MVC API reference
Hide a column during grid definition
#(Html.Kendo().Grid<Something>()
.Name("GridName")
.Columns(columns =>
{
columns.Bound(m => m.Id).Hidden()
columns.Bound(m => m.Name)
})
)
Using PHP
See the Kendo UI for PHP API reference
Hide a column during grid definition
<?php
$column = new \Kendo\UI\GridColumn();
$column->hidden(true);
?>
As #Nic says there are multiple ways of hiding a column but I'm gonna assume that you are using KendoUI methods for hiding it. I.e: set the column hidden to true or programmatically invoke hideColumn.
If so, you should remember that you model might have fields that are not displayed or not even mapped in columns but they exist and you can still access them.
If we have the following Grid definition:
var grid = $("#grid").kendoGrid({
dataSource: ds,
selectable: true,
...
columns :
[
{ field: "Id", hidden: true },
{ field: "FirstName", width: 90, title: "First Name" },
{ field: "LastName", width: 200, title: "Last Name" }
]
}).data("kendoGrid");
Where I've declared a column Id as hidden. I still can access the value of Id by going to the model using:
// I want to access the Id for row 3
var row = $("tr:eq(3)", "#grid");
// Retrieve the item from the grid using dataItem method
var item = $("#grid").data("kendoGrid").dataItem(row);
// Show Id
alert("Id is " + item.Id);
Runnable example
var grid = $("#grid").kendoGrid({
dataSource: [
{ Id: 1, FirstName: "John", LastName: "Smith" },
{ Id: 2, FirstName: "Jane", LastName: "Smith" },
{ Id: 3, FirstName: "Jack", LastName: "Smith" },
{ Id: 4, FirstName: "Joseph", LastName: "Smith" },
{ Id: 5, FirstName: "Jeff", LastName: "Smith" },
],
selectable: true,
columns :
[
{ field: "Id", hidden: true },
{ field: "FirstName", width: 90, title: "First Name" },
{ field: "LastName", width: 200, title: "Last Name" }
]
}).data("kendoGrid");
$("#show").on("click", function(e) {
var row = grid.select();
if (row) {
var item = grid.dataItem(row);
alert ("The ID is :" + item.Id);
} else {
alert("Select a row");
}
});
#grid {
width : 490px;
}
<link href="http://cdn.kendostatic.com/2014.2.903/styles/kendo.common.min.css" rel="stylesheet" />
<link href="http://cdn.kendostatic.com/2014.2.903/styles/kendo.default.min.css" rel="stylesheet" />
<script src="http://cdn.kendostatic.com/2014.2.903/js/jquery.min.js"></script>
<script src="http://cdn.kendostatic.com/2014.2.903/js/kendo.all.min.js"></script>
Select row and click <button id="show" class="k-button">Here</button> to show hidden Id.
<div id="grid"></div>