Azure Bicep: setting a null value if the property doesn't exist - azure

I am deploying schedules for the azure update management service through bicep. My code is as below:
param parSchedules array = [
{
name: 'mysched1'
monthlyOccurrencesDay: null
monthlyOccurrencesOccurence: null
DaysOfWeek: 'Wednesday'
StartTime: '${parBaseTimeForUpdateSchedules}T19:00:00'
tag: {
Update: [
'tag1'
]
}
}
{
name: 'mysched2'
monthlyOccurrencesDay: 'Wednesday'
monthlyOccurrencesOccurence: 1
DaysOfWeek: 'Wednesday'
StartTime: '${parBaseTimeForUpdateSchedules}T07:00:00'
tag: {
Update: [
'tag2'
]
}
}
]
resource resUpdateschedule 'Microsoft.Automation/automationAccounts/softwareUpdateConfigurations#2019-06-01' = [for schedule in parSchedules: {
name: schedule.name
parent: resAutomationAccount
properties: {
scheduleInfo: {
advancedSchedule: {
monthlyOccurrences: [
{
day: schedule.monthlyOccurrencesDay
occurrence: schedule.monthlyOccurrencesOccurence
}
]
weekDays: [
schedule.DaysOfWeek
]
}
description: ''
frequency: 'Week'
interval: 1
isEnabled: true
startTime: schedule.StartTime
timeZone: 'UTC'
}
updateConfiguration: {
duration: 'PT2H'
operatingSystem: 'Windows'
targets: {
azureQueries: [
{
locations: [
parLocation
]
scope: [
subscription().id
]
tagSettings: {
tags: schedule.tag
}
}
]
}
windows: {
includedUpdateClassifications: 'Critical, Security'
rebootSetting: 'IfRequired'
}
}
}
}]
I am getting error with this because null value is not accepted for monthlyOccurrencesDay and monthlyOccurrencesOccurence. So what I want is to be able to use the same list containing different types of schedules (with and without monthlyOccurrencesOccurence) by looping the same resource. Like if the values of monthlyOccurrencesOccurence is null, it shouldn't take into consideration this property. Is that possible at all?

You should be able to conditionally set the monthly occurence like that:
resource resUpdateschedule 'Microsoft.Automation/automationAccounts/softwareUpdateConfigurations#2019-06-01' = [for schedule in parSchedules: {
name: schedule.name
...
properties: {
scheduleInfo: {
advancedSchedule: {
monthlyOccurrences: schedule.monthlyOccurrencesOccurence != null ? [
{
day: schedule.monthlyOccurrencesDay
occurrence: schedule.monthlyOccurrencesOccurence
}
] : []
...
}
...
}
...
}
}]

Related

I am trying to deploy a Logic-App with a Service-Bus Deploy to azure app using Bicep template

