0

I'm trying to dynamically add a ng-click to a bunch of li's that get dynamically created inside of a directive. The idea is to hide the select element and overlay it with a custom div with a ul and use that as the dropdown. This way it can be styled anyway you like. I use the directive to control the select as you are selecting from the ul list. I dynamically created the ul and li's in the directive and add them before the element. I dynamically add the ng-click attribute. This all works fine, however, the ng-click never fires. So I'm forced to use the click event through jQuery (which is on the page because of Foundation). Here is my code. `dataviz.directive("customDropdown", ["$timeout", "$rootScope", "$document", "$compile", function($timeout, $rootScope, $document, $compile){

return {

    controller: function($scope) {

        $scope.clicked = function() {
            alert("ng click worked");
        }

    },

    link: function(scope, element, attributes) {

        // hide the default select element
        // TODO: use css instead
        element.hide();

        var id,
            overlay = angular.element(document.createElement("div")),
            ul = angular.element(document.createElement("ul")),
            span = angular.element(document.createElement("span"));

        id = Math.random().toString().slice(2);

        /*
         * Process the option clicked on. this will dynamically set the
         * correct option as selected and trigger the change event
         *
         * @method processOptionClick
         * @param {Element} the li element clicked on
         * @return undefined
         * */
        function processOptionClick(li) {

            if ( li.data("value") !== "0" ) overlay.addClass("active");

            span.html(li.html());

            element
                .children()
                .attr("selected", false);

            element
                .children()
                .eq(li.attr("data-value"))
                .attr("selected", true);

            // firefox and safari need you to explicitly set the selected attribute
            element[0].selectedIndex = li.attr("data-value");
            element.trigger("change");

        }

        /*
         * Populate the li based on the options in the select element
         *
         *
         * @method populateFakeDropdown
         * @return undefined
         * */
        function populateFakeDropdown() {

            // use $timeout to make sure options are populated before copying
            // them to the ul
            // TODO: this can be better. maybe a promise or custom event of something like that
            $timeout(function(){

                var options = element.children();

                // set the span html to the selected li
                span.html((element.find(":selected").html()));

                // if the value is blank then the dropdown reset so remove the active overlay
                if ( element.find(":selected").val() === "" ) overlay.removeClass("active");

                // remove all previous li's
                ul.empty();

                // loop through the options and rebuild the li's
                angular.forEach(options, function(value, key) {

                    var curOpt = angular.element(value),
                        li = angular.element(document.createElement("li"));

                    if ( curOpt.html() === "Janssen" ) overlay.addClass("active");

                    li.addClass("options");

                    // set the data-value to the index. should be the same as the option it mirrors
                    li.attr("data-value", key);
                    li.attr("data-ng-click", "clicked()");
                    li.on("click", function(){
                        processOptionClick(li);
                    });

                    // set the text of the li from the text of the option
                    li.html(curOpt.html());

                    ul.append(li);

                });


            }, 10);

        }

        span.addClass("selected");

        /*
         * set the data-id of the span. this used for when clicking on dropdown.
         * without this if you click on the text of the dropdown it wouldn't trigger
         * */
        span.attr("data-id", id);

        // hide ul
        // TODO: this should be done in the css
        ul.hide();

        overlay
            .addClass("dropdown")
            .addClass("view-height")
            .addClass(function(){
                return element.attr("class");
            });

        overlay.attr("data-id", id);
        overlay
            .append(span)
            .append(ul);

        // prepend the new overlay before the select element
        element.before(overlay);

        // bind a click event to the body. this allows us to close the "dropdown" when clicking outside of it
        angular.element($document[0].body).on("click", function(e){

            var element = angular.element(e.target);

            // hide any open ul's
            ul.hide();

            // if the element clicked on matches then show the ul
            if ( element.attr("data-id") === id ) {
                ul.addClass("active").show();
            }

        });

        // this should run only once when the directive is instatiated. it will
        // populate the fake dropdown
        populateFakeDropdown();

        // anytime there is an update to the request object update the dropdows as
        // there is a potential that they may have changed
        $rootScope.$on("updateDropdowns", function(){

            populateFakeDropdown();

        });

    }

}

}]);`

I want to use ng-click so i can keep it within angular and take advantage of ngTouch for mobile devices.

2 Answers 2

1

After playing around for a bit I relized how to compile the html. I simply have to pass in the contents of the overlay I'm using. So the line of code that worked was:

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

Now I know how to properly use the $compile service. :)

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

Comments

0

You have to use $compile on new HTML that needs Angular directives:

li.html(
    $compile(curOpt.html())(scope);
);

4 Comments

Why would I have to compile the html? The ng-click is added to the li element, not to the contents of it?
Woops, lots of code...you have to recompile the HTML the click was added to.
Ok. How would I go about that. I'm still learning directives and am not familiar with how to go about that. Thanks.
Would anyone be able to assist me in how to recompile the html?

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.