I'm trying to add some Ctrl + click functionality to a Bootstrap-Vue table in order to select multiple rows. To check if it behaves correctly, I print out some debug info on the page and to the console.
<template>
<div>
<b-table striped hover :fields="fields" :items="items" #row-clicked="rowClick"></b-table>
Debug selected: {{selected.map(item => item.name).join(', ')}}
</div>
</template>
<script>
export default {
name: 'Table',
data () {
return {
fields: [
{key: 'id'},
{key: 'name'}
],
items: [
{id: '1', name: 'Row 1'},
{id: '2', name: 'Row 2'},
{id: '3', name: 'Row 3'},
{id: '4', name: 'Row 4'},
{id: '5', name: 'Row 5'}
],
selected: []
}
},
methods: {
rowClick(item, index, event) {
if(!event.ctrlKey) {
this.selected.forEach(selectedItem => selectedItem._rowVariant = null);
this.selected = [];
}
if(event.ctrlKey && this.selected.includes(item)) {
item._rowVariant = null;
this.selected = this.selected.filter(selectedItem => selectedItem !== item);
} else {
item._rowVariant = 'info';
this.selected.push(item);
}
console.log('Debug selected: ' + this.selected.map(item => item.name).join(', '));
}
}
}
</script>
This works fine, but when I remove the debug line in the template, the table is no longer visually updated and it seems _rowVariant has no effect, even though the console log indicates that the rows are still selected properly.
EDIT: Here is a fiddle: https://jsfiddle.net/aznan/24enw63a/39/
Strange! I could answer it better if you had a fiddle or plnk setup. But still this could be due to a lag.
Try wrapping the function withtin setTimeout like
rowClick(item, index, event) {
setTimeout(function(){
if(!event.ctrlKey) {
this.selected.forEach(selectedItem => selectedItem._rowVariant = null);
this.selected = [];
}
if(event.ctrlKey && this.selected.includes(item)) {
item._rowVariant = null;
this.selected = this.selected.filter(selectedItem => selectedItem !== item);
} else {
item._rowVariant = 'info';
this.selected.push(item);
}
});
}
Related
I am using angular and I have an array of Objects let's say Item(SmallItem, Bollean, Boolean) and in my code I add elements to this array by pushing, like for example:
this.Items.push(new Item(smallItem, false, true));
However, I would like to push an Item if and only if item with the same smallItem does not exist in Items. How do I go about it?
You can simply go back to the basic and do something along thoses lines :
const itemToAdd = new Item(smallItem, false, true);
if(this.Items.findIndex((item) => item.smallItem === itemToAdd.smallItem) < 0) {
this.Items.push(itemToAdd);
}
or if you don't want to create the Item if it is not added :
if(this.Items.findIndex((item) => item.smallItem === smallItemToAdd) < 0) {
this.Items.push(new Item(smallItemToAdd, false, true););
}
You can remove the items afterward with smallItem in it like
Items.forEach((index,item)=>{
if(item.smallItem){
Items.splice(index,1)
)
an other approach could be:
var find = false;
for (let item of Items) {
// same smallItem value
if(item.smallItem) {
find = true;
}
}
if(!find) {
this.Items.push(new Item(smallItem, false, true));
}
Give this a try:
let items = [
{ name: 'Item 1', booleanA: true, booleanB: true },
{ name: 'Item 2', booleanA: true, booleanB: true },
{ name: 'Item 3', booleanA: true, booleanB: true },
{ name: 'Item 4', booleanA: true, booleanB: true },
{ name: 'Item 5', booleanA: true, booleanB: true }
];
function addItemIfNotAlreadyPresent(itemToAdd) {
let itemAlreadyExist = items.find(
item => item.name === itemToAdd.name && item.booleanA === itemToAdd.booleanA && item.booleanB === itemToAdd.booleanB
);
if(!itemAlreadyExist) {
items.push(itemToAdd);
}
}
let itemAlreadyPresent = { name: 'Item 1', booleanA: true, booleanB: true };
addItemIfNotAlreadyPresent(itemAlreadyPresent);
console.log('Items after trying to add itemAlreadyPresent: ', items);
let itemNotPresent = { name: 'Item 6', booleanA: true, booleanB: true };
addItemIfNotAlreadyPresent(itemNotPresent);
console.log('Items after trying to add itemNotPresent: ', items);
I am using selectize to provide inline cell editing in slickgrid. I am able to load this component within cell. But when dropdown options container pops up and it goes beyond the slickgrid viewport, dropdown options container is getting truncated by slickgrid boundary. It should come over the grid. How can I bring the dropdown options container to the top.
var grid;
var columns = [
{ id: 'title', name: 'Title', field: 'title' },
{ id: 'duration', name: 'Duration', field: 'duration' },
{ id: '%', name: '% Complete', field: 'percentComplete' },
{ id: 'start', name: 'Start', field: 'start' },
{ id: 'finish', name: 'Finish', field: 'finish' },
{
id: 'effort-driven',
name: 'Effort Driven',
field: 'effortDriven',
editor: IEditor
},
];
var options = {
enableCellNavigation: true,
enableColumnReorder: false,
editable: true,
autoHeight: true
};
function IEditor(args) {
var selectElement = $('<input type="text"/>');
args.container.append(selectElement[0]);
selectElement.selectize({
create: false,
maxElements: 1,
options: [
{
name: 'A',
value: 'a'
},
{
name: 'B',
value: 'b'
},
{
name: 'C',
value: 'c'
},
{
name: 'D',
value: 'd'
},
{
name: 'E',
value: 'e'
},
{
name: 'F',
value: 'f'
},
],
labelField: 'name',
valueField: 'value'
});
/*********** REQUIRED METHODS ***********/
this.destroy = function() {
// remove all data, events & dom elements created in the constructor
};
this.focus = function() {
// set the focus on the main input control (if any)
};
this.isValueChanged = function() {
// return true if the value(s) being edited by the user has/have been changed
return false;
};
this.serializeValue = function() {
return '';
};
this.loadValue = function(item) {
};
this.applyValue = function(item, state) {
};
this.validate = function() {
return { valid: false, msg: 'This field is required' };
};
}
$(function() {
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = {
title: 'Task ' + i,
duration: '5 days',
percentComplete: Math.round(Math.random() * 100),
start: '01/01/2009',
finish: '01/05/2009',
effortDriven: i % 5 == 0,
};
}
grid = new Slick.Grid('#myGrid', data, columns, options);
grid.init();
});
I have added selectize drop down in Effort Driven column in this plunker
I used to use chosen as my enhanced select but I ran into exactly this problem, and it wasn't solvable due to the HTML it used.
I had to jump ship to Select2. There are examples for this here - check out 'Select2 javascript drop-down editor' and 'Select2 Multiselect javascript drop-down editor'.
Make sure your z-index is bigger than the ones SlickGrid uses. If I remember correctly SlickGrid's highest one was 11 or 12, so with a 13 you should be good to go. Also check the overflow of the cells' css classes; it might happen that your context menu is simply cut off.
I've copied the Grid Component Example into a single-file component (Grid.vue). Within that component, I'm not able to access the columns prop. console.log(this.columns) always prints: [__ob__: Observer] to the log. Can someone tell me why? This works fine in their example on the page and in JSFiddle.
Here's my Grid.vue file:
<script>
export default {
name: 'grid',
props: {
data: Array,
columns: Array,
filterKey: String
},
data: function() {
var sortOrders = {}
console.log(this.columns)
this.columns.forEach((column) => {
sortOrders[column] = 1
});
return {
sortCol: '',
sortOrders: sortOrders
}
},
computed: {
filteredData: function () {
var sortCol = this.sortCol
var filterKey = this.filterKey && this.filterKey.toLowerCase()
var order = this.sortOrders[sortCol] || 1
var data = this.data
if (filterKey) {
data = data.filter((row) => {
return Object.keys(row).some((key) => {
return String(row[key]).toLowerCase().indexOf(filterKey) > -1
})
})
}
if (sortCol) {
data = data.slice().sort((a, b) => {
a = a[sortCol]
b = b[sortCol]
return (a === b ? 0 : a > b ? 1 : -1) * order
})
}
return data
}
},
filters: {
capitalize: function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
},
methods: {
sortBy: function (key) {
this.sortCol = key
console.log(this.sortOrders[key])
this.sortOrders[key] = this.sortOrders[key] * -1
console.log(this.sortOrders[key])
}
},
created() {
},
mounted() {
// var app = this
},
}
</script>
I'm using this component within another component like so:
<template>
<div>
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<grid :data="things" :columns="thingColumns" :filterKey="searchQuery"></grid>
</div>
</template>
<script>
import Grid from './Grid.vue';
export default {
name: 'things-grid',
data: function() {
return {
things: [],
thingColumns: [],
searchQuery: ''
}
},
mounted() {
var app = this
app.things = [
{id: 1, this: 'this 1', that: 'that 1', thing: 'thing 1'},
{id: 2, this: 'this 2', that: 'that 2', thing: 'thing 2'},
{id: 3, this: 'this 3', that: 'that 3', thing: 'thing 3'},
{id: 4, this: 'this 4', that: 'that 4', thing: 'thing 4'},
{id: 5, this: 'this 5', that: 'that 5', thing: 'thing 5'},
]
app.thingColumns = [
'this', 'that', 'thing'
]
app.searchQuery = ''
},
components: { Grid }
}
</script>
In:
<grid :data="things" :columns="thingColumns" :filterKey="searchQuery"></grid>
The value of this.thingColumns is passed as :columns when mounting.
Thus, the console.log(this.columns) inside Grid.vue/data() prints when it is mounting.
And when it is mounting, thingColumns is empty in the parent:
data: function() {
return {
things: [],
thingColumns: [], // initially empty
searchQuery: ''
}
},
mounted() {
var app = this
// ...
app.thingColumns = [ // this code only runs after it is mounted
'this', 'that', 'thing'
]
// ...
},
Since the console.log(this.columns) inside Grid.vue/data() prints when it is mounting, that is, before it is mounted, it prints an empty array:
[__ob__: Observer] // this is an empty array, the __ob__ thing is related to Vue internals
Because, well, parent's thingColumns will only have data after the mounted() hook executes.
And since it is a reactive array, when you update it, it will update the child grid component as well.
Solution:
Move the property initalization code from mounted() to created():
created() { // was mounted()
var app = this
// ...
app.thingColumns = [
'this', 'that', 'thing'
]
// ...
},
This will initialize the data sooner and make it available in time for the console.log() in the child to pick it up.
I am new to development, and learning angular 2 and node. Now working on a project with API integration and in the code below. I am sending all JSON data to array, I tried using JSON.stringify but did not get the desired output. And I need this kind of output:
Area = [
{ value: '3', label: 'sports' },
{ value: '4', label: 'fest' },
{ value: '5', label: 'music' }
];
My ts code is like this
var Area = [];
area=> {
console.log(departments);
area.map(function(areas) {
var array = {"value":area._id,"label":area.areaFor};
Area.push(array);
})
console.log(Area);
},
error => {
console.log(error);
});
but i am getting this output in console
label
"sports"
value
2
label
"fest"
value
3
label
"music"
value
5
You can try this, I changed area to areas inside map function.
area = [
{ value: '3', label: 'sports' },
{ value: '4', label: 'fest' },
{ value: '5', label: 'music' }
];
constructor() {
var Area = [];
Area = this.area.map(function(areas) {
return {"value":areas.value,"label":areas.label};
})
console.log(Area);
}
i have created a tree select that shows a dijit.tree in the dropdown. Now I do not want the user to select a folder even if it is empty. User should only be able to select the end nodes or leaves. dijit.tree treats all empty folders as leafs. how do I get that sorted?
You need to override the _onClick or setSelected methods. This gets complicated if you use the multi-parental model ForestStoreModel.
See fiddle.net
Try doing as such, this will only work for select multiple false:
getIconClass: function fileIconClass(item, nodeExpanded) {
var store = item._S,
get = function() {
return store.getValue(item, arguments[0]);
};
// scope: dijit.Tree
if (item.root || get("isDir")) {
if (!item || this.model.mayHaveChildren(item) || get("isDir")) {
return (nodeExpanded ? "dijitFolderOpened" : "dijitFolderClosed");
} else {
return "dijitLeaf";
}
} else {
return "dijitLeaf";
}
},
onClick: function(item, treeNode, e) {
var store = item._S,
get = function() {
return store.getValue(item, arguments[0]);
};
if (get("isDir")) this.set("selectedItems", []);
}
Adapt as you see fit, matching your json data - in particular the isDir, the above works on a sample of json like this
{
identifier: 'id',
label: 'foo',
items: [
{
id: 'item1',
foo: 'file1',
isDir: false},
{
id: 'item2',
foo: 'emptyDir',
isDir: true},
{
id: 'item3',
foo: 'dir',
isDir: true,
children: [
{
id: 'item3_1',
foo: 'fileInDir',
isDir: false}
]}
]
}