Look I know this is a mild repost of this post but its a bit outdated and I have diffrent packages to worry about aswell as diffrent formatting in my file and file system
I am new to electron so I am sorry if this is a really stupid question
What would be the current best practice for importing Menu() from ./Core/components/Menubar.js
Menubar.js
const { app, Menu } = require('electron')
const isMac = process.platform === 'darwin'
const template = [
// { role: 'appMenu' }
...(isMac ? [{
label: app.name,
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services' },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
}] : []),
// { role: 'fileMenu' }
{
label: 'File',
submenu: [
isMac ? { role: 'close' } : { role: 'quit' }
]
},
// { role: 'editMenu' }
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
...(isMac ? [
{ role: 'pasteAndMatchStyle' },
{ role: 'delete' },
{ role: 'selectAll' },
{ type: 'separator' },
{
label: 'Speech',
submenu: [
{ role: 'startSpeaking' },
{ role: 'stopSpeaking' }
]
}
] : [
{ role: 'delete' },
{ type: 'separator' },
{ role: 'selectAll' }
])
]
},
// { role: 'viewMenu' }
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forceReload' },
{ role: 'toggleDevTools' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
// { role: 'windowMenu' }
{
label: 'Window',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
...(isMac ? [
{ type: 'separator' },
{ role: 'front' },
{ type: 'separator' },
{ role: 'window' }
] : [
{ role: 'close' }
])
]
},
{
role: 'help',
submenu: [
{
label: 'Learn More',
click: async () => {
const { shell } = require('electron')
await shell.openExternal('https://electronjs.org')
}
}
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
// Export the publicly available function
Main.js
const { app, BrowserWindow, ipcMain, nativeImage, NativeImage, nativeTheme, dialog, Menu } = require('electron')
const path = require('path')
//Start the node file system
const fs = require('fs')
const https = require('https')
const appMenu = require('menu');
//Chart JS testing and config
const Chart = require('chart.js');
const MenuConfig = require("./Core/components/Menubar.js")
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
win.loadFile('index.html')
dialog.showOpenDialogSync ([BrowserWindow,])
//Dark theme config
ipcMain.handle('dark-mode:toggle', () => {
if (nativeTheme.shouldUseDarkColors) {
nativeTheme.themeSource = 'light'
} else {
nativeTheme.themeSource = 'dark'
}
return nativeTheme.shouldUseDarkColors
})
ipcMain.handle('dark-mode:system', () => {
nativeTheme.themeSource = 'system'
})
}
const iconName = path.join(__dirname, 'iconForDragAndDrop.png');
const icon = fs.createWriteStream(iconName);
// Create a new file to copy - you can also copy existing files.
fs.writeFileSync(path.join(__dirname, 'drag-and-drop-1.md'), '# First file to test drag and drop')
fs.writeFileSync(path.join(__dirname, 'drag-and-drop-2.md'), '# Second file to test drag and drop')
https.get('https://img.icons8.com/ios/452/drag-and-drop.png', (response) => {
response.pipe(icon);
});
ipcMain.on('ondragstart', (event, filePath) => {
event.sender.startDrag({
file: path.join(__dirname, filePath),
icon: iconName,
})
})
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
I tried to use require() and build() but I can't get the syntax right for this context
For anyone else that comes across this here is how I fixed it assuming template is configured properly.
In Menubar.js
module.exports = Menu.buildFromTemplate(template); On the last line if you set up your template
In main.js
At the top of the file after requiring electron
const applicationMenu = require('./Menubar');
On the line where you are calling app.whenReady
app.whenReady().then(() => {
Menu.setApplicationMenu(applicationMenu);
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
👍
Related
I am learning electron. So I want to open Inspect Element to debug my app.
I already have menu.js.
// #flow
import { app, Menu, shell, BrowserWindow, dialog } from 'electron';
export default class MenuBuilder {
mainWindow: BrowserWindow;
constructor(mainWindow: BrowserWindow) {
this.mainWindow = mainWindow;
}
buildMenu() {
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
this.setupDevelopmentEnvironment();
}
const template =
process.platform === 'darwin'
? this.buildDarwinTemplate()
: this.buildDefaultTemplate();
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
return menu;
}
setupDevelopmentEnvironment() {
this.mainWindow.openDevTools();
this.mainWindow.webContents.on('context-menu', (e, props) => {
const { x, y } = props;
Menu.buildFromTemplate([
{
label: 'Inspect element',
click: () => {
this.mainWindow.inspectElement(x, y);
}
}
]).popup(this.mainWindow);
});
}
buildDarwinTemplate() {
const subMenuAbout = {
label: 'Electron',
submenu: [
{
label: 'Quit',
accelerator: 'Command+Q',
click: () => {
app.quit();
}
}
]
};
const subMenuEdit = {
label: 'Edit',
submenu: [
{ label: 'Undo', accelerator: 'Command+Z', selector: 'undo:' },
{ label: 'Redo', accelerator: 'Shift+Command+Z', selector: 'redo:' },
{ type: 'separator' },
{ label: 'Cut', accelerator: 'Command+X', selector: 'cut:' },
{ label: 'Copy', accelerator: 'Command+C', selector: 'copy:' },
{ label: 'Paste', accelerator: 'Command+V', selector: 'paste:' },
{
label: 'Select All',
accelerator: 'Command+A',
selector: 'selectAll:'
}
]
};
const subMenuViewDev = {
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'Command+R',
click: () => {
this.mainWindow.webContents.reload();
}
},
{
label: 'Toggle Full Screen',
accelerator: 'Ctrl+Command+F',
click: () => {
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
}
},
{
label: 'Toggle Developer Tools',
accelerator: 'Alt+Command+I',
click: () => {
this.mainWindow.toggleDevTools();
}
}
]
};
const subMenuViewProd = {
label: 'View',
submenu: [
{
label: 'Toggle Full Screen',
accelerator: 'Ctrl+Command+F',
click: () => {
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
}
}
]
};
const subMenuWindow = {
label: 'Window',
submenu: [
{
label: 'Minimize',
accelerator: 'Command+M',
selector: 'performMiniaturize:'
},
{ label: 'Close', accelerator: 'Command+W', selector: 'performClose:' },
{ type: 'separator' },
{ label: 'Bring All to Front', selector: 'arrangeInFront:' }
]
};
const subMenuView =
process.env.NODE_ENV === 'development' ? subMenuViewDev : subMenuViewProd;
return [subMenuAbout, subMenuEdit, subMenuView, subMenuWindow];
}
buildDefaultTemplate() {
const templateDefault = [
{
label: '&File',
submenu: [
{
label: '&Open',
accelerator: 'Ctrl+O',
click: () => {
dialog
.showOpenDialog({ properties: ['openFile', 'multiSelections'] })
.then(response => {
if (!response.canceled) {
// handle fully qualified file name
return response.filePaths[0];
}
return false;
})
.catch(error => console.log(error));
}
},
{
label: '&Close',
accelerator: 'Ctrl+W',
click: () => {
this.mainWindow.close();
}
}
]
},
{
label: '&View',
submenu:
process.env.NODE_ENV === 'development'
? [
{
label: '&Reload',
accelerator: 'Ctrl+R',
click: () => {
this.mainWindow.webContents.reload();
}
},
{
label: 'Toggle &Full Screenn',
accelerator: 'F11',
click: () => {
this.mainWindow.setFullScreen(
!this.mainWindow.isFullScreen()
);
}
},
{
label: 'Toggle &Developer Tools',
accelerator: 'Alt+Ctrl+I',
click: () => {
this.mainWindow.toggleDevTools();
}
}
]
: [
{
label: 'Toggle &Full Screen',
accelerator: 'F11',
click: () => {
this.mainWindow.setFullScreen(
!this.mainWindow.isFullScreen()
);
}
}
]
}
];
return templateDefault;
}
}
After running npm run dev, If I right-click on app window, then I am able to see Inspect element option but nothing is happening If I click on it.
Note :
I am using Kubuntu 22.04
Edit 1:
If I press SHIFT+CTRL+C then I am getting this error :
Edit 2:
I am working on a git repo which will be used for editing image. But currently there are some issues in the code. So I want to debug it through Inspect Element.
You can also clone the repo and run :
npm install
npm run dev
I am currently making a reports page and currently struggling how to render the dataset to my BarChart. I have no problems showing static data to the chart but when I use axios it does not work. I read solutions about using watchers and mounted. But I am confused how to apply it if my BarChart is in another component.
This is my BarChart Code:
import { Bar } from "vue-chartjs";
export default {
name: "BarChart",
extends: Bar,
data() {
return {};
},
props: {
label: {
type: Array,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
},
mounted() {
const dates = this.chartData.map((d) => d.date);
const totalCheckIn = this.chartData.map((d) => d.totalCheckIn);
const totalCheckOut = this.chartData.map((d) => d.totalCheckout);
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label[0],
data: totalCheckIn,
},
{
label: this.label[1],
data: totalCheckOut,
},
],
},
this.options
);
},
};
In my reports component this is how I used it:
<BarChart
v-bind:chartData="checkIn"
v-bind:options="checkInOptions"
v-bind:label="checkInLabel"
></BarChart>
import BarChart from "../components/BarChart";
export default {
name: "Reports",
components: { BarChart },
data() {
return {
checkInOptions: {
responsive: true,
maintainAspectRatio: false,
},
checkIn: [
{ date: "1", totalCheckIn: "2", totalCheckout: "2" },
{ date: "2", totalCheckIn: "1", totalCheckout: "2" },
],
checkInLabel: ["Check In", "CheckOut"],
}
},
beforeMount() {
axios
.get('http://localhost:3000/monthly-checkin/'+this.month+'/'+this.year+'')
.then((res) => {
this.checkIn = res.data.monthly;
console.log(this.checkIn)
})
.catch((err) => {
console.log(err.response.data.message);
});
}
}
Please help
Use watch inside your BarChart component as below:
watch:{
chartData:function(newVal,OldVal){
//assign chart data
},
},
Afterwards you need to execute the method where your bar chart data could be updated. Below will be the full snippet.
import { Bar } from "vue-chartjs";
export default {
name: "BarChart",
extends: Bar,
data() {
return {};
},
props: {
label: {
type: Array,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
},
watch: {
chartData: function (newVal, OldVal) {
this.updateChart()
},
},
mounted() {
this.updateChart()
},
methods: {
updateChart() {
const dates = this.chartData.map((d) => d.date);
const totalCheckIn = this.chartData.map((d) => d.totalCheckIn);
const totalCheckOut = this.chartData.map((d) => d.totalCheckout);
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label[0],
data: totalCheckIn,
},
{
label: this.label[1],
data: totalCheckOut,
},
],
},
this.options
);
}
}
};
I'm new to Angular, I have a table that I need to display with two languages based on the user's choice, I have searched a lot for this however, couldn't find anything useful for my case, I have made a work around that doesn't really fulfill my needs as when I go to another page and then back to this page it displays the data with the wrong choice as the variable inside the localstorage returns with undefined. Please advise if you have a better approach as I totally understand that mine is really bad. Thanks in advance.
employee.component.ts
ngOnInit() {
this.switchLanguage = localStorage.getItem('selectedLanguage');
this.lang = localStorage.getItem('lang')
this.getActiveEmployees();
}
getAllEmployees(){
if(this.switchLanguage === "en" || this.browserLang === "en"){
console.log(this.switchLanguage + " Da5al hena lee 1")
this.settings = {
totalKey: 'total',
pager: {
display: true,
perPage: '5'
},
mode: 'external',
actions: false,
columns: {
firstName_FL: {
title: 'First Name',
data: this.employees.firstName_FL,
},
secondName_FL: {
title: 'Second Name',
data: this.employees.secondName_FL,
},
lastName_FL: {
title: 'Last Name',
data: this.employees.lastName_FL,
},
hiringDate: {
title: 'Hiring Date',
data: this.employees.hiringDate,
type: 'date',
filter: {
type: 'daterange'
},
valuePrepareFunction: (lastLoginTime: any) => {
return lastLoginTime.slice(0, 10)
}
},
firstContractingSalary: {
title: 'First Contracting Salary',
valuePrepareFunction: (firstContractingSalary) => {
this.formatedOutputValue = this.currenctPipe.transform(firstContractingSalary, 'EGP ',
'symbol', '1.2-2');
return this.formatedOutputValue
}
},
position: {
title: 'Position',
valuePrepareFunction: (position) => {
return position.name_FL;
},
sort: true
},
department: {
title: 'Department',
valuePrepareFunction: (department) => {
return department.name_FL;
}
},
employeeJobStatuses: {
title: 'Status',
filter: false,
sort: false,
valuePrepareFunction: (employeeJobStatuses) => {
this.statusValidation = employeeJobStatuses.map((element, i) => [
element.status
])
for(var i = 0; i < this.statusValidation.length; i++){
if(this.statusValidation[i][i] === "STATUS_ACTIVE"){
return "Active"
} else if(this.statusValidation[i][i] === "STATUS_SUSPENDED"){
return "Suspended"
} else if(this.statusValidation[i][i] === "STATUS_TERMINATED"){
return "Terminated"
} else if(this.statusValidation[i][i] === "STATUS_INACTIVE"){
return "Inactive"
}
}
}
}
}
};
} else if(this.switchLanguage === "ar" || this.browserLang === "ar"){
this.settings = {
totalKey: 'total',
pager: {
display: true,
perPage: '5'
},
mode: 'external',
actions: false,
columns: {
firstName_SL: {
title: 'الاسم الاول',
data: this.employees.firstName_SL,
},
secondName_SL: {
title: 'الاسم الاوسط',
data: this.employees.secondName_SL,
},
lastName_SL: {
title: 'الاسم الاخير',
data: this.employees.lastName_SL,
},
hiringDate: {
title: 'تاريخ التوظيف',
data: this.employees.hiringDate,
type: 'date',
filter: {
type: 'daterange'
},
valuePrepareFunction: (lastLoginTime: any) => {
return lastLoginTime.slice(0, 10)
}
},
firstContractingSalary: {
title: 'قيمة التعاقد المبدأية',
valuePrepareFunction: (firstContractingSalary) => {
this.formatedOutputValue = this.currenctPipe.transform(firstContractingSalary, 'EGP ', 'symbol', '1.2-2');
return this.formatedOutputValue
}
},
position: {
title: 'المركز',
valuePrepareFunction: (position) => {
return position.name_SL;
},
sort: true
},
department: {
title: 'القسم',
valuePrepareFunction: (department) => {
return department.name_SL;
}
},
employeeJobStatuses: {
title: 'الحالة',
filter: false,
sort: false,
valuePrepareFunction: (employeeJobStatuses) => {
this.statusValidation = employeeJobStatuses.map((element, i) => [
element.status
])
for(var i = 0; i < this.statusValidation.length; i++){
if(this.statusValidation[i][i] === "STATUS_ACTIVE"){
return "نشيط"
} else if(this.statusValidation[i][i] === "STATUS_SUSPENDED"){
return "معلق"
} else if(this.statusValidation[i][i] === "STATUS_TERMINATED"){
return "منتهي"
} else if(this.statusValidation[i][i] === "STATUS_INACTIVE"){
return "غير نشط"
}
}
}
}
}
};
}
this.translate.onLangChange.subscribe(language => {
this.browserLang = language.lang;
if(this.browserLang === "en"){
this.settings = {
totalKey: 'total',
pager: {
display: true,
perPage: '5'
},
mode: 'external',
actions: false,
columns: {
firstName_FL: {
title: 'First Name',
data: this.employees.firstName_FL,
},
secondName_FL: {
title: 'Second Name',
data: this.employees.secondName_FL,
},
lastName_FL: {
title: 'Last Name',
data: this.employees.lastName_FL,
},
hiringDate: {
title: 'Hiring Date',
data: this.employees.hiringDate,
type: 'date',
filter: {
type: 'daterange'
},
valuePrepareFunction: (lastLoginTime: any) => {
return lastLoginTime.slice(0, 10)
}
},
firstContractingSalary: {
title: 'First Contracting Salary',
valuePrepareFunction: (firstContractingSalary) => {
this.formatedOutputValue = this.currenctPipe.transform(firstContractingSalary, 'EGP ', 'symbol', '1.2-2');
return this.formatedOutputValue
}
},
position: {
title: 'Position',
valuePrepareFunction: (position) => {
return position.name_FL;
},
sort: true
},
department: {
title: 'Department',
valuePrepareFunction: (department) => {
return department.name_FL;
}
},
employeeJobStatuses: {
title: 'Status',
filter: false,
sort: false,
valuePrepareFunction: (employeeJobStatuses) => {
this.statusValidation = employeeJobStatuses.map((element, i) => [
element.status
])
for(var i = 0; i < this.statusValidation.length; i++){
if(this.statusValidation[i][i] === "STATUS_ACTIVE"){
return "Active"
} else if(this.statusValidation[i][i] === "STATUS_SUSPENDED"){
return "Suspended"
} else if(this.statusValidation[i][i] === "STATUS_TERMINATED"){
return "Terminated"
} else if(this.statusValidation[i][i] === "STATUS_INACTIVE"){
return "Inactive"
}
}
}
}
}
};
} else if(this.browserLang === "ar"){
this.settings = {
totalKey: 'total',
pager: {
display: true,
perPage: '5'
},
mode: 'external',
actions: false,
columns: {
firstName_SL: {
title: 'الاسم الاول',
data: this.employees.firstName_SL,
},
secondName_FL: {
title: 'الاسم الاوسط',
data: this.employees.secondName_SL,
},
lastName_FL: {
title: 'الاسم الاخير',
data: this.employees.lastName_SL,
},
hiringDate: {
title: 'تاريخ التوظيف',
data: this.employees.hiringDate,
type: 'date',
filter: {
type: 'daterange'
},
valuePrepareFunction: (lastLoginTime: any) => {
return lastLoginTime.slice(0, 10)
}
},
firstContractingSalary: {
title: 'قيمة التعاقد المبدأية',
valuePrepareFunction: (firstContractingSalary) => {
this.formatedOutputValue = this.currenctPipe.transform(firstContractingSalary, 'EGP ', 'symbol', '1.2-2');
return this.formatedOutputValue
}
},
position: {
title: 'المركز',
valuePrepareFunction: (position) => {
return position.name_SL;
},
sort: true
},
department: {
title: 'القسم',
valuePrepareFunction: (department) => {
return department.name_SL;
}
},
employeeJobStatuses: {
title: 'الحالة',
filter: false,
sort: false,
valuePrepareFunction: (employeeJobStatuses) => {
this.statusValidation = employeeJobStatuses.map((element, i) => [
element.status
])
for(var i = 0; i < this.statusValidation.length; i++){
if(this.statusValidation[i][i] === "STATUS_ACTIVE"){
return "نشيط"
} else if(this.statusValidation[i][i] === "STATUS_SUSPENDED"){
return "معلق"
} else if(this.statusValidation[i][i] === "STATUS_TERMINATED"){
return "منتهي"
} else if(this.statusValidation[i][i] === "STATUS_INACTIVE"){
return "غير نشط"
}
}
}
}
}
};
}
})
this.loading = true;
this.restService.GetAllEmployees().subscribe((res: any) => {
this.loading = false;
this.employees = res.data.employees;
const maw = JSON.stringify(this.employees)
this.jsonObj = JSON.parse(maw);
})
}
dont forget to inject TranslateService in ur constrctor ,and add id , name resources in ar.josn , and en.json ,try this
columnheaders:any;
ngOnInit(){
this.columnheaders = []
this.translate.get('the id').subscribe(label =>this.columnheaders[0]= label);
this.translate.get('the name').subscribe(label =>this.columnheaders[1]= label);
}
this.settings = {
columns: {
name: {
title:this.columnheaders[0],
type: 'string',
}
name: {
title:this.columnheaders[1],
type: 'string',
}
}}
i wanna product new menu i try Recursive dictionary array
but still not get correct datas.
below its two array , globalRoutes its dict array , menuRoutes its normal array i wanna use
menuRoutes to search globalRoutes
below its my code:
const globalRoutes = [
{
path: '/user',
meta: {
title: 'UserManager',
icon: 'el-icon-user'
},
children: [{
path: 'userinfo',
meta: {
title: 'UserInfo',
}
},
{
path: 'roleinfo',
meta: {
title: 'Roleinfo'
}
},
{
path: 'rolemenu',
meta: {
title: 'roleMenu'
}
}
]
},
{
path: '/test',
meta: {
title: 'TestMenu',
icon: 'el-icon-setting'
}
}
]
const menuRoutes = ['userinfo', '/test']
function Test1(routes) {
res = []
for(let route of routes){
console.log(route.path)
const data = {}
let menuIndex = menuRoutes.indexOf(route.path)
if(menuIndex > -1){
data.path = route.path
data.meta = route.meta
}else{
if(route.children){
data.path = route.path
data.meta = route.meta
data.children = Test1(route.children)
}
}
if (Object.keys(data).length > 0){
res.push(data)
}
}
return res
}
console.log(Test1(globalRoutes))
Error datas as below:
[
{ path: 'userinfo', meta: { title: 'UserInfo' } },
{
path: '/user',
meta: { title: 'UserManager', icon: 'el-icon-user' },
children: [Circular]
},
{
path: '/test',
meta: { title: 'TestMenu', icon: 'el-icon-setting' }
}
]
I wanted correct data as below:
[
{
path: '/user',
meta: { title: 'UserManager', icon: 'el-icon-user' },
children: [{ path: 'userinfo', meta: { title: 'UserInfo' } }]
},
{
path: '/test',
meta: { title: 'TestMenu', icon: 'el-icon-setting' }
}
]
how need i change code to get correct datas?
Here is simple example based on your code.
const globalRoutes = [
{
path: '/user',
meta: {
title: 'UserManager',
icon: 'el-icon-user'
},
children: [{
path: 'userinfo',
meta: {
title: 'UserInfo',
}
},
{
path: 'roleinfo',
meta: {
title: 'Roleinfo'
}
},
{
path: 'rolemenu',
meta: {
title: 'roleMenu'
}
}
]
},
{
path: '/test',
meta: {
title: 'TestMenu',
icon: 'el-icon-setting'
}
}
];
const menuRoutes = ['userinfo', '/test'];
const inRoutes = (search, routes) => {
let result = [];
routes.forEach((item, index) => {
if (search.includes(item.path)) {
result.push(item);
}
if (item.children) {
item.children.forEach((itm, idx) => {
if (search.includes(itm.path)) {
item.children = item.children.filter(i => i === itm); // or item.children = [itm];
result.push(item);
}
});
}
});
return result;
};
console.log(inRoutes(menuRoutes, globalRoutes));
Hope this helps.
Hi have a table Users with many to many relation to Groups through UsersGroups. UsersGroups has a FK to UsersGroupsRoles:
Users:
module.exports = (sequelize, Sequelize) => {
const Users = sequelize.define(
'Users',
{
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
primaryKey: true,
},
name: {
type: Sequelize.STRING,
},
},
{}
);
Users.associate = function(models) {
Users.belongsToMany(models.Groups, { through: models.UsersGroups });
};
return Users;
};
Groups:
module.exports = (sequelize, Sequelize) => {
const Groups = sequelize.define(
'Groups',
{
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
name: {
type: Sequelize.STRING,
},
},
{}
);
Groups.associate = function(models) {
Groups.belongsToMany(models.Users, { through: models.UsersGroups });
};
return Groups;
};
UsersGroups:
module.exports = (sequelize, Sequelize) => {
const UsersGroups = sequelize.define(
'UsersGroups',
{
order: {
allowNull: true,
type: Sequelize.INTEGER,
defaultValue: 10000,
},
},
{}
);
UsersGroups.associate = function(models) {
UsersGroups.belongsTo(models.UsersGroupsRoles, { as: 'UsersGroupsRoles', onDelete: 'CASCADE' });
};
return UsersGroups;
};
UsersGroupsRoles:
module.exports = (sequelize, Sequelize) => {
const UsersGroupsRoles = sequelize.define(
'UsersGroupsRoles',
{
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
role: {
type: Sequelize.STRING,
},
},
{}
);
UsersGroupsRoles.associate = function(models) {
UsersGroupsRoles.hasMany(models.UsersGroups, { as: 'UsersGroupsRoles', onDelete: 'CASCADE' });
};
return UsersGroupsRoles;
};
Now I want to query Users and UsersGroups, and get the UsersGroupsRoles:
models.Groups.findAll({
attributes: {
exclude: ['createdAt', 'updatedAt'],
},
include: [
{
model: models.Users,
attributes: {
exclude: ['createdAt', 'updatedAt', 'email', 'password'],
},
through: {
include: [
{
model: models.UsersGroupsRoles,
as: 'UsersGroupsRoles',
},
],
},
},
],
})
But the query fails with TypeError: Cannot read property 'indexOf' of undefined. I suppose it is because the include clause inside through, but then, what is the correct way to include a one-to-many association in an intermediate table?
Thanks!
What about try this?
try {
let groups = await models.Groups.findAll({
attributes: {
exclude: ['id','createdAt', 'updatedAt'],
}
})
const userGroupsPromises = groups.map(group => {
return models.UsersGroups.findAll({
where: {
groupId: group.id
},
include: [{
model: models.User,
attributes: {
exclude: ['createdAt', 'updatedAt', 'email', 'password'],
}
}, {
model: models.UsersGroupsRoles,
}]
})
})
const userGroupsPromiseResult = await Promise.all(userGroupsPromises)
groups = groups.map((group, index) => {
const _group = group.get()
_group.UserGroups = userGroupsPromiseResult[index]
return _group
})
console.log(groups)
} catch (err) {
console.log(err)
}