801 lines
14 KiB
Markdown
801 lines
14 KiB
Markdown
# Property Dependencies Guide
|
|
|
|
Deep dive into n8n property dependencies and displayOptions mechanism.
|
|
|
|
---
|
|
|
|
## What Are Property Dependencies?
|
|
|
|
**Definition**: Rules that control when fields are visible or required based on other field values.
|
|
|
|
**Mechanism**: `displayOptions` in node schema
|
|
|
|
**Purpose**:
|
|
- Show relevant fields only
|
|
- Hide irrelevant fields
|
|
- Simplify configuration UX
|
|
- Prevent invalid configurations
|
|
|
|
---
|
|
|
|
## displayOptions Structure
|
|
|
|
### Basic Format
|
|
|
|
```javascript
|
|
{
|
|
"name": "fieldName",
|
|
"type": "string",
|
|
"displayOptions": {
|
|
"show": {
|
|
"otherField": ["value1", "value2"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Translation**: Show `fieldName` when `otherField` equals "value1" OR "value2"
|
|
|
|
### Show vs Hide
|
|
|
|
#### show (Most Common)
|
|
|
|
**Show field when condition matches**:
|
|
```javascript
|
|
{
|
|
"name": "body",
|
|
"displayOptions": {
|
|
"show": {
|
|
"sendBody": [true]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Meaning**: Show `body` when `sendBody = true`
|
|
|
|
#### hide (Less Common)
|
|
|
|
**Hide field when condition matches**:
|
|
```javascript
|
|
{
|
|
"name": "advanced",
|
|
"displayOptions": {
|
|
"hide": {
|
|
"simpleMode": [true]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Meaning**: Hide `advanced` when `simpleMode = true`
|
|
|
|
### Multiple Conditions (AND Logic)
|
|
|
|
```javascript
|
|
{
|
|
"name": "body",
|
|
"displayOptions": {
|
|
"show": {
|
|
"sendBody": [true],
|
|
"method": ["POST", "PUT", "PATCH"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Meaning**: Show `body` when:
|
|
- `sendBody = true` AND
|
|
- `method IN (POST, PUT, PATCH)`
|
|
|
|
**All conditions must match** (AND logic)
|
|
|
|
### Multiple Values (OR Logic)
|
|
|
|
```javascript
|
|
{
|
|
"name": "someField",
|
|
"displayOptions": {
|
|
"show": {
|
|
"method": ["POST", "PUT", "PATCH"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Meaning**: Show `someField` when:
|
|
- `method = POST` OR
|
|
- `method = PUT` OR
|
|
- `method = PATCH`
|
|
|
|
**Any value matches** (OR logic)
|
|
|
|
---
|
|
|
|
## Common Dependency Patterns
|
|
|
|
### Pattern 1: Boolean Toggle
|
|
|
|
**Use case**: Optional feature flag
|
|
|
|
**Example**: HTTP Request sendBody
|
|
```javascript
|
|
// Field: sendBody (boolean)
|
|
{
|
|
"name": "sendBody",
|
|
"type": "boolean",
|
|
"default": false
|
|
}
|
|
|
|
// Field: body (depends on sendBody)
|
|
{
|
|
"name": "body",
|
|
"displayOptions": {
|
|
"show": {
|
|
"sendBody": [true]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Flow**:
|
|
1. User sees sendBody checkbox
|
|
2. When checked → body field appears
|
|
3. When unchecked → body field hides
|
|
|
|
### Pattern 2: Resource/Operation Cascade
|
|
|
|
**Use case**: Different operations show different fields
|
|
|
|
**Example**: Slack message operations
|
|
```javascript
|
|
// Operation: post
|
|
{
|
|
"name": "channel",
|
|
"displayOptions": {
|
|
"show": {
|
|
"resource": ["message"],
|
|
"operation": ["post"]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Operation: update
|
|
{
|
|
"name": "messageId",
|
|
"displayOptions": {
|
|
"show": {
|
|
"resource": ["message"],
|
|
"operation": ["update"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Flow**:
|
|
1. User selects resource="message"
|
|
2. User selects operation="post" → sees channel
|
|
3. User changes to operation="update" → channel hides, messageId shows
|
|
|
|
### Pattern 3: Type-Specific Configuration
|
|
|
|
**Use case**: Different types need different fields
|
|
|
|
**Example**: IF node conditions
|
|
```javascript
|
|
// String operations
|
|
{
|
|
"name": "value2",
|
|
"displayOptions": {
|
|
"show": {
|
|
"conditions.string.0.operation": ["equals", "notEquals", "contains"]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unary operations (isEmpty) don't show value2
|
|
{
|
|
"displayOptions": {
|
|
"hide": {
|
|
"conditions.string.0.operation": ["isEmpty", "isNotEmpty"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Pattern 4: Method-Specific Fields
|
|
|
|
**Use case**: HTTP methods have different options
|
|
|
|
**Example**: HTTP Request
|
|
```javascript
|
|
// Query parameters (all methods can have)
|
|
{
|
|
"name": "queryParameters",
|
|
"displayOptions": {
|
|
"show": {
|
|
"sendQuery": [true]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Body (only certain methods)
|
|
{
|
|
"name": "body",
|
|
"displayOptions": {
|
|
"show": {
|
|
"sendBody": [true],
|
|
"method": ["POST", "PUT", "PATCH", "DELETE"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Using get_property_dependencies
|
|
|
|
### Basic Usage
|
|
|
|
```javascript
|
|
const deps = get_property_dependencies({
|
|
nodeType: "nodes-base.httpRequest"
|
|
});
|
|
```
|
|
|
|
### Example Response
|
|
|
|
```javascript
|
|
{
|
|
"nodeType": "n8n-nodes-base.httpRequest",
|
|
"dependencies": {
|
|
"body": {
|
|
"shows_when": {
|
|
"sendBody": [true],
|
|
"method": ["POST", "PUT", "PATCH", "DELETE"]
|
|
},
|
|
"required_when_shown": true
|
|
},
|
|
"queryParameters": {
|
|
"shows_when": {
|
|
"sendQuery": [true]
|
|
},
|
|
"required_when_shown": false
|
|
},
|
|
"headerParameters": {
|
|
"shows_when": {
|
|
"sendHeaders": [true]
|
|
},
|
|
"required_when_shown": false
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### When to Use
|
|
|
|
**✅ Use when**:
|
|
- Validation fails with "missing field" but you don't see that field
|
|
- A field appears/disappears unexpectedly
|
|
- You need to understand what controls field visibility
|
|
- Building dynamic configuration tools
|
|
|
|
**❌ Don't use when**:
|
|
- Simple configuration (use get_node_essentials)
|
|
- Just starting configuration
|
|
- Field requirements are obvious
|
|
|
|
---
|
|
|
|
## Complex Dependency Examples
|
|
|
|
### Example 1: HTTP Request Complete Flow
|
|
|
|
**Scenario**: Configuring POST with JSON body
|
|
|
|
**Step 1**: Set method
|
|
```javascript
|
|
{
|
|
"method": "POST"
|
|
// → sendBody becomes visible
|
|
}
|
|
```
|
|
|
|
**Step 2**: Enable body
|
|
```javascript
|
|
{
|
|
"method": "POST",
|
|
"sendBody": true
|
|
// → body field becomes visible AND required
|
|
}
|
|
```
|
|
|
|
**Step 3**: Configure body
|
|
```javascript
|
|
{
|
|
"method": "POST",
|
|
"sendBody": true,
|
|
"body": {
|
|
"contentType": "json"
|
|
// → content field becomes visible AND required
|
|
}
|
|
}
|
|
```
|
|
|
|
**Step 4**: Add content
|
|
```javascript
|
|
{
|
|
"method": "POST",
|
|
"sendBody": true,
|
|
"body": {
|
|
"contentType": "json",
|
|
"content": {
|
|
"name": "John",
|
|
"email": "john@example.com"
|
|
}
|
|
}
|
|
}
|
|
// ✅ Valid!
|
|
```
|
|
|
|
**Dependency chain**:
|
|
```
|
|
method=POST
|
|
→ sendBody visible
|
|
→ sendBody=true
|
|
→ body visible + required
|
|
→ body.contentType=json
|
|
→ body.content visible + required
|
|
```
|
|
|
|
### Example 2: IF Node Operator Dependencies
|
|
|
|
**Scenario**: String comparison with different operators
|
|
|
|
**Binary operator** (equals):
|
|
```javascript
|
|
{
|
|
"conditions": {
|
|
"string": [
|
|
{
|
|
"operation": "equals"
|
|
// → value1 required
|
|
// → value2 required
|
|
// → singleValue should NOT be set
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Unary operator** (isEmpty):
|
|
```javascript
|
|
{
|
|
"conditions": {
|
|
"string": [
|
|
{
|
|
"operation": "isEmpty"
|
|
// → value1 required
|
|
// → value2 should NOT be set
|
|
// → singleValue should be true (auto-added)
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Dependency table**:
|
|
|
|
| Operator | value1 | value2 | singleValue |
|
|
|---|---|---|---|
|
|
| equals | Required | Required | false |
|
|
| notEquals | Required | Required | false |
|
|
| contains | Required | Required | false |
|
|
| isEmpty | Required | Hidden | true |
|
|
| isNotEmpty | Required | Hidden | true |
|
|
|
|
### Example 3: Slack Operation Matrix
|
|
|
|
**Scenario**: Different Slack operations show different fields
|
|
|
|
```javascript
|
|
// post message
|
|
{
|
|
"resource": "message",
|
|
"operation": "post"
|
|
// Shows: channel (required), text (required), attachments, blocks
|
|
}
|
|
|
|
// update message
|
|
{
|
|
"resource": "message",
|
|
"operation": "update"
|
|
// Shows: messageId (required), text (required), channel (optional)
|
|
}
|
|
|
|
// delete message
|
|
{
|
|
"resource": "message",
|
|
"operation": "delete"
|
|
// Shows: messageId (required), channel (required)
|
|
// Hides: text, attachments, blocks
|
|
}
|
|
|
|
// get message
|
|
{
|
|
"resource": "message",
|
|
"operation": "get"
|
|
// Shows: messageId (required), channel (required)
|
|
// Hides: text, attachments, blocks
|
|
}
|
|
```
|
|
|
|
**Field visibility matrix**:
|
|
|
|
| Field | post | update | delete | get |
|
|
|---|---|---|---|---|
|
|
| channel | Required | Optional | Required | Required |
|
|
| text | Required | Required | Hidden | Hidden |
|
|
| messageId | Hidden | Required | Required | Required |
|
|
| attachments | Optional | Optional | Hidden | Hidden |
|
|
| blocks | Optional | Optional | Hidden | Hidden |
|
|
|
|
---
|
|
|
|
## Nested Dependencies
|
|
|
|
### What Are They?
|
|
|
|
**Definition**: Dependencies within object properties
|
|
|
|
**Example**: HTTP Request body.contentType controls body.content structure
|
|
|
|
```javascript
|
|
{
|
|
"body": {
|
|
"contentType": "json",
|
|
// → content expects JSON object
|
|
"content": {
|
|
"key": "value"
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
"body": {
|
|
"contentType": "form-data",
|
|
// → content expects form fields array
|
|
"content": [
|
|
{
|
|
"name": "field1",
|
|
"value": "value1"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
### How to Handle
|
|
|
|
**Strategy**: Configure parent first, then children
|
|
|
|
```javascript
|
|
// Step 1: Parent
|
|
{
|
|
"body": {
|
|
"contentType": "json" // Set parent first
|
|
}
|
|
}
|
|
|
|
// Step 2: Children (structure determined by parent)
|
|
{
|
|
"body": {
|
|
"contentType": "json",
|
|
"content": { // JSON object format
|
|
"key": "value"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Auto-Sanitization and Dependencies
|
|
|
|
### What Auto-Sanitization Fixes
|
|
|
|
**Operator structure issues** (IF/Switch nodes):
|
|
|
|
**Example**: singleValue property
|
|
```javascript
|
|
// You configure (missing singleValue)
|
|
{
|
|
"type": "boolean",
|
|
"operation": "isEmpty"
|
|
// Missing singleValue
|
|
}
|
|
|
|
// Auto-sanitization adds it
|
|
{
|
|
"type": "boolean",
|
|
"operation": "isEmpty",
|
|
"singleValue": true // ✅ Added automatically
|
|
}
|
|
```
|
|
|
|
### What It Doesn't Fix
|
|
|
|
**Missing required fields**:
|
|
```javascript
|
|
// You configure (missing channel)
|
|
{
|
|
"resource": "message",
|
|
"operation": "post",
|
|
"text": "Hello"
|
|
// Missing required field: channel
|
|
}
|
|
|
|
// Auto-sanitization does NOT add
|
|
// You must add it yourself
|
|
{
|
|
"resource": "message",
|
|
"operation": "post",
|
|
"channel": "#general", // ← You must add
|
|
"text": "Hello"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting Dependencies
|
|
|
|
### Problem 1: "Field X is required but not visible"
|
|
|
|
**Error**:
|
|
```json
|
|
{
|
|
"type": "missing_required",
|
|
"property": "body",
|
|
"message": "body is required"
|
|
}
|
|
```
|
|
|
|
**But you don't see body field in configuration!**
|
|
|
|
**Solution**:
|
|
```javascript
|
|
// Check dependencies
|
|
const deps = get_property_dependencies({
|
|
nodeType: "nodes-base.httpRequest"
|
|
});
|
|
|
|
// Find that body shows when sendBody=true
|
|
// Add sendBody
|
|
{
|
|
"method": "POST",
|
|
"sendBody": true, // ← Now body appears!
|
|
"body": {...}
|
|
}
|
|
```
|
|
|
|
### Problem 2: "Field disappears when I change operation"
|
|
|
|
**Scenario**:
|
|
```javascript
|
|
// Working configuration
|
|
{
|
|
"resource": "message",
|
|
"operation": "post",
|
|
"channel": "#general",
|
|
"text": "Hello"
|
|
}
|
|
|
|
// Change operation
|
|
{
|
|
"resource": "message",
|
|
"operation": "update", // Changed
|
|
"channel": "#general", // Still here
|
|
"text": "Updated" // Still here
|
|
// Missing: messageId (required for update!)
|
|
}
|
|
```
|
|
|
|
**Validation error**: "messageId is required"
|
|
|
|
**Why**: Different operation = different required fields
|
|
|
|
**Solution**:
|
|
```javascript
|
|
// Check essentials for new operation
|
|
get_node_essentials({
|
|
nodeType: "nodes-base.slack"
|
|
});
|
|
|
|
// Configure for update operation
|
|
{
|
|
"resource": "message",
|
|
"operation": "update",
|
|
"messageId": "1234567890", // Required for update
|
|
"text": "Updated",
|
|
"channel": "#general" // Optional for update
|
|
}
|
|
```
|
|
|
|
### Problem 3: "Validation passes but field doesn't save"
|
|
|
|
**Scenario**: Field hidden by dependencies after validation
|
|
|
|
**Example**:
|
|
```javascript
|
|
// Configure
|
|
{
|
|
"method": "GET",
|
|
"sendBody": true, // ❌ GET doesn't support body
|
|
"body": {...} // This will be stripped
|
|
}
|
|
|
|
// After save
|
|
{
|
|
"method": "GET"
|
|
// body removed because method=GET hides it
|
|
}
|
|
```
|
|
|
|
**Solution**: Respect dependencies from the start
|
|
|
|
```javascript
|
|
// Correct approach
|
|
get_property_dependencies({
|
|
nodeType: "nodes-base.httpRequest"
|
|
});
|
|
|
|
// See that body only shows for POST/PUT/PATCH/DELETE
|
|
// Use correct method
|
|
{
|
|
"method": "POST",
|
|
"sendBody": true,
|
|
"body": {...}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Advanced Patterns
|
|
|
|
### Pattern 1: Conditional Required with Fallback
|
|
|
|
**Example**: Channel can be string OR expression
|
|
|
|
```javascript
|
|
// Option 1: String
|
|
{
|
|
"channel": "#general"
|
|
}
|
|
|
|
// Option 2: Expression
|
|
{
|
|
"channel": "={{$json.channelName}}"
|
|
}
|
|
|
|
// Validation accepts both
|
|
```
|
|
|
|
### Pattern 2: Mutually Exclusive Fields
|
|
|
|
**Example**: Use either ID or name, not both
|
|
|
|
```javascript
|
|
// Use messageId
|
|
{
|
|
"messageId": "1234567890"
|
|
// name not needed
|
|
}
|
|
|
|
// OR use messageName
|
|
{
|
|
"messageName": "thread-name"
|
|
// messageId not needed
|
|
}
|
|
|
|
// Dependencies ensure only one is required
|
|
```
|
|
|
|
### Pattern 3: Progressive Complexity
|
|
|
|
**Example**: Simple mode vs advanced mode
|
|
|
|
```javascript
|
|
// Simple mode
|
|
{
|
|
"mode": "simple",
|
|
"text": "{{$json.message}}"
|
|
// Advanced fields hidden
|
|
}
|
|
|
|
// Advanced mode
|
|
{
|
|
"mode": "advanced",
|
|
"attachments": [...],
|
|
"blocks": [...],
|
|
"metadata": {...}
|
|
// Simple field hidden, advanced fields shown
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### ✅ Do
|
|
|
|
1. **Check dependencies when stuck**
|
|
```javascript
|
|
get_property_dependencies({nodeType: "..."});
|
|
```
|
|
|
|
2. **Configure parent properties first**
|
|
```javascript
|
|
// First: method, resource, operation
|
|
// Then: dependent fields
|
|
```
|
|
|
|
3. **Validate after changing operation**
|
|
```javascript
|
|
// Operation changed → requirements changed
|
|
validate_node_operation({...});
|
|
```
|
|
|
|
4. **Read validation errors for dependency hints**
|
|
```
|
|
Error: "body required when sendBody=true"
|
|
→ Hint: Set sendBody=true to enable body
|
|
```
|
|
|
|
### ❌ Don't
|
|
|
|
1. **Don't ignore dependency errors**
|
|
```javascript
|
|
// Error: "body not visible" → Check displayOptions
|
|
```
|
|
|
|
2. **Don't hardcode all possible fields**
|
|
```javascript
|
|
// Bad: Adding fields that will be hidden
|
|
```
|
|
|
|
3. **Don't assume operations are identical**
|
|
```javascript
|
|
// Each operation has unique requirements
|
|
```
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
**Key Concepts**:
|
|
- `displayOptions` control field visibility
|
|
- `show` = field appears when conditions match
|
|
- `hide` = field disappears when conditions match
|
|
- Multiple conditions = AND logic
|
|
- Multiple values = OR logic
|
|
|
|
**Common Patterns**:
|
|
1. Boolean toggle (sendBody → body)
|
|
2. Resource/operation cascade (different operations → different fields)
|
|
3. Type-specific config (string vs boolean conditions)
|
|
4. Method-specific fields (GET vs POST)
|
|
|
|
**Troubleshooting**:
|
|
- Field required but not visible → Check dependencies
|
|
- Field disappears after change → Operation changed requirements
|
|
- Field doesn't save → Hidden by dependencies
|
|
|
|
**Tools**:
|
|
- `get_property_dependencies` - See dependency rules
|
|
- `get_node_essentials` - See operation requirements
|
|
- Validation errors - Hints about dependencies
|
|
|
|
**Related Files**:
|
|
- **[SKILL.md](SKILL.md)** - Main configuration guide
|
|
- **[OPERATION_PATTERNS.md](OPERATION_PATTERNS.md)** - Common patterns by node type
|