Hello all, I was following this article (Field representing related object not populating) on how to get fields representing related objects populated. I was able to get it working, however, I noticed the custom filters no longer work.
My question how can I extend the base behavior so that I can add my model includes? I view the documentation here https://docs.forestadmin.com/documentation/v/v6/reference-guide/routes/default-routes#get-a-list-of-records, but it doesn’t show how to add includes/joins.
My imports
const express = require('express');
const { PermissionMiddlewareCreator, RecordsGetter, RecordGetter } = require('forest-express-sequelize');
const { collections, orderItems, orders, buyers, brands } = require('../models');
const routr = express.Router();
const permissionMiddlewareCreator = new PermissionMiddlewareCreator('orders');
List override
router.get('/orders', permissionMiddlewareCreator.list(), (request, response, next) => {
// Learn what this route does here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/routes/default-routes#get-a-list-of-records
const limit = parseInt(request.query.page.size, 10) || 15
const offset = (parseInt(request.query.page.number, 10) - 1) * limit
const recordsGetter = new RecordsGetter(orders)
const include = [
{ model: collections, include: [{ model: brands}] },
{ model: orderItems },
{ model: buyers }
]
var findAll = orders.findAndCountAll({ include: include, offset, limit })
Promise.all([findAll]).then(([allOrders]) => {
return recordsGetter.serialize(allOrders.rows, { count: allOrders.count })
})
.then((recordsSerialized) => {
return response.send(recordsSerialized);
})
.catch(next)
});
Expected behavior
- The user goes to the list page
- User clicks on the filter button and applies custom filters (where the selected field is not = x)
- The admin displays filters orders by the custom filters
Actual behavior
What is the current behavior?
- Filters are not being displayed
Context
- Package Version:
- Express Version: 4.16.3
- Sequelize Version: 5.15.1
- Database Dialect: MySQL
- Database Version: 1.7.0
Hi @james-janetech,
Welcome to our community!
I have one silly question to begin: why do you need to override your route? Are you sure you need to?
I was wondering because the features you talked about (having related data displayed, custom filters taken into account) are working with the default code if your DB is well defined.
If you actually need to override your route, then your filters will be taken into account if you use (as shown in the doc) recordsGetter.getAll(request.query)
.
Let me know!
Cheers.
Hi @anon34731316,
I’m running into the same issue mentioned in this article where Field representing related object not populating
Order model association:
Orders.associate = (models) => {
Orders.belongsTo(models.buyers);
Orders.belongsTo(models.collections);
Orders.hasMany(models.orderItems);
};
My order smart view
const { collection } = require('forest-express-sequelize');
const models = require('../models');
// This file allows you to add to your Forest UI:
// - Smart actions: https://docs.forestadmin.com/documentation/reference-guide/actions/create-and-manage-smart-actions
// - Smart fields: https://docs.forestadmin.com/documentation/reference-guide/fields/create-and-manage-smart-fields
// - Smart relationships: https://docs.forestadmin.com/documentation/reference-guide/relationships/create-a-smart-relationship
// - Smart segments: https://docs.forestadmin.com/documentation/reference-guide/segments/smart-segments
collection('orders', {
actions: [],
fields: [
{
field: 'order number',
type: 'Integer',
get: (order) => {
return order.id
}
},
{
field: 'units',
type: 'Number',
get: function(order) {
return order.orderItems.reduce((a, b) => {
return a + (b['quantity'] || 0)
}, 0);
}
},
{
field: 'Collection Name',
type: "String",
get: (order) => {
return `${order.collection.brand.name} ${order.collection.season}`;
}
},
{ // used to override totalPrice until moved to the database
field: 'total_price',
type: 'String',
get: (order) => {
let totalPrice = (order.status == 'draft') ? (order.orderItems||[]).reduce((a, b) => { return a + (parseFloat(b['totalPrice']) || 0) }, 0) : parseFloat(order.totalPrice);
let currency = (order.orderItems.length > 0) ? order.orderItems[0].currency : order.collection.currency[0]
return `${totalPrice.toFixed(2)} ${currency.toUpperCase()}`
}
},
{ // used to override subtotalPrice // used to override totalPrice until moved to the database
field: 'sub_total_price',
type: 'String',
get: (order) => {
let subtotalPrice = (order.status == 'draft') ? (order.orderItems||[]).reduce((a, b) => { return a + (parseFloat(b['subtotalPrice']) || 0) }, 0) : parseFloat(order.subtotalPrice);
let currency = (order.orderItems.length > 0) ? order.orderItems[0].currency : order.collection.currency[0]
return `${subtotalPrice.toFixed(2)} ${currency.toUpperCase()}`
}
}
],
segments: [],
});
I’m only able to view the see the smart fields if I click on the data.
This tells me my orders list isn’t including the joins when querying. I even tried it using the snipet here
https://docs.forestadmin.com/documentation/reference-guide/relationships/create-a-smart-relationship
@james-janetech,
Yes the problem is probably coming from the route you’ve overridden.
I am still not sure why you needed to though. If you explain me it might give me more useful information to help you out
And as I said in my previous message:
if you actually need to override your route, then your filters will be taken into account if you use (as shown in the doc) recordsGetter.getAll(request.query)
.
Did you check this documentation and did you try this syntax?
Thanks.
@anon34731316 ,
I’m trying to get my smart view fields to be populated. I reverted my changes overriding the routes using the code from the documentation only.
orders admin page
orders.js (route)
orders.js (forest)
Okay I resolved the issue. When debugging I don’t think forest add the includes on the list page, that’s why I’m not seeing the smart view.
My solution feels like a hack if there’s a better way feel free to chime in.
First, I let forest do all of the work with the filtering, then I take the ids and pass it to my orders model so it can return all of the includes
records => orders.findAll({include: associations, where:{ id: records.map(r => r.id )}}))
code block
const recordsGetter = new RecordsGetter(orders);
recordsGetter.getAll(request.query).then(records => orders.findAll({include: associations, where:{ id: records.map(r => r.id )}}))
.then(records => recordsGetter.serialize(records))
.then(recordsSerialized => response.send(recordsSerialized))
.catch(next);
Thanks