I am trying to deploy a bicep template to create a logic app and service bus using VS Code. But When I am trying to deploy the Bicep to azure portal
I am getting bad request error
enter image description here
Here is my Bicep look like
param prefix string
param location string = resourceGroup().location
param sendGridApiKey string
resource serviceBus 'Microsoft.ServiceBus/namespaces#2021-11-01' existing = {
name: '${prefix}sb'
}
resource serviceBusConnection 'Microsoft.Web/connections#2016-06-01' = {
name: '${prefix}sbconn'
location: location
properties: {
displayName: '${prefix}sb'
api: {
id: '${subscription().id}/providers/Microsoft.Web/locations/${location}/managedApis/servicebus'
}
parameterValueSet: {
name: 'managedIdentityAuth'
values: {
namespaceEndpoint: {
value: 'sb://${serviceBus.name}.servicebus.windows.net'
}
}
}
}
}
resource sendGridConnection 'Microsoft.Web/connections#2016-06-01' = {
name: '${prefix}sndgrdconn'
location: location
properties: {
displayName: '${prefix}sndgrdconn'
api: {
id: '${subscription().id}/providers/Microsoft.Web/locations/${location}/managedApis/sendgrid'
}
parameterValues: {
apiKey: sendGridApiKey
}
}
}
resource logicAppEmailSend 'Microsoft.Logic/workflows#2019-05-01' = {
name: '${prefix}logic-EmailSend'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
state: 'Enabled'
definition: {
'$schema': 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#'
contentVersion: '1.0.0.0'
parameters: {
'$connections': {
defaultValue: {}
type: 'Object'
}
}
}
}
}
I have tried a lot but didn't find the error
thanks in advance.
I have modified a bit of code in the given code so it's working, and I have deployed the bicep file using VS Code to Azure
{subscription().id}/providers/Microsoft.Web/locations/{location}/servicebus
I have changed the above path to
{subscription().id}/providers/Microsoft.Web/locations/{location}/managedApis/servicebus
Thanks to #mattruma for Bicep template
param prefix string
param location string = resourceGroup().location
param sendGridApiKey string
resource serviceBus 'Microsoft.ServiceBus/namespaces#2021-11-01' existing = {
name: '${prefix}sb'
}
resource serviceBusConnection 'Microsoft.Web/connections#2016-06-01' = {
name: '${prefix}sbconn'
location: location
properties: {
displayName: '${prefix}sb'
api:
{
id: '${subscription().id}/providers/Microsoft.Web/locations/${location}/managedApis/servicebus'
}
parameterValueSet:
{
name: 'managedIdentityAuth'
values:
{
namespaceEndpoint:
{
value: 'sb://${serviceBus.name}.servicebus.windows.net'
}
}
}
}
}
resource logicAppEmailSend 'Microsoft.Logic/workflows#2019-05-01' = {
name: '${prefix}logic-EmailSend'
location: location
identity: {
type: 'SystemAssigned'
}
properties:
{
state: 'Enabled'
definition:
{
'$schema': 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#'
contentVersion: '1.0.0.0'
parameters:
{
'$connections': {
defaultValue: { }
type: 'Object'
}
}
triggers:
{
'When_a_message_is_received_in_a_queue_(auto-complete)': {
recurrence:
{
frequency: 'Minute'
interval: 3
}
evaluatedRecurrence:
{
frequency: 'Minute'
interval: 3
}
type: 'ApiConnection'
inputs:
{
host:
{
connection:
{
name: '#parameters(\'$connections\')[\'servicebus\'][\'connectionId\']'
}
}
method: 'get'
path: '/#{encodeURIComponent(encodeURIComponent(\'emailsend\'))}/messages/head'
queries:
{
queueType: 'Main'
}
}
}
}
actions:
{
'Dead-letter_the_message_in_a_queue': {
runAfter:
{
Send_email: [
'Failed'
'TimedOut'
]
}
type: 'ApiConnection'
inputs:
{
host:
{
connection:
{
name: '#parameters(\'$connections\')[\'servicebus\'][\'connectionId\']'
}
}
method: 'post'
path: '/#{encodeURIComponent(encodeURIComponent(\'emailsend\'))}/messages/deadletter'
queries:
{
deadLetterErrorDescription: ''
deadLetterReason: ''
lockToken: '#triggerBody()?[\'LockToken\']'
sessionId: '#triggerBody()?[\'SessionId\']'
}
}
}
Parse_message:
{
runAfter: { }
type: 'ParseJson'
inputs:
{
content: '#base64ToString(triggerBody()?[\'ContentData\'])'
schema:
{
properties:
{
body:
{
type: 'string'
}
subject:
{
type: 'string'
}
to:
{
type: 'string'
}
}
type: 'object'
}
}
}
Send_email:
{
runAfter:
{
Parse_message: [
'Succeeded'
]
}
type: 'ApiConnection'
inputs:
{
body:
{
from: 'someone#somewhere.com'
fromname: 'Someone'
ishtml: true
subject: '#body(\'Parse_message\')?[\'subject\']'
text: '<p>#{body(\'Parse_message\')?[\'body\']}</p>'
to: '#body(\'Parse_message\')?[\'to\']'
}
host:
{
connection:
{
name: '#parameters(\'$connections\')[\'sendgrid\'][\'connectionId\']'
}
}
method: 'post'
path: '/v4/mail/send'
}
}
}
outputs: { }
}
parameters:
{
'$connections': {
value:
{
servicebus:
{
connectionId: serviceBusConnection.id
connectionName: serviceBusConnection.name
connectionProperties: {
authentication:
{
type: 'ManagedServiceIdentity'
}
}
id: '${subscription().id}/providers/Microsoft.Web/locations/${location}/managedApis/servicebus'
}
}
}
}
}
}
After successfully deploying to azure portal
Click on Goto resource group it will redirect to below page

