<p>Okay, please don't be afraid and give it a try. I'm using the angular way, it seems a little bit difficult but it's actually really easy once you get used to it and works perfectly as soon as you understand it a little bit. If you need changes I'll provide whatever you need.<br>
<strong>Edit</strong>: here you can see a live example for it <a href="https://plnkr.co/edit/uqIupfOslx7qWMedoiBE?p=preview" rel="nofollow noreferrer">plunker</a> or course without css but it is your html</p>

<p>Let's get into it.
For testing purposes I created this category structure in my backend and called the group <code>filter</code>.
<a href="https://i.sstatic.net/QAVVY.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/QAVVY.png" alt="enter image description here"></a></p>

<p>First you need to include this library you can of course use the <code>{% includeJsRessource %}</code> as well</p>

<pre><code>&lt;script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"&gt;&lt;/script&gt;
</code></pre>

<p>Then you create 2 javascript arrays one for the Culture, Democracy... I call them parents and one for their children that belong to them</p>

<pre><code>// get all filters of the first level
{% set filters = craft.categories.group('filter').level(1).find() %}
&lt;script type="text/javascript"&gt;
    var children = [];
    var parents = [];
    {% for filter in filters %}
        parents.push({
            title: "{{ filter.title }}",
            id: "{{ filter.id }}"
        });
        // now fetch all children for them
        {% set children = craft.categories.group('filter').descendantOf(filter).level(2).find() %}
        {% for child in children %}
            children.push({
                title: "{{ child.title }}",
                id: "{{ child.id }}",
                parent: "{{ filter.id }}"
            });
        {% endfor %}
    {% endfor %}
&lt;/script&gt;
</code></pre>

<p>In the end you'll have 2 array that could look like<a href="https://i.sstatic.net/5qnGf.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/5qnGf.png" alt="enter image description here"></a></p>

<p>Now the funny part starts
include this javascript file. You can ask whatever you want I'll explain it. Even if the syntax and everything what's going on seems a little bit strange, but make sure this is loaded <strong>after</strong> the library from above</p>

<pre><code>var  myApp = angular.module('myApp',[]).config(function($interpolateProvider) {
    $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
});

myApp.controller('filterController', ['$scope', function ($scope) {
    // all parents
    $scope.parents = parents;
    // all children
    $scope.children = children;

    // return if the parent is selected or not
    $scope.filterBySelectedParent = function (item) {
        return $scope.selectedParents.indexOf(item.parent) !== -1;
    };

    // an array with all selected parent ids
    $scope.selectedParents = [];

    // include an item to the array or slice it when the input it clicked
    $scope.addFilter = function(id){
        var index = $scope.selectedParents.indexOf(id);
        if(index === -1){
            $scope.selectedParents.push(id);
        }else{
            $scope.selectedParents.splice(index, 1);
        }
    }
}]);
</code></pre>

<p>And finally your new html</p>

<pre><code>&lt;!-- this is your menu or your filter bar or whatever you want to call it --&gt;
&lt;!-- I inspected your html and tried to use that but you must include ng-app and ng-controller somewhere --&gt;
&lt;div ng-app="myApp" ng-controller="filterController"&gt;
    &lt;!-- your first ul... all your parents, the first filter in your page --&gt;
    &lt;ul&gt;
        &lt;li ng-repeat="filter in parents"&gt;
            &lt;label class=""&gt;
                &lt;input type="checkbox" ng-click="addFilter(filter.id);" value="{[{filter.id}]}"&gt;&lt;span&gt;{[{ filter.title }]}&lt;/span&gt;
            &lt;/label&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;!-- all your children, the second filter in your page --&gt;
    &lt;ul&gt;
        &lt;li class="" ng-repeat="child in children | filter: filterBySelectedParent"&gt;
            &lt;label class="" &gt;
                &lt;input type="checkbox" data-name="selectItemfocusArea" value="{[{ child.id }]}"&gt;&lt;span&gt;{[{ child.title }]}&lt;/span&gt;
            &lt;/label&gt;
        &lt;/li&gt;
    &lt;/ul&gt;

    &lt;!-- include the rest here --&gt;
