1

I am building a search application.I am using the highlighter function from Johann Burkard's JavaScript text higlighting jQuery plugin. After an angularJS $Http call all the data is bound. I created a directive to call the Highlighter function.

searchApplication.directive('highlighter', function () {
    return {
        restrict: 'A',
        link: function (scope, element) {
            element.highlight(scope.searchText);
        }
    }
});

here is the controller `searchApplication.controller('searchController', function ($scope, $http, searchService) {

$scope.myObject= {
    searchResults: null,
    searchText: "",
};
$scope.search = function () {
    searchService.doSearch($scope.luceneSearch.searchText).then(
        function (data) {
            $scope.myObject.searchResults = data;
        },
        function (data, status, headers, configs) {
            $log(status);
        });
}

});`

here is the service

searchApplication.factory('searchService', function ($http, $q) {
return {
    doSearch: function (_searchText) {
        var deferred = $q.defer();
        var searchURL = '/Search';
        $http({
            method: 'POST',
            url: searchURL,
            params: { searchText: _searchText }
        })
        .success(function (data, status, headers, configs) {
            deferred.resolve(data);
        })
        .error(function (data, status, headers, configs) {
            deferred.reject(data, status, headers, configs);
        });
        return deferred.promise;
    }
}

});

In the html I have the following

<td ng-repeat="col in row.fields" highlighter>
     {{col.Value}}
</td>

The directive is not getting the value to be searched, rather it gets {{col.Value}} and hence it is not able to highlight.

What am I doing wrong? How can I get the actual bound values so that I can manipulate it? Is there a better way to do this?

Updated: with controller and service code

1 Answer 1

2

From the code given, it should work fine if your controller has $scope.searchText properly set. I defined your directive in my app and debugged the link() function in Chrome, and scope.searchText is found as expected. If from browser debugging you find scope.searchText to be undefined you probably need to also post your controller code here.


UPDATE: From your comment, it seems the problem here is the execution order within Angular. Apparently the linking function is getting called before text interpolation is finished, so the solution is to wait for that process before proceeding with the highlighting part.

The trick here is to $watch for an update in col.Value and invoke the highlight logic afterward. The code below should do the trick:

app.directive('highlighter', function ($log) {
    return {
        restrict: 'A',
        compile: function compile(element, attributes) {
            // at this point, we still get {{col.Value}}
            var preinterpolated = element.text().trim();

            // removing the enclosing {{ and }}, so that we have just the property
            var watched = preinterpolated.substring(2, preinterpolated.length - 2);
            $log.info('Model property being watched: ' + watched);

            return {
                post: function (scope, element) {
                    // we watch for the model property here
                    scope.$watch(watched, function(newVal, oldVal) {
                        // when we reach here, text is already interpolated
                        $log.info(element.text());
                        element.highlight(scope.searchText);
                    });
                }
            };
        }
    };
});

This time around, $log logic should print out the interpolated value instead of just col.Value.


UPDATE2: I'm not quite sure how to go from there with directive, but if you don't mind using Angular filter, you can try this Angular UI solution. After attaching js file to your page, just include 'ui.highlight' module in your app and the filter will be available for use. It's also small like your jquery lib as well:

https://github.com/angular-ui/ui-utils/blob/master/modules/highlight/highlight.js

You can try live example here:

http://angular-ui.github.io/ui-utils/

Your HTML should now look like this (directive is no longer needed):

<td ng-repeat="col in row.fields">
   {{col.Value | highlight:searchText}}
</td>

Also noted that now the CSS class for hightlighted text is ui-match instead of highlight.


UPDATE3: If you're set on using a directive, this person seems to do something very similar, except that he's adding a timeout:

http://dotnetspeak.com/2013/07/implementing-a-highlighting-directive-for-angular

setTimeout(function () {
    element.highlight(scope.searchText);
}, 300);
Sign up to request clarification or add additional context in comments.

8 Comments

scope.searchText is showing me what the values are but in this line element.highlight(scope.searchText);. the element.node.data is not showing the bound value rather shows me {{col.value}}. I have updated my post with the service and controller.
@gkbinary Please see updated solution. I didn't use jquery nor hightlight plugin (my app is pure Angular), but at least from my testing the logic is now being executed after the text interpolation step.
this still leaves the text as is. I actually am seeing the values in scope.col.Value, So i tried doing this if(scope.col.value==scope.searchText) then scope.col.value = '<span class="highlight"'+ scope.col.value +'</span>'; this produces the result with the HTML as is rather than putting it in a span and applying the css.
@gkbinary Please see updated solution. It works if you don't mind using Angular filter instead of jquery function. This way you also don't need directive.
@gkbinary Also added another update in case you still want to try working a bit more on directive.
|

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.