This expression is referencing its own declaration, which is not allowed.bicep(BCP079) Bicep errr

I have a bicep file which is supposed to create a virtual network gateway. I have broken it down by having a seperate bicep file that creates the virtual network. What I really ought to do is have a module for the vnet creation and another for the virtual network gateway, as bicep is new to me, I prefer to do things with little steps and then improve.
What am I trying to achieve ?
Create a virtual network gateway using bicep. I have it as an ARM template which currently works. I converted the ARM template to a bicep file, and this has failed to successfully deploy.
param location string = resourceGroup().location
param rg string = resourceGroup().name
param virtual_network_name string = 'my_virtual_network'
param gwSubnetName string = 'myGatewaySubnet'
param public_ip_gateway string = 'my_public_ip'
param p2s_vpn_name string = 'myPoint_toSite'
param p2s_subnet_name string = 'p2s_subnet'
resource public_ip_gateway_resource 'Microsoft.Network/publicIPAddresses#2022-01-01' = {
name: public_ip_gateway
location: location
sku: {
name: 'Basic'
tier: 'Regional'
}
properties: {
ipAddress: '40.161.130.50'
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Dynamic'
idleTimeoutInMinutes: 4
ipTags: []
}
}
resource virtual_network_name_GatewaySubnet 'Microsoft.Network/virtualNetworks/subnets#2022-01-01' = {
name: '${virtual_network_name}/GatewaySubnet'
properties: {
addressPrefix: '10.2.255.0/25'
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
dependsOn: [
virtual_network_name_resource
]
}
resource virtual_network_name_p2s_subnet 'Microsoft.Network/virtualNetworks/subnets#2022-01-01' = {
name: '${virtual_network_name}/p2s_subnet'
properties: {
addressPrefix: '10.2.1.0/24'
serviceEndpoints: []
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
dependsOn: [
virtual_network_name_resource
]
}
resource p2s_vpn_name_resource 'Microsoft.Network/virtualNetworkGateways#2022-01-01' = {
name: p2s_vpn_name
location: location
properties: {
enablePrivateIpAddress: false
ipConfigurations: [
{
name: 'default'
id: '${p2s_vpn_name_resource.id}/ipConfigurations/default'
properties: {
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
id: public_ip_gateway_resource.id
}
subnet: {
id: virtual_network_name_GatewaySubnet.id
}
}
}
]
natRules: []
enableBgpRouteTranslationForNat: false
disableIPSecReplayProtection: false
sku: {
name: 'VpnGw1'
tier: 'VpnGw1'
}
gatewayType: 'Vpn'
vpnType: 'RouteBased'
enableBgp: false
activeActive: false
vpnClientConfiguration: {
vpnClientAddressPool: {
addressPrefixes: [
'119.x.x.0/24'
]
}
vpnClientProtocols: [
'OpenVPN'
]
vpnAuthenticationTypes: [
'Certificate'
]
vpnClientRootCertificates: [
{
name: 'Rahman'
id: '${p2s_vpn_name_resource.id}/vpnClientRootCertificates/MyCert'
properties: {
publicCertData: 'xxxxxxxxxxx=='
}
}
]
vpnClientRevokedCertificates: []
radiusServers: []
vpnClientIpsecPolicies: []
}
bgpSettings: {
asn: 65515
bgpPeeringAddress: '10.2.255.126'
peerWeight: 0
bgpPeeringAddresses: [
{
ipconfigurationId: '${p2s_vpn_name_resource.id}/ipConfigurations/default'
customBgpIpAddresses: []
}
]
}
customRoutes: {
addressPrefixes: []
}
vpnGatewayGeneration: 'Generation1'
}
}
resource virtual_network_name_resource 'Microsoft.Network/virtualNetworks#2022-01-01' = {
name: virtual_network_name
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.2.0.0/16'
]
}
subnets: [
{
name: 'GatewaySubnet'
id: resourceId(rg, 'Microsoft.Network/virtualNetworks/subnets', virtual_network_name ,gwSubnetName)
properties: {
addressPrefix: '10.2.255.0/25'
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
type: 'Microsoft.Network/virtualNetworks/subnets'
}
{
name: 'p2s_subnet'
// id: virtual_network_name_p2s_subnet.id
id: resourceId(rg, 'Microsoft.Network/virtualNetworks/subnets', virtual_network_name ,p2s_subnet_name)
properties: {
addressPrefix: '10.1.1.0/24'
serviceEndpoints: []
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
type: 'Microsoft.Network/virtualNetworks/subnets'
}
]
virtualNetworkPeerings: []
enableDdosProtection: false
}
}
what have I done ?
I have tried to get around circular reference issues by creating the virtual network first, and referencing it using the example below.
instead of id: virtual_network_name_p2s_subnet.id I have changed it to
id: resourceId(rg, 'Microsoft.Network/virtualNetworks/subnets', virtual_network_name ,p2s_subnet_name)
However I'm unsure as to how to deal with cases like
ipconfigurationId: '${p2s_vpn_name_resource.id}/ipConfigurations/default' when the virtual networ gateway has not been created, I have no way of knowing what the ipconfigurationID would be.
This leads to the error
This expression is referencing its own declaration, which is not allowed.bicep(BCP079)
Few things here,
You're defining the subnets multiple times: in the vnet resource and separately. You only need to define them once inside the vnet resource. As you suggested you could then reference them like that:
resourceId(rg, 'Microsoft.Network/virtualNetworks/subnets', virtual_network_name_resource.name ,p2s_subnet_name)
If you need to reference the same resource, you could always do it like that as well:
resourceId('Microsoft.Network/virtualNetworkGateways/ipConfigurations', p2s_vpn_name, 'default')
Here is is simplified version of your template:
param location string = resourceGroup().location
param virtual_network_name string = 'my_virtual_network'
param gwSubnetName string = 'myGatewaySubnet'
param public_ip_gateway string = 'my_public_ip'
param p2s_vpn_name string = 'myPoint_toSite'
param p2s_subnet_name string = 'p2s_subnet'
resource public_ip_gateway_resource 'Microsoft.Network/publicIPAddresses#2022-01-01' = {
name: public_ip_gateway
location: location
sku: {
name: 'Basic'
tier: 'Regional'
}
properties: {
ipAddress: '40.161.130.50'
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Dynamic'
idleTimeoutInMinutes: 4
ipTags: []
}
}
resource virtual_network_resource 'Microsoft.Network/virtualNetworks#2022-01-01' = {
name: virtual_network_name
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.2.0.0/16'
]
}
subnets: [
{
name: gwSubnetName
properties: {
addressPrefix: '10.2.255.0/25'
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
type: 'Microsoft.Network/virtualNetworks/subnets'
}
{
name: p2s_subnet_name
properties: {
addressPrefix: '10.1.1.0/24'
serviceEndpoints: []
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
type: 'Microsoft.Network/virtualNetworks/subnets'
}
]
virtualNetworkPeerings: []
enableDdosProtection: false
}
}
resource p2s_vpn_name_resource 'Microsoft.Network/virtualNetworkGateways#2022-01-01' = {
name: p2s_vpn_name
location: location
properties: {
enablePrivateIpAddress: false
ipConfigurations: [
{
name: 'default'
properties: {
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
id: public_ip_gateway_resource.id
}
subnet: {
id: resourceId('Microsoft.Network/virtualNetworks/subnets', virtual_network_resource.name, gwSubnetName)
}
}
}
]
natRules: []
enableBgpRouteTranslationForNat: false
disableIPSecReplayProtection: false
sku: {
name: 'VpnGw1'
tier: 'VpnGw1'
}
gatewayType: 'Vpn'
vpnType: 'RouteBased'
enableBgp: false
activeActive: false
vpnClientConfiguration: {
vpnClientAddressPool: {
addressPrefixes: [
'119.x.x.0/24'
]
}
vpnClientProtocols: [
'OpenVPN'
]
vpnAuthenticationTypes: [
'Certificate'
]
vpnClientRootCertificates: [
{
name: 'Rahman'
properties: {
publicCertData: 'xxxxxxxxxxx=='
}
}
]
vpnClientRevokedCertificates: []
radiusServers: []
vpnClientIpsecPolicies: []
}
bgpSettings: {
asn: 65515
bgpPeeringAddress: '10.2.255.126'
peerWeight: 0
bgpPeeringAddresses: [
{
ipconfigurationId: resourceId('Microsoft.Network/virtualNetworkGateways/ipConfigurations', p2s_vpn_name, 'default')
customBgpIpAddresses: []
}
]
}
customRoutes: {
addressPrefixes: []
}
vpnGatewayGeneration: 'Generation1'
}
}