&lt;/div&gt;
</code></pre>

<p>Explanation: so what actually happens is the following </p>

<ol>
<li>you create 2 arrays in javascript based on your backend inputs</li>
<li>angular renders your menu based on those two arrays but the second one has a filter. Only clicked items of the first array are shown</li>
<li>as soon as someone clicks on an filter it is included in an array <code>$scope.selectedParents</code> </li>
<li>any change in this array is recognized automatically which results, that the html renders again => your other filters are shown.</li>
</ol>

<p>Please tell me if I missunderstood you somehow.. based on my current state I can change nearly everything really easily in just a few clicks. For example if you would like to automatically select your children you would include <code>ng-checked="filterBySelectedParent(child)"</code> on your input and remove the <code>| filter: filterBySelectedParent</code>.. that's it</p>

CC BY-SA 3.0
2017-12-09T02:08:10.720Z
Thanks for this solution!  As for the HTML, it's actually possible to just add the options to the select box and it gets generated into that ul/li list with labels with a plugin I'm using to create the multi-checkbox functionality.  I will try out your method though and let you know how it goes!
user5824
CC BY-SA 3.0
2017-12-09T02:17:47.830Z
Ah okay sry I thought it was your work. My solution has definitely disadvantages, for example you have to get used to the new methods but from my experience (and everyone else will say the same who uses angular) for searching/filtering and filter that depends other filters and all these kind of things this method is perfect because you don't have to care about the html since angular does everything for you and of course it boosts your performance compared to php or jquery. Anyway I wish you good luck
Robin Schambach
CC BY-SA 3.0
2017-12-13T02:37:41.270Z
Hi Robin, thanks for much for the help.  I've made a test page to test your solution and it's not quite working: http://www.joycefdn.org/grantsDB
I tried to convert the HTML to the select boxes that I need and it doesn't work when I apply the multiple select option plugin to the selects, in that case, the secondary select box does not fill in at all.  Also, I need the values of the select boxes to still be the titles of the categories because that's how the filtering works.  Any help would be greatly appreciated!!
user5824
CC BY-SA 3.0
2017-12-13T02:41:18.763Z
This is how I tried to edit it:
<div ng-app="myApp" ng-controller="filterController">
<select id="program" name="program" multiple="multiple">
<option value="" selected>Program</option>
<option ng-repeat="filter in parents" ng-click="addFilter(filter.id);" value="{[{filter.id}]}">{[{ filter.title }]}</option>
</select>
<select id="focusArea" name="focusArea" multiple="multiple">
<option class="" ng-repeat="child in children | filter: filterBySelectedParent"><span data-name="selectItemfocusArea" value="{[{ child.id }]}">{[{ child.title }]}</span>
</option>
</select>
</div>
user5824
CC BY-SA 3.0
2017-12-13T03:08:25.490Z
I'm so sorry, I'm really new to Stack Exchange, I think I forgot to tag you... @robin-schambach
user5824
CC BY-SA 3.0
2017-12-13T05:11:18.953Z
It actually works but you hide the real select with all functionality and show the useless jquery select with no functionality instead. By the way: best practice would be to create all your filters that way, so you have multiple Arrays with all filters, in order to display the entries by your arrays. If you want I could do it for you. It makes everything much easier and smoother. I tried to accomplish such a thing with jquery in the past too. But it becomes a pain sooner or later
Robin Schambach
CC BY-SA 3.0
2017-12-13T05:34:10.340Z
I think that is the same reason why your previous code did not work either. Your code may have been correct but you did not activate your functions for the jquery filter, only for you own but you hide it and never use it
Robin Schambach
CC BY-SA 3.0
2017-12-13T18:23:11.603Z
I'm not sure what you mean, do you mean I could use Angular to make the multi-select options in the select boxes instead of the jQuery plugin? The other filters don't really need to cascade on each other like the Program and Focus Area ones so I'm only using jQuery to make them multi-selects, also for your code, is there a way to make them cascade on each other without using "value" since that's how the filters display the entries?  Thanks!!
user5824
CC BY-SA 3.0
2017-12-13T18:28:35.130Z
It's not that you could to it, you should use only angular or another jquery plugin, since the one you use is not able to sync properly. The value attribute does not matter, you can leave it if you don't want to use the real strength of the script and of course if you don't want to avoid trouble sooner or later because of jquery. As soon as you have more entries and reach a certain limit or if you want to include more filters it is going to be mess
Robin Schambach
CC BY-SA 3.0
2017-12-13T19:05:23.427Z
ohhh, I see what you mean.  I see it working in my test page now, I just have to reconcile how it filters the entries now and style it.  Does it seem right to you??  Thanks!
user5824
CC BY-SA 3.0
2017-12-13T19:08:46.580Z
That's one way you could do it
Robin Schambach
CC BY-SA 3.0
2017-12-09T01:05:37.030Z
2017-12-09T01:30:49.183Z
2017-12-09T01:30:49.183Z
Robin Schambach
<p>I have a question about combining Twig and jQuery in Craft. I have a couple of filters on a page that outputs some entries:
<a href="http://www.joycefdn.org/grants" rel="nofollow noreferrer">http://www.joycefdn.org/grants</a></p>

