0

I am trying to add another filter to the FAQ Categories>Questions w/ Filter App and have bascially duplicated the working code for the first filter but it isn't working even though I have setup a second entity type just like the first filter. See sample code below.

My cshtml code:

@using ToSic.SexyContent
@functions
    {
    // variable which will contain the sorted categories
    IEnumerable<dynamic> sortedCategories;

    IEnumerable<dynamic> sortedTypes;

    // Prepare the data - get all categories through the pipeline
    public override void CustomizeData()
    {
    // get all categories of these questions, then get the distinct entities
    // this could all be done on 1 line, but it would be harder for people who don't know LINQ yet
    var questionsInThisModule = AsDynamic(App.Data["CO-Filter"].List);
    var categoriesUsed = questionsInThisModule.SelectMany(q => ((List<DynamicEntity>)q.Categories));
    var distinctCategories = categoriesUsed.Select(AsEntity).Distinct();    // Distinct only works reliably when cast as entity
    sortedCategories = AsDynamic(distinctCategories).OrderBy(q => q.Name);

    var typesInThisModule = AsDynamic(App.Data["CO-Filter"].List);
    var typesUsed = typesInThisModule.SelectMany(a => ((List<DynamicEntity>)a.Types));
    var distinctTypes = typesUsed.Select(AsEntity).Distinct();    // Distinct only works reliably when cast as entity
    sortedTypes = AsDynamic(distinctTypes).OrderBy(a => a.Name);
    }
}
<h2 class="sc-element">@ListContent.Title @ListContent.Toolbar</h2>
<div>@Html.Raw(ListContent.Introduction)</div>
<div>
    <strong>@App.Resources.FilterBy </strong>
    <select id="ddlFeatureFilter">
        <option value="all">@App.Resources.ShowAll</option>
        @foreach (var cat in sortedCategories)
        {
        <option value="@cat.EntityId">@cat.Title</option>
        }
    </select>
</div>
<div>
    <strong>@App.Resources.FilterBy </strong>
    <select id="ddlFeatureFilterOne">
        <option value="allOne">@App.Resources.ShowAll</option>
        @foreach (var catOne in sortedTypes)
        {
        <option value="@catOne.EntityId">@catOne.Title</option>
        }
    </select>
</div>
<ol>
    @foreach (var q in AsDynamic(App.Data["CO-Filter"]))
    {
    <li class="sc-element faq-set faq-setOne" data-tags="@String.Join(",", ((List<DynamicEntity>)q.Categories).Select(a => AsDynamic(a).EntityId))">
        @q.Toolbar @Edit.Toolbar(actions: "edit,new", contentType: "CO-Filter")
        <a class="faq-question" style="cursor: pointer">
            @if(!String.IsNullOrEmpty(q.LinkText))
            {
            @q.LinkText
            } else {
            @q.Link
            }
        </a>
    </li>
    }
</ol>

<script src="@App.Path/assets/faq.js" data-enableoptimizations="true"></script>

<script>
    $(document).ready(function() {
    initFaqSection("DnnModule-" + @Dnn.Module.ModuleID, "@ListPresentation.ShowEffect");
    });
</script>

My updated assets/faq js code:

function initFaqSection(containerSelector, showEffect) {
    var container = $("." + containerSelector);
    $(".faq-question", container).click(function (e) {
        var answer;
        switch(showEffect) {
            case "slide":
                answer = $(e.target).closest(".faq-set").find(".faq-answer");
                answer.slideToggle();
                e.preventDefault();
                break;
            case "lightbox":
                var question = $(e.target);
                answer = question.next();
                answer.dialog({
                    title: question.text(),
                    autoOpen: true,
                    dialogClass: "dnnFormPopup",
                    modal: true
                });
            default:
                break;
        }
    });

    // Attach drop-down filter
    $("#ddlFeatureFilter", container).change(function (changeEvent) {
        var tagFilter = changeEvent.target[changeEvent.target.selectedIndex].value;
        console.log("tf:" + tagFilter);
        //alert(tagFilter);
        $(".faq-set", container).each(function (i, e) {
            var tags = ($(e).attr('data-tags') + ",all").split(',');
            console.log(tags);
            if ($.inArray(tagFilter, tags) != -1)// || tagFilter == "all")
                $(e).slideDown();
            else
                $(e).slideUp();
        });
    });

        // Attach drop-down filter
    $("#ddlFeatureFilterOne", container).change(function (changeEvent) {
        var tagFilter = changeEvent.target[changeEvent.target.selectedIndex].value;
        console.log("tf:" + tagFilter);
        //alert(tagFilter);
        $(".faq-set", container).each(function (i, e) {
            var tags = ($(e).attr('data-tags') + ",allOne").split(',');
            console.log(tags);
            if ($.inArray(tagFilter, tags) != -1)// || tagFilter == "allOne")
                $(e).slideDown();
            else
                $(e).slideUp();
        });
    });

}

