7.6 KiB
Response Wall Bug Fixes
Issues Identified and Fixed
1. TypeError: responses.filter is not a function
Error Location: app/controllers/responses.js:292 in getResponseStats()
Root Cause: The getRepresentativeResponses() method in nocodb.js was returning the raw NocoDB API response object {list: [...], pageInfo: {...}} instead of an array. The controller code expected an array and tried to call .filter() on an object.
Fix Applied: Modified getRepresentativeResponses() to extract the list array from the response and normalize each item:
async getRepresentativeResponses(params = {}) {
if (!this.tableIds.representativeResponses) {
throw new Error('Representative responses table not configured');
}
const result = await this.getAll(this.tableIds.representativeResponses, params);
// NocoDB returns {list: [...]} or {pageInfo: {...}, list: [...]}
const list = result.list || [];
return list.map(item => this.normalizeResponse(item));
}
2. TypeError: responses.map is not a function
Error Location: app/controllers/responses.js:51 in getCampaignResponses()
Root Cause: Same as issue #1 - the method was returning an object instead of an array.
Fix Applied: Same fix as above ensures an array is always returned.
3. Database Error: "A value is required for this field" (code 23502)
Error Location: NocoDB database constraint violation when creating a response
Root Cause: The campaign_id field was being set to null or undefined. Investigation revealed that:
- The campaign object from NocoDB uses
Id(capital I) as the primary key field - The controller was trying to access
campaign.id(lowercase) which returnedundefined - NocoDB's representative_responses table has
campaign_idmarked as required ("rqd": true)
Fix Applied:
- Updated
submitResponse()controller to check multiple possible field names:
campaign_id: campaign.Id || campaign.id || campaign['Campaign ID'],
- Added validation in
createRepresentativeResponse()to fail fast if campaign_id is missing:
if (!responseData.campaign_id) {
throw new Error('Campaign ID is required for creating a response');
}
- Added debug logging to track the campaign_id value:
console.log('Submitting response with campaign_id:', newResponse.campaign_id, 'from campaign:', campaign);
4. Array Handling in Response Upvotes
Potential Issue: The getResponseUpvotes() method had the same array vs object issue
Fix Applied: Updated the method to return a normalized array:
async getResponseUpvotes(params = {}) {
if (!this.tableIds.responseUpvotes) {
throw new Error('Response upvotes table not configured');
}
const result = await this.getAll(this.tableIds.responseUpvotes, params);
// NocoDB returns {list: [...]} or {pageInfo: {...}, list: [...]}
const list = result.list || [];
return list.map(item => this.normalizeUpvote(item));
}
Files Modified
-
app/services/nocodb.js
- Modified
getRepresentativeResponses()- Extract and normalize list - Modified
getResponseUpvotes()- Extract and normalize list - Modified
createRepresentativeResponse()- Add campaign_id validation and logging
- Modified
-
app/controllers/responses.js
- Modified
submitResponse()- Handle multiple campaign ID field name variations (ID, Id, id) - Added debug logging for campaign_id
- Modified
-
app/public/js/admin.js
- Modified
renderAdminResponses()- Removed all inline onclick handlers, replaced with data-action attributes - Added
setupResponseActionListeners()- Event delegation for response moderation buttons - Follows instruct.md guidelines: "No inline event handlers. Always use addEventListener in JS files."
- Modified
-
app/public/js/api-client.js
- Added
put()method for HTTP PUT requests - Added
patch()method for HTTP PATCH requests - Added
delete()method for HTTP DELETE requests - These methods were missing and causing errors in admin panel operations
- Added
Testing
After applying these fixes, test the following:
-
Load Response Wall - Visit
http://localhost:3333/response-wall.html?campaign=test-page- Stats should load without errors
- Response list should load without errors
-
Submit Response - Fill out and submit the response form
- Should successfully create a response in pending status
- Should return a success message
- Check logs for "Submitting response with campaign_id: [number]"
-
Upvote Response - Click the upvote button on an approved response
- Should increment the upvote count
- Should prevent duplicate upvotes
-
Admin Moderation - Visit
http://localhost:3333/admin.html→ Response Moderation tab- Should see pending responses
- Should be able to approve/reject responses
Deployment
The application container has been restarted with:
docker compose restart app
All fixes are now live and ready for testing.
Root Cause Analysis
The main issue was a misunderstanding of NocoDB's API response structure:
- Expected: Array of records directly
- Actual: Object with
{list: [records], pageInfo: {...}}
This is a common pattern in REST APIs for pagination support. The fix ensures all service methods return properly normalized arrays for consistent usage throughout the application.
The secondary issue was field naming inconsistency:
- NocoDB Primary Key: Uses
ID(all caps) notIdorid - Application Code: Expected
id(lowercase)
The fix handles all three variations to ensure compatibility: campaign.ID || campaign.Id || campaign.id
5. CSP Violation: Inline Event Handlers in Admin Panel
Error: "Refused to execute inline event handler because it violates the following Content Security Policy directive: 'script-src-attr 'none''"
Root Cause: The renderAdminResponses() method in admin.js was using inline onclick handlers like:
<button onclick="adminPanel.approveResponse(${response.id})">
This violates the development guidelines in instruct.md which explicitly state: "No inline event handlers. Always use addEventListener in JS files."
Fix Applied:
- Replaced all inline onclick handlers with data-action attributes
- Created
setupResponseActionListeners()method using event delegation - All buttons now use pattern:
data-action="approve-response" data-response-id="${response.id}" - Event delegation listens on container and routes actions based on data attributes
6. Missing HTTP Methods in API Client
Error: "TypeError: window.apiClient.patch is not a function"
Root Cause: The APIClient class in api-client.js only had get() and post() methods. Admin panel operations needed patch(), put(), and delete() methods for updating and deleting responses.
Fix Applied: Added three new methods to APIClient:
async put(endpoint, data) { ... }
async patch(endpoint, data) { ... }
async delete(endpoint) { ... }
Prevention
To prevent similar issues in the future:
- Type Safety: Consider adding TypeScript or JSDoc type annotations
- Consistent Normalization: Always normalize data at the service layer
- Field Name Standards: Document NocoDB field naming conventions
- Validation: Add validation for required fields early in the request flow
- Logging: Continue adding debug logging for data transformations
Related Documentation
- See
RESPONSE_WALL_USAGE.mdfor usage instructions - See
RESPONSE_WALL_IMPLEMENTATION.mdfor feature implementation details - See
scripts/build-nocodb.shfor database schema definitions