質問

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/

役に立ちましたか?

解決

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top