1

I'm trying to create a filter that would transform a string in real time when a browser is being resized and hits a media query break-point.

I just want to :

  • display "string.short" when min-width <= 200px
  • display "string.long" when min-width > 200px
  • make it generic and reusable (don't want to put code in a controller)
  • can't use a directive because, I will be filling things like title/value/alt attributes

So far, it's working at load time (without resizing), but I want to add the browser resize detection to adapt the label if the user resize its browser.

HTML :

<input value="{{ 'string' | responsivize}}" />

Filter :

angular.module('filters.responsivize', [])

.filter('responsivize', [function() {
    return function(key) {

        var showShort = function() {
            return Modernizr && !Modernizr.mq('only all and (min-width: 768px)');
        };

        //TODO: add any way to wath this in real time ?
        //$rootScope.$watch(showShort, function () {});
        //jQuery(window).resize(function() {});

        return key.concat(showShort() ? '.short' : '.long');
    };
}]);

(partially) Working jsfiddle http://jsfiddle.net/2Q8eL/2/

1 Answer 1

1

Filter should only be used to format/filter data after Angular has detected that the value to filter has changed. You could of course inject $rootScope into your filter and call $rootScope.$apply() to trigger Angular to call the filter again, but that would be a bit confusing for other developers.

I'd say you have two options. One is to add a run block for your app module that adds a method on the $rootScope which you can call, which listens to resize events and calls $rootScope.$apply().

So you'd do this instead:

<input value="{{responsivize('string')}}" />

The other option is not to put it a run block but make a directive instead which still places the responsivize method on the $rootScope. You'd name the directive and add it to your <body>.

Basically something like this:

angular.module('app')
  .directive('responsivize', function($rootScope) {
    return {
      restrict: 'A',
      link: function(scope, elm, attr){
        var showShort = Modernizr && !Modernizr.mq('only all and (min-width: 768px)');

        jQuery(window).resize(function() {
          var showShort = Modernizr && !Modernizr.mq('only all and (min-width: 768px)');
          $rootScope.$apply();
        });

        $rootScope.responsivize = function(key) {
          return key.concat(showShort ? '.short' : '.long');
        }
      }
    };
  });

And the HTML:

<body responsivize>
  ...
</body>

That way it's isolated to that directive, and you can reuse it. Do note that the window resize event might fire a lot of times, so you might want to throttle how many times you call $rootScope.$apply().

A bonus of having it as a method instead of a filter is that the code that calls the method is free to format/use the return value as it wants.

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

2 Comments

Thanks for that, good idea for the rootscope method. Could you elaborate your second option? I didn't understand the "<body>" part.
What about a filter depending on $locale, that can change dynamically?

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.