0

I am trying to create a faceting widget that works with Solr. How do I add ng-click event to each newly added facet item. So when a user clicks on an item in the list, I can re-query solr.

HTML Usage:

<facet field="query.response.facets.facet_fields.location" name="location" />

Directive:

var commonComponentsApp = commonComponentsApp || angular.module('cpUtils', []);
commonComponentsApp.directive("facet", function($compile) {
'use strict';
return {
    restrict: "E",
    scope: {
        field: "=",
        name: "@"
    },
    link: function (scope, element) {
        var list = new Array(), i, facet_item;
        scope.$watch('field', function (data) {
            if (data === undefined || data === null) {
                return;
            }
            for (i = 0; i <= data.length - 1 ; i += 2) {
                facet_item = '<li class="unstyled" ng-click=applyFilter('+ scope.name + "," + data[i] + ')>' + data[i] + " (" + data[i + 1] + ")</li>";
                var e = angular.element(facet_item);
                $compile(e.contents())(scope);
                list.push(e);
            }
            element.html(list);
        });

        scope.applyFilter = function (facet, value) {
            console.log("called");
            console.log(facet + ' ' + value);
        }
    }
};
});

Thanks

3
  • list is an array try with list.join('') Commented Apr 2, 2014 at 16:39
  • Sorry, What do you mean? Also, when I check scope in Batarang, applyFilter: null Commented Apr 2, 2014 at 16:58
  • You can't do element.html(list) because list is an array BTW field: "=" so field is an object so you need $watch with the third param true Commented Apr 2, 2014 at 17:23

1 Answer 1

1

I can see a few issues here. First, you are compiling the contents of your li item, instead of the element itself...

$compile(e.contents())(scope);

The ng-click directive is on the actual li element, so you need to compile the entire thing, instead of just its children. Change that line to...

e = $compile(e)(scope);

Next, you are $watching the value of scope.field, which appears to be an array, based upon your for loop. Therefore, you should use $watchCollection, instead of $watch.

scope.$watchCollection('field', ...

Next, you can't add a native javascript array to the DOM...

    ...
    list.push(e);
}
element.html(list);

Instead of adding each compiled element to an array, append each to the DOM immediately. So change the above to...

    ...
    element.append(e);
}

It will happen so fast it will appear that they are all added to the DOM at the same time.

Finally, assuming that the arguments you are passing to your ng-click function are strings, you need to put them in quotes. Change the line to something like this...

facet_item = '<li class="unstyled" ng-click=applyFilter("'+ scope.name + '","' + data[i] + '")>' + data[i] + ' (' + data[i + 1] + ')</li>';

Angular $evaluates the parameters in ng-click, meaning essentially it treats them like javascript code, which allows you to pass variables. If you don't have the quotes, it thinks that they are variables (which are undefined), when in your case they are actually just primitives (strings I assume)

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot charlie. The function gets called but the arguments come as undefined.
I edited my answer to include a potential fix for the undefined arguments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.