Setting Filters from Code

  • 1
  • Question
  • Updated 5 years ago
  • Answered
  • (Edited)
How can I manually invoke a filter/condition? Take a look at this page: http://www.biadev.com/directory My goal here is to hard code the links into the custom menu I built on the left. I thought about using tabset but changed to this, the thinking there being less tabs, less tables, less page load strain this way. But anyways, how can communicate with filters directly? Can I add it in the url or if there's JS for this could you get me started?

Cheers,
Photo of Ryan Rawls

Ryan Rawls

  • 242 Points 100 badge 2x thumb

Posted 5 years ago

  • 1
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Hi Ryan,

Yes, it is possible to manipulate Conditions through the Skuid Model API, which is the gateway to Condition manipulation. "Filters" are user interface components for manipulating Conditions, and whenever a Model's data is refreshed using the updateData() method on a Model, Filters are rebuilt and rendered appropriately based on the current state of the Conditions they interact with.

Essentially there are 3 Model prototype methods you can use for interacting with the Conditions on a particular model:

- setCondition(condition,value)
- activateCondition(condition)
- deactivateCondition(condition)

where "condition" is a Condition object obtained by using the following API method:

- getConditionByName(name)

In order to "register" Conditions with Skuid, you'll need to set their State to "Filterable, Default Off" or "Filterable, Default On", and give them a unique Name.

So, as an example, say we have a list of Accounts tied to a Model called "MyAccountsModel". We have one Condition in our Model, named "Industry", that's on the Industry field, set to Filterable Default Off.

Then, we have 3 Toggle Filters on our Accounts table, one that sets the value of the Industry condition to "Retail", another that sets it to "Electronics", and another that Deactivates the Industry Condition entirely, called "All Industry":



If you wanted to replicate the functionality of these 3 Filters in your sidebar component, you would need to have the following JavaScript executed for each of the "filter" items in your sidebar:

1. Retail item:



var accModel = skuid.model.getModel('MyAccountsModel');
var industryCondition = accModel.getConditionByName('Industry');
accModel.setCondition(industryCondition,'Retail');
accModel.updateData();


2. Electronics item:



var accModel = skuid.model.getModel('MyAccountsModel');
var industryCondition = accModel.getConditionByName('Industry');
accModel.setCondition(industryCondition,'Electronics');
accModel.updateData();


3. Any Industry item:



var accModel = skuid.model.getModel('MyAccountsModel');
var industryCondition = accModel.getConditionByName('Industry');
accModel.deactivateCondition(industryCondition);
accModel.updateData();


The condition activation/deactivation logic can get more complex as your Conditions increase in complexity, but this API should enable you to achieve what you're after.

When Filter Items have multiple effects, you'll need to ensure that you're deactivating / activating Conditions that may conflict, as appropriate. For instance, if instead of reusing a single "Industry" condition, you had created 2 separate Conditions, e.g.

"IndustryEqualsRetail": (Industry = 'Retail')
"IndustryEqualsElectronics": (Industry = 'Electronics')

each of your Filters would have needed to have 2 Effects:

1. Retail filter:
-Activate IndustryEqualsRetail
-Deactivate IndustryEqualsElectronics

2. Electronics filter:
-Activate IndustryEqualsElectronics
-Deactivate IndustryEqualsRetail

3. Any Industry filter:
-Deactivate IndustryEqualsElectronics
-Deactivate IndustryEqualsRetail

and your JavaScript logic would need to do the same.
Photo of Ryan Rawls

Ryan Rawls

  • 242 Points 100 badge 2x thumb
Zach, Thank you very much for taking the time for this detailed response. I'm digesting every bit of it.
Photo of Ryan Rawls

Ryan Rawls

  • 242 Points 100 badge 2x thumb
Zach, I'm looking over the model api documentation page and it doesnt seem like it's there but I just want to confirm: Does the api have a function that can will deactivate all conditions in one go? If not I'll build the function that toggles them all off, just thought I'd check tho first.
Photo of Ryan Rawls

Ryan Rawls

  • 242 Points 100 badge 2x thumb
Scratch that last question, I was using activateCondition where I should've been using setCondition, which changed the logic a great deal. I see now that the code for "Any Industry Item" is my reset/clear all function.
Photo of Ryan Rawls

Ryan Rawls

  • 242 Points 100 badge 2x thumb
Hi Zach, Progress made. Following your steps I have it all working as far as updating data based on the right condition. You can view it here: http://www.biadev.com/directory

Now I'm just working on making some post-page-refresh changes to my custom page title that holds the id="protitle". Where I'm stuck on this is in using the callback capability with updateData() to store the element id of the link originally clicked so that I can use it in my post-refresh functions to do things like update value of pagetitle and addClass() to active menu item.