Azure Dashboard template for App Service Plan

I woudl like to create a Azure Dashboard template to monitor CPU percentage for my App Service Plan. Currently It look like this:
resource dashboardName_resource 'Microsoft.Portal/dashboards#2020-09-01-preview' = {
name: dashboardName
location: location
properties: {
lenses: [
{
order: 0
parts: [
{
position: {
x: 0
y: 4
rowSpan: 3
colSpan: 11
}
metadata: {
inputs: [
{
name: 'queryInputs'
value: {
timespan: {
duration: 'PT1H'
}
id: resourceId(appServicePlanResourceGroup, 'Microsoft.Web/serverfarms', appServicePlanName)
chartType: 0
metrics: [
{
name: 'CPU Percentage'
resourceId: resourceId(appServicePlanResourceGroup, 'Microsoft.Web/serverfarms', appServicePlanName)
}
]
}
}
]
type: 'Extension/Microsoft_Azure_Monitoring/PartType/MetricsChartPart'
}
}
]
}
]
}
}
The validation & deployment was succesfull, but when I get to this dashboard i got this:
Does anyon knows why?
By referring a document from MS sample replica of your bicep code is created and was able to deploy it successfully.
While I am doing a repro, I have changed type extension in .bicep file fromtype:'Extension/Microsoft_Azure_Monitoring/PartType/MetricsChartPart to type:'Extension/HubsExtension/PartType/MonitorChartPart' which got succeeded and able to view the CPU metrics.
Attaching a sample code for your reference:
param location string = resourceGroup().location
param appServicePlanResourceGroup string = 'xxxxx'
param appServicePlanName string = 'xxxxxxx'
resource symbolicname 'Microsoft.Portal/dashboards#2020-09-01-preview' = {
name: 'xxxxmydemo'
location: location
tags: {
demo: 'repro01'
}
properties: {
lenses: [
{
metadata: {}
order: 2
parts: [
{
metadata: {
type: 'Extension/HubsExtension/PartType/MonitorChartPart'
inputs: [
{
name: 'queryInputs'
value: {
timespan: {
duration: 'PT1H'
}
id: resourceId(appServicePlanResourceGroup, 'Microsoft.Web/serverfarms', appServicePlanName)
chartType: 0
metrics: [
{
name: 'CPU Percentage'
resourceId: resourceId(appServicePlanResourceGroup, 'Microsoft.Web/serverfarms', appServicePlanName)
}
]
}
}
]
}
position: {
colSpan: 11
metadata: {}
rowSpan: 5
x: 3
y: 4
}
}
]
}
]
metadata: {}
}
}
Output for your reference:
Note: Validate access control(IAM) permissions for the resource group ideally and it should be part of it.