The content item entity fields setup: enter image description here

The content item itself:

enter image description here

What I currently have (note second filter only displays but doesnt filter by 'type').

enter image description here

I know my code is incorrect but is there an easy solution?

Also, is there any easy way if a link is displayed (no linktext entered by a user) to remove the path url and the extension?

Thx

UPDATE:

I have tried to create a combined function like so:

function initFaqSection(containerSelector, showEffect) {
    var container = $("." + containerSelector);
    $(".faq-question", container).click(function (e) {
        var answer;
        switch(showEffect) {
            case "slide":
                answer = $(e.target).closest(".faq-set").find(".faq-answer");
                answer.slideToggle();
                e.preventDefault();
                break;
            case "lightbox":
                var question = $(e.target);
                answer = question.next();
                answer.dialog({
                    title: question.text(),
                    autoOpen: true,
                    dialogClass: "dnnFormPopup",
                    modal: true
                });
            default:
                break;
        }
    });
    // Attach drop-down filters
    function runFilters() { 
        var filter1 = $("#ddlFeatureFilterOne").value;
        var filter2 = $("#ddlFeatureFilterTwo").value;
        //alert(filters);
        $("#ddlFeatureFilterTwo", container).change(runFilters);
            $(".faq-set", container).each(function (i, e) {
            var tags = ($(e).attr('data-tags') + ",allTwo").split(',');
            console.log(tags);
            if ($.inArray(filter1, tags) != -1 && $.inArray(filter2, tags) != -1)
                $(e).slideDown();
            else
                $(e).slideUp();
            });
    }
}

with my cshtml code as follows:

<div>
    <strong>@App.Resources.FilterBy </strong>
    <select id="ddlFeatureFilterOne">
        <option value="allTwo">@App.Resources.ShowAll</option>
        @foreach (var catOne in sortedCategories)
        {
        <option value="@catOne.EntityId">@catOne.Name</option>
        }
    </select>
    <select id="ddlFeatureFilterTwo">
        <option value="allTwo">@App.Resources.ShowAll</option>
        @foreach (var catTwo in sortedTypes)
        {
        <option value="@catTwo.EntityId">@catTwo.Name</option>
        }
    </select>
</div>

but this still only works the first filter?

denisjoconnor
  • 115
  • 1
  • 9

2 Answers2

1

So just as a side-note: you're asking a sequence of different questions in one issue, which makes it harder to answer. I recommend you split the questions in the future.

Now the problem you're having is the fact that you have two filters which currently don't know anything about each other. So the real solution is

  1. to have a combined runFilters() method which takes the value from both dropdowns and applies both
  2. your binding should then only call this, like $("#ddlFeatureFilterOne", container).change(runFilters);

The runFilters will look something like this (pseodo code):

``` function runFilters() { var filter1 = $("#ddl...").value; // not sure if it's .value var filter2 = $("#...")...;

    $(".faq-set", container).each(function (i, e) {
        var tags = ($(e).attr('data-tags') + ",allOne").split(',');
        console.log(tags);
        if ($.inArray(filter1, tags) != -1 && $.inArray(filter2, tags) != -1)
            $(e).slideDown();
        else
            $(e).slideUp();
    });

}

```

something like that :). for removing the path, you want to trim it in JS by the lastIndexOf("/") - see https://www.w3schools.com/JSREF/jsref_lastindexof.asp or using the c# equivalent https://msdn.microsoft.com/en-us/library/system.string.lastindexof(v=vs.110).aspx