For reference value, here's the single function I use to handle condition changes for all menu links. As you can see I used JQuery to help consolidate the task. With this, I just have to apply the class ".mycatlink" to all menu links.

jQuery(document).ready(function($){
$('.mycatlink').click(function() {
var prof = $(this).attr('name');
var catid = $(this).attr('id');
var cattitle = $(this).attr('title');
var proModel = skuid.model.getModel('Pros');
var proCondition = proModel.getConditionByName('ProType');
proModel.setCondition(proCondition, prof);
proModel.updateData(mycallback(catid,cattitle));
});
});

And here's my function to run after page refresh.

function mycallback() {
jQuery(document).ready(function($){
$(catid).addClass('myactive');
$('#protitle').text(cattitle);
});
}

Let me end with this. My JS/JQuery coding skills are fairly rusty, so I may very well be missing something fundamental here, but if so it's with how I'm using updateData, cause all other parts of the function work.
Photo of Ben Hubbard

Ben Hubbard, Employee

  • 12,490 Points 10k badge 2x thumb
I think your callback function needs to declare its parameters like this...


function mycallback(catid,cattitle) {
Photo of Ryan Rawls

Ryan Rawls

  • 242 Points 100 badge 2x thumb
I actually looked at your response and thought "ok yea that looks right.......now what did I paste?" Checked my inline code and I have the function set with the two parameters like you pasted. Not sure where I pasted mine from, there's a lot of notepad pasting going on when I piece these together, but at any rate, that function's in there like that.
Photo of Ben Hubbard

Ben Hubbard, Employee

  • 12,490 Points 10k badge 2x thumb
Ok, I looked at it again. You're passing the return result of mycallback into updatedata, not the actual function. Probably the easiest way to fix this would be to use an anonymous function. Either of these should work.



proModel.updateData(function() {
mycallback(catid,cattitle);
});





proModel.updateData(function(){
catid.addClass('myactive');
$('#protitle').text(cattitle);
});


Also, since this function is in a callback, there's really no need I can think of for the jQuery ready wrapper there.
Photo of Ryan Rawls

Ryan Rawls

  • 242 Points 100 badge 2x thumb
Thanks Ben and Success, well, 90% the way there anyways. Using your first function (the second one wouldn't set the title) it works, but only if it's the first link you click, and it only will execute once. If you try to use it again, nothing happens.

You can see it in action: http://biadev.com/directory Just click "Architect", all the other links are using a deprecated function I started with but will switch to this one once its ironed out. If you click Architect (as your very first click) it works, if you click another link before it, it won't. Curious.

My first suspect was that somehow the main reference element (.mycatlink class) was being stripped after the callback (which would explain the one time behavior anyways), but upon inspection after clicking it, that value remains intact. Do you have any ideas or suggestions? Thank you for the help thus far.
Photo of Ryan Rawls

Ryan Rawls

  • 242 Points 100 badge 2x thumb
As for the jQuery wrapper I tried removing but it threw errors so I kept it and here's my updated code:


jQuery(document).ready(function($){
$('.mycatlink').click(function() {
var prof = $(this).attr('name');
var catid = $(this).attr('id');
var cattitle = $(this).attr('title');
var proModel = skuid.model.getModel('Pros');
var proCondition = proModel.getConditionByName('ProType');
proModel.setCondition(proCondition, prof);
proModel.updateData(function() {
mycallback(catid,cattitle);
});
});
});

function mycallback(catid,cattitle) {
jQuery(document).ready(function($){
$('#'+catid).addClass('myactive');
$('#protitle').text(cattitle);
});
}
Photo of Glenn Elliott

Glenn Elliott, Champion

  • 7,738 Points 5k badge 2x thumb
This is a great topic and I've implemented this code with near success, but I think I've faced the same issue as Ryan.

Like Ryan's example, I have a left side nav bar with links that filter a table on the right. I click the first link and the filter works, but any subsequent click does nothing. It doesn't matter which link I click, it's just the first one that works and every subsequent click does nothing. Weird.

My code looks like this, and I call it by defining the class of the HTML element:
jQuery(document).ready(function($){
$('.applyclientfilter').click(function() {
var clientModel = skuid.model.getModel('Clients');
var clientCondition = clientModel.getConditionByName('mmfp__status__c');
clientModel.setCondition(clientCondition,'Client');
clientModel.updateData();
});
$('.applyprospectfilter').click(function() {
var prospectModel = skuid.model.getModel('Clients');
var prospectCondition = prospectModel.getConditionByName('mmfp__status__c');
prospectModel.setCondition(prospectCondition,'Prospect');
prospectModel.updateData();
});
});