How to populate Azure SignalR Service's upstream code in Bicep

I have a Bicep template to create an Azure SignalR Service per the following script. How can I obtain the upstream's code value within the bicep template and populate the urlTemplate's code value based on it? (the keyword TBD exhibits the exact spot in the following code.)
targetScope = 'resourceGroup'
param location string = resourceGroup().location
param signalRName string
resource signalR 'Microsoft.SignalRService/signalR#2022-02-01' = {
name: signalRName
location: location
kind: 'SignalR'
sku: {
name: 'Free_F1'
tier: 'Free'
capacity: 1
}
properties: {
features: [
{
flag: 'ServiceMode'
value: 'Serverless'
}
{
flag: 'EnableConnectivityLogs'
value: 'true'
}
{
flag: 'EnableMessagingLogs'
value: 'true'
}
{
flag: 'EnableLiveTrace'
value: 'true'
}
]
liveTraceConfiguration: {
enabled: 'true'
categories: [
{
name: 'ConnectivityLogs'
enabled: 'true'
}
{
name: 'MessagingLogs'
enabled: 'true'
}
{
name: 'HttpRequestLogs'
enabled: 'true'
}
]
}
cors: {
allowedOrigins: [
'*'
]
}
upstream: {
templates: [
{
hubPattern: '*'
eventPattern: '*'
categoryPattern: '*'
auth: {
type: 'None'
}
urlTemplate: 'https://${signalRName}.azurewebsites.net/runtime/webhooks/signalr?code=TBD'
}
]
}
}
}
I'm assuming that you are using a function app that has the same name as your signalR service.
Looking at the documentation:
The url always looks like that <Function_App_URL>/runtime/webhooks/signalr?code=<API_KEY>
the API_KEY is a function app systemkey called signalr_extension.
So you should be able to retrieve the key and use it like that:
var signalRKey = listKeys(resourceId('Microsoft.Web/sites/host', signalRName, 'default'), '2022-03-01').systemkeys.signalr_extension
resource signalR 'Microsoft.SignalRService/signalR#2022-02-01' = {
name: signalRName
...
properties: {
...
upstream: {
templates: [
{
...
urlTemplate: 'https://${signalRName}.azurewebsites.net/runtime/webhooks/signalr?code=${signalRKey}'
}
]
}
}
}