iJungleBoy
  • 5,325
  • 1
  • 9
  • 21
  • NOTE: Understood ref separating out questions in future. I have created a separate question for trimming file path issue here - https://stackoverflow.com/questions/44386431/2sxc-removing-file-path-by-trimming-w-javascript-method – denisjoconnor Jun 06 '17 at 09:37
  • @djoc did this solve your problem? if yes, pls mark as the right answer – iJungleBoy Jun 07 '17 at 13:06
  • I added an UPDATE to initial question above (my attempt at runFilters method) thx – denisjoconnor Jun 07 '17 at 13:50
  • The effect I'm trying to achieve is pretty much the exact same as on http://2sxc.org/en/apps with multiple filters all connected to same data. Currently I have two entitys which have no connection via the file their associated with on display? Also tried giving single entity an entity within itself (Category entity has its own category entity) to try and connect file with two filters but no luck....Is the 'App Catelog' using Angular to achieve multiple filters on your own site? – denisjoconnor Jun 14 '17 at 08:40
1

I found a solution in the end....

It required me to add a 'data-title' tag as otherwise I could not link the data connected w/ filter1 (Categories) w/ that of filter2 (Types):

data-title="@String.Join(",", ((List<DynamicEntity>)q.Categories).Select(a => AsDynamic(a).EntityId))"

So I associated 'data-title' w/ my Categories filter and associated 'data-tags' w/ my Types filter.

My cshtml filter code:

<div>
    <strong>@App.Resources.FilterBy </strong>
    <select id="ddlFeatureFilterOne">
        <option value="allTwo">@App.Resources.ShowAll</option>
        @foreach (var catOne in sortedCategories)
        {
        <option value="@catOne.EntityId">@catOne.Name</option>
        }
    </select>
    <select id="ddlFeatureFilterTwo">
        <option value="allTwo">@App.Resources.ShowAll</option>
        @foreach (var catTwo in sortedCategoriesTypes)
        {
        <option value="@catTwo.EntityId">@catTwo.Name</option>
        }
    </select>
</div>
<ol>
    @functions{
        public static string SplitWord(string text)
        {
            int slash = text.LastIndexOf("/");
            int dot = text.LastIndexOf(".");
            dot--;
            var data = text.Substring(slash + 1, dot - slash);
            return data;
        }
    }
            @foreach (var q in AsDynamic(App.Data["CatFilter"]))
        {
                <li class="sc-element faq-set" data-title="@String.Join(",", ((List<DynamicEntity>)q.Categories).Select(a => AsDynamic(a).EntityId))" data-tags="@String.Join(",", ((List<DynamicEntity>)q.Types).Select(a => AsDynamic(a).EntityId))">
                    @q.Toolbar @Edit.Toolbar(actions: "edit,new,more", contentType: "CatFilter")
                    <a class="faq-question" href="@q.Link" style="cursor: pointer">
                        @if (!String.IsNullOrEmpty(q.LinkText))
                    {
                            @q.LinkText
                    }
                    else
                    {
                            @SplitWord(q.Link);
                    }
                    </a>
                </li>
        }
</ol>

And my adjusted runFilters function code:

    function runFilters() { 
    var filter1 = $("#ddlFeatureFilterOne").value;
    var filter2 = $("#ddlFeatureFilterTwo").value;
    }
    //alert(tagFilter);
    $("#ddlFeatureFilterOne", container).change(function(){
        var filter1 = $("#ddlFeatureFilterOne").val();
        var filter2 = $("#ddlFeatureFilterTwo").val();
        $(".faq-set", container).each(function (i, e) {
            var title = ($(e).attr('data-title') + ",allTwo").split(',');
            var tags = ($(e).attr('data-tags') + ",allTwo").split(',');
            console.log(title);
            if ($.inArray(filter1, title) != -1 && $.inArray(filter2, tags) != -1)
            $(e).slideDown();
        else
            $(e).slideUp();
        });
    });
    $("#ddlFeatureFilterTwo", container).change(function () {
        var filter1 = $("#ddlFeatureFilterOne").val();
        var filter2 = $("#ddlFeatureFilterTwo").val();
        $(".faq-set", container).each(function (i, e) {
            var tags = ($(e).attr('data-tags') + ",allTwo").split(',');
            var title = ($(e).attr('data-title') + ",allTwo").split(',');
            console.log(tags);
            if ($.inArray(filter1, title) != -1 && $.inArray(filter2, tags) != -1)
                $(e).slideDown();
            else
                $(e).slideUp();
        });
    });

Hope this helps others w/ similar issues

denisjoconnor
  • 115
  • 1
  • 9