<p>My categories are organized like this:
Education and Economic Mobility
 - Educator Quality 
 - Innovation<br>
 - Pathways 
Environment 
 - Climate Solutions<br>
 - Great Lakes<br>
Culture 
 - Arts Access and Participation<br>
 - Arts Leadership and Workforce<br>
 - Creativity and Cultural Production<br>
 - Joyce Awards 
Democracy<br>
 - Fair Elections<br>
 - Media<br>
Gun Violence Prevention and Justice Reform<br>
 - Gun Violence Prevention<br>
 - 21st Century Policing<br>
 - Reducing Mass Incarceration<br>
Special Opportunities<br>
 - Communications<br>
 - Cross-Programmatic Innovations<br>
 - Digital Tools</p>

<p>with the top level being Programs and the second level being focus areas.  I would like to have it so that when a Program is selected then the Focus Area select menu gets populated with the categories that are children of that program.  I currently have this jQuery left over from another method I tried which does get the current Programs that are selected:</p>

<pre><code>$(".grants-data form[name='grantSearch'] select[name='program']").change(function(){
    var selectedPrograms = $("form[name='grantSearch'] input[data-name='selectItemprogram'][value!='']:checked").map(function() {
    return this.value;
                }).get().join('|');
});
</code></pre>

<p>and I have this which appends all of the descendants of all categories to the focus area menu:</p>

<pre><code>{% set catSlug = craft.categories.title('focusArea').first() %}
            {% set childFAs = craft.categories.descendantOf(catSlug) %} 
            $("select#focusArea").html('&lt;option value=""&gt;Focus Area&lt;/option&gt;');
            {% for fa in childFAs %}
            $("select#focusArea").append('&lt;option value="{{fa.title}}"&gt;{{fa.title}}&lt;/option&gt;');
            {% endfor %}
            {% if faSlug|length %}
                $("select#focusArea option[value='{{faSlugOrig}}']").attr('selected',true);
            {% endif %}
            &lt;/script&gt;
</code></pre>

<p>but I can't seem to connect these two so that only the descendants of the program that is clicked get populated.  I think I may be overthinking this or trying to combine two methods that just won't combine.  Any help would be greatly appreciated!</p>

<p>Thanks!!</p>

CC BY-SA 3.0
2017-12-08T23:59:49.037Z
Would an answer without jquery be ok for you too? I don't like jquery for this task but I could help you
Robin Schambach
CC BY-SA 3.0
2017-12-09T00:07:08.363Z
Sure!  Any answer would be okay with me :-)
user5824
<categories>
Selecting descendants of a category when ancestor is clicked
# Selecting descendants of a category when ancestor is clicked

