Since individual filters cannot be conditionally rendered, we have a page with multiple filter sets. There’s a basic set that are always there, but additional filtersets might show with different critieria. When a filter is applied, it can affect as many as 43 different models, so it can take a little bit of time. So, we are not applying filters immediately in case a user wants to apply multiple filters - when they hit apply there’s a few seconds of wait time.
However, with multiple filter sets, we can have multiple Apply/Cancel buttons. I can target these buttons to hide using display:none - but is there any code that will Apply filters from multiple filter sets at one time?
Hey there, Jack! I have two questions:
- Are you on version 11.2 or higher?
- Could you provide some details as to the need to affect up to 43 models?
Yes on 11.2.9
It’s a little complicated but I’ll try and explain - we have a “scorecard” which is a table of Parent Object, each column is a period of time, and the values in the cells are the average or sum (depending on a user’s setting for each Parent Object) of a child object for a given time period. The user can choose to show up to 25 months plus up to 13 quarters plus yearly rollups of 2018 through 2015 plus the Last 13 months rolling. So 43 models, all aggregate.
Note that all the months and quarters are dynamically created via snippets, so they are only on the page if the user has settings that necessitate those.
The filters are actually on a separate FilterModel, and there’s a snippet that when the filter model is requeried, it checks each filter on the filter model and activates and sets values or deactivates the same conditions on each of the 43 models, then requeries those, which is querying up to 43 aggregate models.
Thanks for responding Javid, and I’m interested in your initial idea, even if you don’t think it will work, maybe it will point to something I haven’t thought of!
Hey Jack! Apologies on my apparent hiatus from this thread...
Sounds like a pretty complicated page! I had originally asked what version you were on to make sure you could use Action Sequences. I've been using these like crazy in our internal projects, and in some pretty powerful ways. These have also made complex pages easier to understand and even easier to update later.
Action Sequences
The three things that keep me going back to Action Sequences every day include:
They are reusable.
They can be generalized using Input Parameters.
They can be triggered by events.
Triggering sequences by events is optional here, but this is really helpful when communicating between pages and their Page Includes, so I'll skip it in this post.
At first, I can build an Action Sequence to fit one or more specific use cases, like setting conditions or querying models. After finding patterns, I can use the Input Parameters to generalize the sequence (such as which model, model's condition, or value is passed into a particular part of the sequence).
In your case, I think you can convert much of that Javascript one or more Action Sequences with Inputs. I’ll explain below. Javascript snippets will be necessary if you have situations where you need to transform your data values to service a following next step.
Thought Process
You have a complex filter situation. A single Filter Set hasn't been able to solve your problem, nor will it - different fields need to be filtered on many different models and you need them to query at the same time once you have your filter values. Is there a way to build a custom filter set component in Skuid with components I have right now?
Of course! There are two big steps involved:
Building a Custom Filter Set
Defining Generalized Action Sequences
Building a Custom Filter Set
Build a UI-Only model that will be dedicated to holding your filter values. I usually call mine "UIFilter".
The UIFilter model needs one field defined per available filter value in your current Filter Sets - I'm seeing 22 in your screenshot, (BMI, Pediatrics, Multi-Organ, etc). Each of these fields needs to match the field data type.
Now, each of these fields should be defined in such a way to provide filter values for the user. You can provide lists by defining some fields as References to other objects, Model-supplied Picklists, or Manually-defined Picklists.
Once you have these, it's time to build your custom "Filter". Expose the UIFilter model's fields with a Field Editor component. Configure each Reference field to display as a Picklist if you wish, and configure the component to always be in Edit mode.
Great! Now you have the shell of a Custom Filter Set!
Next, we'll give it a brain!
Setting Up the First-Level Action Sequences
Look at all your different models and their conditions. Can you find a pattern? Which model conditions are always activated in the same way? Which models are provided the same value(s) in the JS you have now?
This might be the most difficult part, but it's incredibly worthwhile to find these patterns if you haven't already. Patterns should be found on models that have similar conditions, and it’s more likely that these will crop up in models using the same Object. You might find something like the following:
Pattern A - StartDateCondition, EndDateCondition, AccountTypeCondition
Pattern B - BeforeDateCondition, AccountTypeCondition
Pattern C - BeforeDateCondition, OpportunityStageCondition, OpportunityTypeCondition
Once you have identified any patterns in your models and their conditions, do the following for each pattern:
1. Build an Action Sequence called "Set & Activate Model Conditions - (pattern name)" that does the following:
Has a "model" Input defined
Has "model condition" Inputs defined for each similar condition in the current pattern
Has "value" Inputs defined for each of the condition Inputs you just created
Here's an example in one of our pages:
2. Set the first action to deactivate all filterable conditions on the input model.
3. Create one Branch action per model condition. The Branch will check if the input value respective to the model condition has been provided (is not blank when given to the Action Sequence), using this Formula:
{{$Input.YourInputValueName}} != null && {{$Input.YourInputValueName}} != “”
If the value was not provided, it will have already been deactivated in the very first step.
Make sure you have “Continue with the next action” set for “After running the branch”, or else none of this will work!
4. In each Branch action, Activate & Set Model Condition for that condition. If the filter value is provided, pass this value to the model condition.
This is what one Action Sequence will look like for a given model condition pattern with four similar conditions:
Setting Up the Second-Level Action Sequences
I know, this may seem like overkill, but stay with me! Now that we have the first-level action sequences defined for all model condition patterns, we are going to make use of the UIFilter model fields.
1. Create another Action Sequence named “Prepare Models”. For each of the models on which you will need to filter, add one of the respective “Set & Activate” action sequences to this new action sequence. Add a descriptive “On-Error” action to each action sequence to make debugging easier.
2. Use Global Merge Syntax to provide UIFilter values for all inputs in each of the action sequences.
Finishing Up!
At this point you have a Custom Filter Set in your UI, and you have just built the brains for it to set the filter conditions correctly using Action Sequences and their Inputs. This alone is an accomplishment, but it was all for nothing if your users can’t filter!
1. Create a button labelled “Apply”.
2. Add the Action Sequence “Prepare Models”
3. Add a final “Query Models”, selecting all 43 of your models involved.
4. Filter away!
The idea is that your users will interact with the Field Editor component that manipulates the UIFilter model. After these values are updated, they are available for the action sequences you've defined that will 1) accept the model values as parameters and 2) set the conditions accordingly (if needed). All you need to do at this point is "Prepare Models" then query for a refresh of all values.
Jack, let me know if this method will work for your use case. I've found this to be a successful Skuid development pattern in multiple places, and I'm hoping it works well in your page too! I'd be happy to go into more detail wherever necessary.
That’s pretty amazing! Great idea. And I can easily conditionally render each of the fields used to a drive a filter - in essence getting to the ability to conditionally render an individual filter.
It’s a LOT of work though - 43 models and 22 conditions each. Yes there are patterns, but the javascript snippet is so simple - check one model for all active conditions, then for each of the 43 models activate/deactivate the same conditions. I never need to specifically reference any single condition, so if I add or subtract filters or conditions, that snippet doesn’t change a bit.
But using the UImodel to offer filter options in a field editor is really cool. I think I can use that to set the conditions on my on FilterModel, then continue to use my snippet to set the conditions on all the relevant models.
I’ll reach back out if I run into issues implementing a version of this. I love action sequences and continue to use them more and more, but sometimes a snippet is just the easiest solution. And faster I think too, since I can store in a cached static resource, vs. all the lines of xml created for so many actions…
There’s definitely truth in that! I come from a coding background myself, but it’s always fun to find the Skuid method of doing things. It’s also much easier for non-coders to pick up what’s happening in the page!
Hope this is useful for you somewhere down the road!
Reply
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.