How to filter children in tree structure in Tabulator?

I tried callingsetFilter function on my Tabulator tree structure, in order to filter out items. It seems to only filter out top parents. Any idea how to make this work for any level (any children or parents)? http://tabulator.info/docs/4.1/tree doesn't say much about how filtering works.
Function
table.setFilter('id', '=', 214659) is not returning anything...
Tree structure
[
{
"level":0,
"name":"word1",
"id":125582,
"_children":[
{
"level":1,
"name":"word6",
"id":214659
},
{
"level":1,
"name":"word7",
"id":214633
},
{
"level":1,
"name":"word2",
"id":214263,
"_children":[
{
"level":2,
"name":"word8",
"id":131673
},
{
"level":2,
"name":"word9",
"id":125579
},
{
"level":2,
"name":"word10",
"id":125578
},
{
"level":2,
"name":"word4",
"id":172670,
"_children":[
{
"level":3,
"name":"word13",
"id":172669
},
{
"level":3,
"name":"word14",
"id":174777
},
{
"level":3,
"name":"word5",
"id":207661,
"_children":[
{
"level":4,
"name":"word15",
"id":216529
},
{
"level":4,
"name":"word16",
"id":223884,
"_children":[
{
"level":5,
"name":"word17",
"id":223885,
"_children":[
{
"level":6,
"name":"word18",
"id":229186,
"_children":[
{
"level":7,
"name":"word19",
"id":219062
},
{
"level":7,
"name":"word20",
"id":222243
}
]
}
]
}
]
}
]
}
]
},
{
"level":2,
"name":"word3",
"id":214266,
"_children":[
{
"level":3,
"name":"word11",
"id":216675
},
{
"level":3,
"name":"word12",
"id":216671
}
]
}
]
}
]
}
]
After a little searching found out an extension for lodash library called deepdash which has deep level filtering and it works quite well.
You will have 2 new dependencies but I think it will serve your purpose.
Check the documentation on how to install them here
In the snippet here you can see in the log the results. I made a sandbox also here
This is for a list of ids, one or more.
If you need only for one value change the conditional. return _.indexOf(idList, value.id) !== -1; to return id===value.id; where id is your id variable
Also after looking at the documentation from Tabulator, the have only one level filtering, even if you write your own custom filter it wouldn't help, because it expects a bool value to render the row or not. But only for the first level, so if the parent is not what you look for the child will be ignored. The only option for you is to filter the data outside the Tabulator.
const data = [
{
level: 0,
name: "word1",
id: 125582,
_children: [
{
level: 1,
name: "word6",
id: 214659
},
{
level: 1,
name: "word7",
id: 214633
},
{
level: 1,
name: "word2",
id: 214263,
_children: [
{
level: 2,
name: "word8",
id: 131673
},
{
level: 2,
name: "word9",
id: 125579
},
{
level: 2,
name: "word10",
id: 125578
},
{
level: 2,
name: "word4",
id: 172670,
_children: [
{
level: 3,
name: "word13",
id: 172669
},
{
level: 3,
name: "word14",
id: 174777
},
{
level: 3,
name: "word5",
id: 207661,
_children: [
{
level: 4,
name: "word15",
id: 216529
},
{
level: 4,
name: "word16",
id: 223884,
_children: [
{
level: 5,
name: "word17",
id: 223885,
_children: [
{
level: 6,
name: "word18",
id: 229186,
_children: [
{
level: 7,
name: "word19",
id: 219062
},
{
level: 7,
name: "word20",
id: 222243
}
]
}
]
}
]
}
]
}
]
},
{
level: 2,
name: "word3",
id: 214266,
_children: [
{
level: 3,
name: "word11",
id: 216675
},
{
level: 3,
name: "word12",
id: 216671
}
]
}
]
}
]
}
];
const idList = [214659];
const found = _.filterDeep(
data,
function(value) {
return _.indexOf(idList, value.id) !== -1;
},
{ tree: true, childrenPath: '_children' }
);
console.log(found);
<script src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/deepdash/browser/deepdash.min.js"></script>
<script>
deepdash(_);
</script>
Here is a recursive function that will find the parent and/or children matching a condition.
In this example, the parent item will always be displayed if a child item is a match - even if the parent itself is not a match - but you can easily adjust the code to your needs by tuning the test in the for loop.
var filterTree = function (data, filter) {
if (data['_children'] && data['_children'].length > 0) {
for (var i in data['_children']) {
return data[filter.field] == filter.value || filterTree(data['_children'][i], filter);
}
}
return data[filter.field] == filter.value;
};
Call this function as a custom filter callback:
table.setFilter(filterTree, {field:'myfield', type:'=', value:'myvalue'});
Note that this is just example code that focuses on the logic of filtering a tree recursively. The above works only for the '=' comparison.
In a real situation, you will have to implement more code to handle all other operators supported by tabulator, as dynamic operator assignment is not possible in Javascript. You could maybe consider eval() but that's another story.
More info about dynamic operator assignment here:
Are Variable Operators Possible?
Here is an example of implementation handling all tabulator operators:
// Operators
var compare = {
'=': function(a, b) { return a == b },
'<': function(a, b) { return a < b },
'<=': function(a, b) { return a <= b },
'>': function(a, b) { return a > b },
'>=': function(a, b) { return a >= b },
'!=': function(a, b) { return a != b },
'like': function(a, b) { return a.includes(b)}
};
// Filter function
var filterTree = function (data, filter) {
if (data['_children'] && data['_children'].length > 0) {
for (var i in data['_children']) {
return compare[filter.type](data[filter.field], filter.value) || filterTree(data['_children'][i], filter);
}
}
return compare[filter.type](data[filter.field], filter.value);
};
// Set a filter. The operator can now be provided dynamically
table.setFilter(filterTree, {field:'myfield', type: '>=', value:'myvalue'});

Resources