(Asked by: username_0 on 2017-12-08)

I have a question about combining Twig and jQuery in Craft. I have a couple of filters on a page that outputs some entries:
http://www.joycefdn.org/grants
My categories are organized like this:
Education and Economic Mobility
 - Educator Quality 
 - Innovation
 - Pathways 
Environment 
 - Climate Solutions
 - Great Lakes
Culture 
 - Arts Access and Participation
 - Arts Leadership and Workforce
 - Creativity and Cultural Production
 - Joyce Awards 
Democracy
 - Fair Elections
 - Media
Gun Violence Prevention and Justice Reform
 - Gun Violence Prevention
 - 21st Century Policing
 - Reducing Mass Incarceration
Special Opportunities
 - Communications
 - Cross-Programmatic Innovations
 - Digital Tools
with the top level being Programs and the second level being focus areas.  I would like to have it so that when a Program is selected then the Focus Area select menu gets populated with the categories that are children of that program.  I currently have this jQuery left over from another method I tried which does get the current Programs that are selected:
$(".grants-data form[name='grantSearch'] select[name='program']").change(function(){
    var selectedPrograms = $("form[name='grantSearch'] input[data-name='selectItemprogram'][value!='']:checked").map(function() {
    return this.value;
                }).get().join('|');
});

and I have this which appends all of the descendants of all categories to the focus area menu:
{% set catSlug = craft.categories.title('focusArea').first() %}
            {% set childFAs = craft.categories.descendantOf(catSlug) %} 
            $("select#focusArea").html('Focus Area');
            {% for fa in childFAs %}
            $("select#focusArea").append('{{fa.title}}');
            {% endfor %}
            {% if faSlug|length %}
                $("select#focusArea option[value='{{faSlugOrig}}']").attr('selected',true);
            {% endif %}
            

but I can't seem to connect these two so that only the descendants of the program that is clicked get populated.  I think I may be overthinking this or trying to combine two methods that just won't combine.  Any help would be greatly appreciated!
Thanks!!

**Tags:** categories

> **Comments:**
> **username_1**: Would an answer without jquery be ok for you too? I don't like jquery for this task but I could help you  
> **username_0**: Sure!  Any answer would be okay with me :-)  

---

## 1 answers

### Answer by username_1 on 2017-12-09. Score: 0 | Accepted answer

Okay, please don't be afraid and give it a try. I'm using the angular way, it seems a little bit difficult but it's actually really easy once you get used to it and works perfectly as soon as you understand it a little bit. If you need changes I'll provide whatever you need.
Edit: here you can see a live example for it plunker or course without css but it is your html
Let's get into it.
For testing purposes I created this category structure in my backend and called the group filter.

First you need to include this library you can of course use the {% includeJsRessource %} as well


Then you create 2 javascript arrays one for the Culture, Democracy... I call them parents and one for their children that belong to them
// get all filters of the first level
{% set filters = craft.categories.group('filter').level(1).find() %}


In the end you'll have 2 array that could look like
Now the funny part starts
include this javascript file. You can ask whatever you want I'll explain it. Even if the syntax and everything what's going on seems a little bit strange, but make sure this is loaded after the library from above
var  myApp = angular.module('myApp',[]).config(function($interpolateProvider) {
    $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
});

myApp.controller('filterController', ['$scope', function ($scope) {
    // all parents
    $scope.parents = parents;
    // all children
    $scope.children = children;

    // return if the parent is selected or not
    $scope.filterBySelectedParent = function (item) {
        return $scope.selectedParents.indexOf(item.parent) !== -1;
    };

    // an array with all selected parent ids
    $scope.selectedParents = [];

    // include an item to the array or slice it when the input it clicked
    $scope.addFilter = function(id){
        var index = $scope.selectedParents.indexOf(id);
        if(index === -1){
            $scope.selectedParents.push(id);
        }else{
            $scope.selectedParents.splice(index, 1);
        }
    }
}]);

