i am new to angular2/primeng.
How to show the primeng context menu on left click instead of the default right click inside a datatable?
thanks
Since version 6.1.4 of PrimeNG it can be done with triggerEvent property.
On the template:
<img #targetImage2 src="assets/img/vejo_trabalhos_bonitos.jpg" alt="Test image">
<p-contextMenu [target]="targetImage2" [model]="contextMenuItems" [appendTo]="'body'" triggerEvent="click"></p-contextMenu>
On the component:
contextMenuItems: MenuItem[];
constructor(private messageService: MessageService) { }
ngOnInit(): void {
this.contextMenuItems = [
{ label: 'Edit', icon: 'pi pi-fw pi-pencil', command: event => this.displayMessage(event.item.label) },
{ label: 'Export', icon: 'pi pi-fw pi-external-link', command: event => this.displayMessage(event.item.label) },
{ label: 'Delete', icon: 'pi pi-fw pi-trash', command: event => this.displayMessage(event.item.label) }
];
}
displayMessage(action: string): void {
this.messageService.add({severity: 'info', summary: `"${action}" action clicked!`});
}
But if one wants to display the context menu on both left and right mouse button events. It can be done too.
On the template:
<img #targetImage src="assets/img/vejo_trabalhos_bonitos.jpg" alt="Test image" (click)="onLeftMouseClick($event,contextMenu)">
<p-contextMenu #contextMenu [target]="targetImage" [model]="contextMenuItems" [appendTo]="'body'"></p-contextMenu>
On the component:
contextMenuItems: MenuItem[];
constructor(private messageService: MessageService) { }
ngOnInit(): void {
this.contextMenuItems = [
{ label: 'Edit', icon: 'pi pi-fw pi-pencil', command: event => this.displayMessage(event.item.label) },
{ label: 'Export', icon: 'pi pi-fw pi-external-link', command: event => this.displayMessage(event.item.label) },
{ label: 'Delete', icon: 'pi pi-fw pi-trash', command: event => this.displayMessage(event.item.label) }
];
}
displayMessage(action: string): void {
this.messageService.add({severity: 'info', summary: `"${action}" action clicked!`});
}
onLeftMouseClick(event: MouseEvent, contextMenu: ContextMenu): void {
event.stopPropagation();
event.preventDefault();
contextMenu.show(event);
}
You might want to reconsider why you would want to change the default like that. Right clicking is pretty much the universal way that people expect Context Menus to work. As Pardeep said, other than rooting around in the code, you wouldn't be able to change that.
Related
I'm using the VueFormulate library to generate forms from a JSON schema. Doing this I would like the ability to add any event listeners I need without having to update my generic component so I'm attempting to pass the event up using v-on="$listeners". The trouble is that I need to do some processing before passing the form object back to the client so I need to have some events specified.
For example, below when clicking the button that emits the 'save' event, the parent component ends up receiving the 'save' event but also a 'click' event. Both of which trigger the 'save' event listeners. If I remove v-on="$listeners" then the defined events work, however those specified only in the schema no longer get passed through.
// Dynamic-form.vue
<template>
<div>
{{ $listeners }}
<FormulateForm
:name="name"
v-model="theForm"
:schema="filteredFormSchema"
#submit="handleSubmit"
#save="handleSave"
v-on="$listeners"
>
</FormulateForm>
</div>
</template>
<script>
import "./vue-formulate-config"
import { cloneDeep } from "lodash";
export default {
name: "DynamicForm",
props: {
formSchema: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
name: {
type: String,
default: 'theForm'
},
hideOptionalFields: {
type: Boolean,
default: false
}
},
data() {
return {
theForm: {},
schema: [],
};
},
methods: {
handleSave: function() {
this.$emit("save", this.generateFormData(this.theForm))
},
handleSubmit: function (formValues) {
this.$emit("submit", this.generateFormData(formValues));
},
},
};
</script>
Below is the snippet using the component above. You can see I'm listening for some events that are not emitted directly from that component. Those are specified in the schema json and are passed through.
// some-form.vue
<DynamicForm
class="nested-alt p-10 rounded"
name="some-form"
:formSchema="k209Schema"
:formData="form"
#submit="handleSubmit"
#save="saveAsDraft($event)"
#showPreview="handleShowPreview"
#cancel="handleCancelClick"
></DynamicForm>
[
{
name: 'preview',
type: 'button',
label: 'Preview',
"input-class": 'btn btn-outline-dark btn-sm',
'#click': 'showPreview'
},
{
name: 'cancel',
type: 'button',
label: 'Cancel',
"input-class": 'btn btn-outline-dark btn-sm',
'#click': 'cancel'
},
{
name: 'save',
type: 'button',
label: 'Save as Draft',
"input-class": 'btn btn-outline-dark btn-sm',
'#click': 'save'
},
{
name: 'submit',
type: 'submit',
label: 'Send',
"input-class": 'btn btn-info btn-sm'
}
]
When doing this you have to be careful with the event names chosen. In this case the event name in the schema is the same event name being emitted from the handleSave() method. So what's happening is the 'save' event from VueFormulate is caught in dynamic-form.vue where #save catches it and calls that method. Additionally, the v-on="$listeners" is taking that same re-named click event (i.e. the 'save' click event) and passing it through. Now you have a save event containing the click payload as well as a save event contining your form payload from the handleSave() method.
The fix: change the 'save' event name in one of the places. I ended up changine the schema click to be more explicit that it's a click and named it save-click.
// some-form.vue
<DynamicForm
class="nested-alt p-10 rounded"
name="some-form"
:formSchema="k209Schema"
:formData="form"
#submit="handleSubmit"
#save-click="saveAsDraft($event)"
#showPreview="handleShowPreview"
#cancel="handleCancelClick"
></DynamicForm>
[
{
name: 'preview',
type: 'button',
label: 'Preview',
"input-class": 'btn btn-outline-dark btn-sm',
'#click': 'showPreview'
},
{
name: 'cancel',
type: 'button',
label: 'Cancel',
"input-class": 'btn btn-outline-dark btn-sm',
'#click': 'cancel-click'
},
{
name: 'save',
type: 'button',
label: 'Save as Draft',
"input-class": 'btn btn-outline-dark btn-sm',
'#click': 'save-click'
},
{
name: 'submit',
type: 'submit',
label: 'Send',
"input-class": 'btn btn-info btn-sm'
}
]
I am using SideMenuBar from https://www.npmjs.com/package/vue-sidebar-menu to generate a side menu for my app. The elements in the bar should be dynamic based on whether the person is logged-in. The problem I have is that when I login, the items arent reactive - I need to refresh my browser for the menu to refresh. Any idea what I am doing wrong?
<div id="app">
<sidebar-menu :menu="dynamicMenu" #toggle-collapse="onToggleCollapse" #item-click="onItemClick" :collapsed="collapseMenu" >
</sidebar-menu>
<router-view />
computed: {
isAuthorized: function() {
return UserStorageService.GetUser() === null ? false : true;
},
dynamicMenu() {
return [
{
header: true,
title: "Menu",
hiddenOnCollapse: true
},
{
href: { path: "/" },
title: "Home",
icon: "fas fa-home"
},
{
href: { path: "/Dashboard" },
title: "Dashboard",
icon: "fas fa-folder",
hidden: !this.isAuthorized
},
{
href: { path: "/" },
title: "Reporting",
icon: "fas fa-archive",
hidden: !this.isAuthorized
},
{
href: { path: "/" },
title: "My profile",
icon: "fas fa-share-alt",
hidden: !this.isAuthorized
}
]
}
},
When I sign-in, the value of "isAuthorized" should change to true. That value should then be assigned to my dynamic menu (the inverse) and should toggle the menu option hidden/not-hidden.
I have set up navigation with Bottom tabs in react-native-navigation, this is working fine
bottomTabs: {
id: 'BOTTOM_TABS_LAYOUT',
children: [
{
stack: {
id: 'HOME_TAB',
children: [
{
component: {
id: 'HOME_SCREEN'
name: 'HomeScreen'
}
}
],
options: {
bottomTab: {
icon: require('./home.png')
}
}
}
},
{
stack: {
id: 'PROFILE_TAB',
children: [
{
component: {
id: 'PROFILE_SCREEN',
name: 'ProfileScreen'
}
}
],
options: {
bottomTab: {
icon: require('./profile.png')
}
}
}
}
]
}
But I want to add some other code when I switch from a tab to another, how could this be done?
You can listen to tab selection events by registering a Navigation events listener. The tabSelected event is emitted when the selected tab has changed.
Navigation.events().registerBottomTabSelectedListener((selectedTabIndex, unselectedTabIndex) => {
});
If you'd like to handle the tab selection yourself, set the selectTabOnPress: false option on the bottomTab you'd like to handle selection for, and register a tabPressed listener to handle the tab press event. This event is emitted when a tab is pressed by the user.
options: {
bottomTab: {
icon: require('./home.png'),
selectTabOnPress: false
}
}
Navigation.events().registerBottomPressedListener((tabIndex) => {
});
I am trying to add a submenu from a javascriot file.
Default menu works perfectly, but I don't know if it is possible to assign a submenu using that same structure.
export const getTabsMdl = () => {
let r = null
r = [
{ name: 'Saldo', icon: 'receipt', to: '/saldo' },
{ name: 'Vendas', icon: 'receipt', to: '/vendas' },
{ name: 'Account', icon: 'assignment', to: '/conta' },
{ name: 'Clients', icon: 'supervisor_account', to: '/clientes' },
{ name: 'More', [{ name: 'Sub-Item', icon: 'autorenew', to: '/sub-01' }] }
return r
}
<q-route-tab
v-for="(bTab, bTIndex) in getTabsMdl()"
:to="bTab.to"
:label="bTab.name"
:name="bTab.name"
:icon="bTab.icon"
:key="bTIndex"
no-caps
/>
In Quasar, you can define hierarchy of menus.
Please check this one.
https://github.com/quasarframework/quasar/blob/dev/docs/src/examples/QMenu/MenuInMenu.vue
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>