hopefully this will be helpful to someone else. I'm using ag-grid enterprise's context menu feature. I wanted to have a shortcut key corresponding to the menu items, but nothing happened when I pressed the key combination.
To make it more confusing (to me) their own example of how to do this doesn't work:
https://www.ag-grid.com/javascript-grid-context-menu/
The problem is that the shortcut attribute only lists the shortcut but doesn't fire anything. You must also write an event handler for the cellKeyDown event to watch for the shortcut:
import { Component } from '#angular/core';
import { GetContextMenuItemsParams } from 'ag-grid-community';
#Component({
selector: 'app-root',
template:
`
<ag-grid-angular style="width: 500px; height: 500px;" class="ag-theme-balham"
[rowData]="rowData" [columnDefs]="columnDefs"
[getContextMenuItems]="getContextMenuItems"
(cellKeyDown)="onCellKeyDown($event)">
</ag-grid-angular>
`,
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'ag-grid-import-excel';
columnDefs = [
{headerName: 'Make', field: 'make' },
{headerName: 'Model', field: 'model' },
{headerName: 'Price', field: 'price'}
];
rowData = [
{ make: 'Toyota', model: 'Celica', price: 35000 },
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxter', price: 72000 }
];
getContextMenuItems(params:GetContextMenuItemsParams ) {
return [
'copy',
'copyWithHeaders',
'paste',
'separator',
{
name: "insert",
shortcut: "Alt + i",
action: function() {
console.log("insert");
},
icon: '<i class="fas fa-plus"></i>'
},
'export',
];
}
onCellKeyDown($event) {
let event:KeyboardEvent = $event.event;
if (event.altKey && event.key === "i") {
console.log('alt i pressed')
}
}
}
Related
I have a bootstrap table that shows a list of appliances. I am importing my data with Axios and for this specific table I am outputting data from two database tables, so I have one object which is called applianceReferences which stores another object called activeAppliances.
Not sure if it is relevant for this question, but just so you know.
Before talking about the problem, let me just post the whole code and below I will talk about the section that is giving me issues.
<template>
<b-container class="my-2">
<b-card v-if="showTable" class="ml-4 mr-4">
<b-table
search-placeholder="search"
:filter-included-fields="fields.map(f => f.key)"
include-filter
:items="applianceReferences"
:fields="fields"
/>
</b-card>
</b-container>
</template>
<script>
import {applianceService} from "#/services/appliance";
import CommonCollapsible from "#/components/common/CommonCollapsible";
import moment from 'moment';
export default {
components: { CommonCollapsible, CommonTable },
props: {
ownerId: String,
ownerType: String,
showDocuments: Boolean,
goToAppliances: "",
importAppliances: ""
},
data() {
return {
applianceReferences: [],
showTable: true
}
},
computed: {
fields() {
return [
{
key: 'referenceName',
label: this.$t('referenceName'),
sortable: true
},
{
key: 'activeAppliance.type',
label: this.$t('type'),
sortable: true,
},
{
key: 'activeAppliance.brandName',
label: this.$t('brand'),
sortable: true
},
{
key: 'activeAppliance.purchaseDate',
label: this.$t('purchaseDate'),
sortable: true,
template: {type: 'date', format: 'L'}
},
{
key: 'activeAppliance.warrantyDuration',
label: this.$t('warrantyDuration'),
sortable: true,
formatter: (warrantyDuration, applianceId, appliance) =>
this.$n(warrantyDuration) + ' ' +
this.$t(appliance.activeAppliance.warrantyDurationType ?
`model.appliance.warrantyDurationTypes.${appliance.activeAppliance.warrantyDurationType}` :
''
).toLocaleLowerCase(this.$i18n.locale),
sortByFormatted: (warrantyDuration, applianceId, appliance) =>
appliance.activeAppliance.warrantyDurationType === 'YEARS' ? warrantyDuration * 12 : warrantyDuration
},
{
key: 'activeAppliance.purchaseAmount',
label: this.$t('amount'),
sortable: true,
template: {
type: 'number', format: {minimumFractionDigits: '2', maximumFractionDigits: '2'},
foot: sum
}
},
{
key: 'actions',
template: {
type: 'actions',
head: [
{
text: 'overviewOfAppliances',
icon: 'fas fa-fw fa-arrow-right',
action: this.createAppliance
},
{
icon: 'fas fa-fw fa-file-excel',
action: this.importAppliance,
tooltip: this.$t('importAppliances'),
}
],
cell: [
{
icon: 'fa-trash',
variant: 'outline-danger',
action: this.remove
},
]
}
}
]
},
},
methods: {
load() {
Object.assign(this.$data, this.$options.data.apply(this));
this.applianceReferences = null;
applianceService.listApplianceReferences(this.ownerId).then(({data: applianceReferences}) => {
this.applianceReferences = applianceReferences;
this.applianceReferences.forEach( reference => {
applianceService.listAppliances(reference.id).then(result => {
this.$set(reference, 'appliances', result.data);
this.$set(reference, 'activeAppliance', result.data.find(appliance => appliance.active))
this.loaded = true
})
})
}).catch(error => {
console.error(error);
})
},
createAppliance(){
this.goToAppliances()
},
importAppliance(){
this.importAppliances()
},
},
watch: {
ownerId: {
immediate: true,
handler: 'load'
}
},
}
</script>
Okay, so the error occurs in this specific property:
{
key: 'activeAppliance.warrantyDuration',
label: this.$t('warrantyDuration'),
sortable: true,
formatter: (warrantyDuration, applianceId, appliance) =>
this.$n(warrantyDuration) + ' ' +
this.$t(appliance.activeAppliance.warrantyDurationType ?
`model.appliance.warrantyDurationTypes.${appliance.activeAppliance.warrantyDurationType}` :
''
).toLocaleLowerCase(this.$i18n.locale),
sortByFormatted: (warrantyDuration, applianceId, appliance) =>
appliance.activeAppliance.warrantyDurationType === 'YEARS' ? warrantyDuration * 12 : warrantyDuration
},
What I am basically doing here is combining two values from the object: warrantyDuration and warrantyDurationType and putting them in one single row in my bootstrap table.
The problem is that this is giving me an error: Cannot read properties of undefined (reading 'warrantyDurationType'
Yet the data actually outputs normally.
So what exactly does it want me to do?
I tried wrapping a v-if around the table to make sure that the application checks if the data exist before outputting it, but this does not solve the issue.
<div v-if="applianceReferences && applianceReferences.activeAppliance">
<b-card v-if="showTable" class="ml-4 mr-4">
<common-table
search-placeholder="search"
:filter-included-fields="fields.map(f => f.key)"
include-filter
:items="applianceReferences"
:fields="fields"
/>
</b-card>
</div>
Last, just to give you a full overview, my array looks like this:
Any ideas?
What I'm trying to do?
Use a Handler that allow me insert an image by URL, the reason for this is to not use too much space in the Database.
What version of Vue I'm using?
Vue 2
What is not working?
When I add the handler, quill toolbar doesn't identify my custom toolbar, and it adds all the options, the console is throwing me the next error: "[Vue warn]: Error in data(): "ReferenceError: showImageUI is not defined".
Also "this.quill.insertEmbed()" is not working, the console threw me this: "Uncaught ReferenceError: Quill is not defined" (this pass when I change the Handler Image value, I'll let the second option at the final)
<template>
<div class="addBlog">
<h1>Add New Blog</h1>
<quill-editor v-model="content" :options="editorOptions" ref="myQuillEditor"/>
</div>
</template>
<script>
import 'quill/dist/quill.snow.css';
import { Quill, quillEditor } from 'vue-quill-editor';
export default {
name: 'AddBlog',
components: {
quillEditor
},
data: () => ({
title: '',
category: '',
content: '',
editorOptions: {
theme: 'snow',
debug: 'info',
placeholder: 'Type your post...',
readOnly: true,
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
['link', 'image', 'video']
],
handlers: { image: showImageUI }
}
}
},
// debug: 'info',
// placeholder: 'Type your post...',
// readOnly: true,
// theme: 'snow'
// },
delta: undefined
}),
methods: {
showImageUI() {
var range = this.quill.getSelection();
var value = prompt('please copy paste the image url here.');
if(value){
this.quill.insertEmbed(range.index, 'image', value, Quill.sources.USER);
}
}
},
watch: {
content() {
this.delta = this.$refs.myQuillEditor.quill.getContents();
}
}
};
</script>
And here I let you the code(the second option) where I used directly the function into the handler:
editorOptions: {
theme: 'snow',
debug: 'info',
placeholder: 'Type your post...',
readOnly: true,
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
['link', 'image', 'video']
],
handlers: { image: function imageHandler() {
var range = this.quill.getSelection();
var value = prompt('please copy paste the image url here.');
if(value){
this.quill.insertEmbed(range.index, 'image', value, Quill.sources.USER);
}} }
}
}
},
I am very new to Quasar, I want to display Quasar tree nodes from a Local JSON file and with on click of a particular node item I want to show some text.
As of now I am using Quasar tree like this.
<template>
<q-page class="flex fixed-left">
<q-tree
:nodes="simple"
node-key="label"
no-connectors
:expanded.sync="expanded"
text-color="blue"
></q-tree>
</q-page>
</template>
<style>
</style>
<script>
export default {
name: 'HelloWorld',
data () {
return {
expanded: [ 'Resources' ],
simple: [
{
label: 'Resources',
children: [
{
label: 'Projects',
children: [
{
label: 'Data sets' ,
children: [
{
label: 'Items',
}
]
},
{ label: 'Good recipe' }
]
},
{
label: 'Good service (disabled node with icon)',
icon: 'room_service',
disabled: true,
children: [
{ label: 'Prompt attention' },
{ label: 'Professional waiter' }
]
},
{
label: 'Pleasant surroundings (with icon)',
icon: 'photo',
children: [
{
label: 'Happy atmosphere (with image)',
img: 'https://cdn.quasar.dev/img/logo_calendar_128px.png'
},
{ label: 'Good table presentation' },
{ label: 'Pleasing decor' }
]
}
]
}
]
}
}
}
</script>
It was coming like this
Now I wanted to get these nodes from a local JSON file and on click on Items should display some text .
Please help me with this.
To import JSON in ECMAScript:
If you don't have a lot of JSON files and you have the permission to modify and convert them into JS files, you can follow this answer: https://stackoverflow.com/a/39855320/3241933
Then you should import the vanilla JS object into data().
Example solution:
<template>
<q-page class="flex fixed-left">
<q-tree
:nodes="simple"
node-key="label"
no-connectors
:expanded.sync="expanded"
text-color="blue"
></q-tree>
</q-page>
</template>
<style>
</style>
<script>
import jsonData from './data.js'
export default {
name: 'HelloWorld',
data () {
return {
expanded: [ 'Resources' ],
simple: jsonData
}
}
}
</script>
Make sure that your import is an array of object.
I don't have any problem in localizing the components and views strings but I am lock into finding a way to localize dynamically the Toolbar items ( and of course the same items in the navigation drawer..
Currently they are displayed in App.vue as menuItems[i].title
<v-toolbar-items class="hidden-xs-only">
<v-btn flat :to="menuItems[0].link">
<v-icon left>{{ menuItems[0].icon }}</v-icon>
<span>{{ menuItems[0].title }}</span>
</v-btn>
with the script:
<script>
export default {
data () {
return {
appName: 'myAPP',
sideNav: false,
menuItems: [
{ icon: 'home', title: 'Home', link: '/home' },
{ icon: 'info', title: 'About', menu: [{ title: 'Company', link: '/company' }, { title: 'Office', link: '/office' }] },
{ icon: 'people', title: 'Members', menu: [], link: '/members' },
{ icon: 'local_library', title: 'Blog', link: '/blog' },
{ icon: 'local_grocery_store', title: 'Shopping', link: '/shopping' }
]
}
},
methods: {
switchLocale: function (newLocale) {
this.$store.dispatch('switchI18n', newLocale)
}
}
}
</script>
Should I use a computed value ? or use directly $t() in the template ?
feedback, advices and links appreciated
UPDATE
main.js
Vue.filter('translate', function (value) {
if (!value) return ''
value = 'lang.views.global.' + value.toString()
return i18n.t(value)
})
locales/i18n/en_US
{
"views": {
"global": {
"Home": "Home",
"Section1": "Section 1",
..
Vue provides filter to help us to format the common text.
So I think it will be one of your choices.
You can click above link to follow the guide to set up your filters.
Edit:
I just realized Vue-filters should not be dependent on this context as the Vue author said. So updated my answer as below:
Then the codes will be like below:
// create vue-i18n instance
const i18n = new VueI18n({
locale: getDefaultLanguage(),
messages: langs
})
// create global filter
Vue.filter('myLocale', function (value) {
return i18n.t(value)
})
In your views or components:
<template>
<v-toolbar-items class="hidden-xs-only">
<v-btn flat :to="menuItems[0].link">
<v-icon left>{{ menuItems[0].icon }}</v-icon>
<span>{{ menuItems[0].title | myLocale }}</span>
</v-btn>
</template>
<script>
export default {
data () {
return {
appName: 'myAPP',
sideNav: false,
menuItems: [
{ icon: 'home', title: 'Home', link: '/home' },
{ icon: 'info', title: 'About', menu: [{ title: 'Company', link: '/company' }, { title: 'Office', link: '/office' }] },
{ icon: 'people', title: 'Members', menu: [], link: '/members' },
{ icon: 'local_library', title: 'Blog', link: '/blog' },
{ icon: 'local_grocery_store', title: 'Shopping', link: '/shopping' }
]
}
},
filters: {
myLocaleWhichNotWork: function (value) {
return this.$t(value) // this won't work because filters should not be dependent on this context
}
}
}
</script>
I'm having troubles triggering a separate Vue instance method by name for each element in a v-for loop on click.
Each action corresponds to a method, but it's not triggered. What am I doing wrong?
Code:
<v-btn v-for="btn in windowControlButtons" :key="btn.id"
#click="btn.action"
>
<v-icon size="20px">{{btn.icon}}</v-icon>
</v-btn>
...
window: remote.getCurrentWindow(),
windowControlButtons: [
{
icon: 'remove',
action: minimizeWindow()
},
{
icon: 'crop_square',
action: maximizeWindow()
},
{
icon: 'close',
action: closeWindow()
}
]
...
methods: {
minimizeWindow() {
this.window.minimize()
},
maximizeWindow() {
this.window.maximize()
},
closeWindow() {
this.window.close()
}
}
UPDATE
I can trigger some code directly in the data(), e.g.:
...
{
icon: 'remove',
action: () => {remote.getCurrentWindow().minimize()}
},
But what if a method wasn't as short?
How do I trigger a method already specified in methods: { }?
btn.action is a string, thus you can't execute it.
Every Vue instance/component method is accessible as a property in the vm.$options.methods object.
I suggest creating another method, say handleClick, to simplify your method calling depending on the button, and invoke the best suitable method from this.$options.methods as shown below.
new Vue({
el: '#app',
data: {
windowControlButtons: [
{id: 1, icon: 'remove', action: 'minimizeWindow'},
{id: 2, icon: 'crop_square', action: 'maximizeWindow'},
{id: 3, icon: 'close', action: 'closeWindow'}
]
},
methods: {
handleClick(button) {
if (this.$options.methods[button.action]) { // guard to prevent runtime errors
this.$options.methods[button.action]();
}
},
minimizeWindow() {
console.log('minimizeWindow');
},
maximizeWindow() {
console.log('maximizeWindow');
},
closeWindow() {
console.log('closeWindow');
}
}
})
<script src="https://unpkg.com/vue#2.5.15/dist/vue.min.js"></script>
<div id="app">
<button v-for="btn in windowControlButtons" :key="btn.id" #click="handleClick(btn)">
<span>{{btn.icon}}</span>
</button>
</div>