And finally your new html



    
    
        
            
                {[{ filter.title }]}
            
        
    

    
    
        
            
                {[{ child.title }]}
            
        
    

    


Explanation: so what actually happens is the following 

you create 2 arrays in javascript based on your backend inputs
angular renders your menu based on those two arrays but the second one has a filter. Only clicked items of the first array are shown
as soon as someone clicks on an filter it is included in an array $scope.selectedParents 
any change in this array is recognized automatically which results, that the html renders again => your other filters are shown.

Please tell me if I missunderstood you somehow.. based on my current state I can change nearly everything really easily in just a few clicks. For example if you would like to automatically select your children you would include ng-checked="filterBySelectedParent(child)" on your input and remove the | filter: filterBySelectedParent.. that's it

> **Comments:**
> **username_0**: Thanks for this solution!  As for the HTML, it's actually possible to just add the options to the select box and it gets generated into that ul/li list with labels with a plugin I'm using to create the multi-checkbox functionality.  I will try out your method though and let you know how it goes!  
> **username_1**: Ah okay sry I thought it was your work. My solution has definitely disadvantages, for example you have to get used to the new methods but from my experience (and everyone else will say the same who uses angular) for searching/filtering and filter that depends other filters and all these kind of things this method is perfect because you don't have to care about the html since angular does everything for you and of course it boosts your performance compared to php or jquery. Anyway I wish you good luck  
> **username_0**: Hi Robin, thanks for much for the help.  I've made a test page to test your solution and it's not quite working: http://www.joycefdn.org/grantsDB I tried to convert the HTML to the select boxes that I need and it doesn't work when I apply the multiple select option plugin to the selects, in that case, the secondary select box does not fill in at all.  Also, I need the values of the select boxes to still be the titles of the categories because that's how the filtering works.  Any help would be greatly appreciated!!  
> **username_0**: This is how I tried to edit it: <div ng-app="myApp" ng-controller="filterController"> <select id="program" name="program" multiple="multiple"> <option value="" selected>Program</option> <option ng-repeat="filter in parents" ng-click="addFilter(filter.id);" value="{[{filter.id}]}">{[{ filter.title }]}</option> </select> <select id="focusArea" name="focusArea" multiple="multiple"> <option class="" ng-repeat="child in children | filter: filterBySelectedParent"><span data-name="selectItemfocusArea" value="{[{ child.id }]}">{[{ child.title }]}</span> </option> </select> </div>  
> **username_0**: I'm so sorry, I'm really new to Stack Exchange, I think I forgot to tag you... @robin-schambach  
> **username_1**: It actually works but you hide the real select with all functionality and show the useless jquery select with no functionality instead. By the way: best practice would be to create all your filters that way, so you have multiple Arrays with all filters, in order to display the entries by your arrays. If you want I could do it for you. It makes everything much easier and smoother. I tried to accomplish such a thing with jquery in the past too. But it becomes a pain sooner or later  
> **username_1**: I think that is the same reason why your previous code did not work either. Your code may have been correct but you did not activate your functions for the jquery filter, only for you own but you hide it and never use it  
> **username_0**: I'm not sure what you mean, do you mean I could use Angular to make the multi-select options in the select boxes instead of the jQuery plugin? The other filters don't really need to cascade on each other like the Program and Focus Area ones so I'm only using jQuery to make them multi-selects, also for your code, is there a way to make them cascade on each other without using "value" since that's how the filters display the entries?  Thanks!!  
> **username_1**: It's not that you could to it, you should use only angular or another jquery plugin, since the one you use is not able to sync properly. The value attribute does not matter, you can leave it if you don't want to use the real strength of the script and of course if you don't want to avoid trouble sooner or later because of jquery. As soon as you have more entries and reach a certain limit or if you want to include more filters it is going to be mess  
> **username_0**: ohhh, I see what you mean.  I see it working in my test page now, I just have to reconcile how it filters the entries now and style it.  Does it seem right to you??  Thanks!  
> **username_1**: That's one way you could do it  

---

