しるてく

技術的な話をします

ui.routerとdecorator

書いてみたけど使うか分からないのでメモるだけメモっとく。

ui-viewのautoscrollのスクロール位置を固定する

https://github.com/angular-ui/ui-router/wiki/Quick-Reference#autoscroll

ui.routerではui-viewが切り替わった時にautoscrollって属性をつけてあげないとスクロールしてくれない。
$uiViewScrollでは、viewの要素と関係ない位置にスクロールできないので、decoratorでごにょごにょしてやる。
具体例として、ヘッダーをfixedで表示しているとautoscrollを指定したときにそのui-viewの上部にスクロールしてしまうので上のほうがヘッダーに隠れてしまうので、強制的に一番上までスクロールさせたい。

app.config ['$provide', ($provide) ->
  $provide.decorator '$uiViewScroll', () ->
    (uiViewElement) ->window.scrollTo(0, 0)
]

$state.goのreloadを常にtrueにしてやる

同じstateに移動できないのやだなーみたいなとき。

app.config ['$provide', ($provide) ->
  $provide.decorator '$state', ($delegate) ->
    state = $delegate
    state.superGo = state.go
    state.go = (to, params, options) ->
      options = options || {}
      if angular.isUndefined options.reload
        options.reload = true
      this.superGo(to, params, options)

    return $delegate
]

javascriptのreplaceでまとめて置換する

たとえば、

/path/to/:category/:typeみたいなのがあったときに{ category: 'hoge', type: 'fuga' }をわたしてあげると/path/to/hoge/fugaにして欲しいなってとき。

replaceの引数にfuctionが使えるので、

  var path = '/path/to/:category/:type'
  var params = {
    category: 'hoge',
    type: 'fuga'
  }
  path = path.replace(/\:([^\/]*)/g, function(all, group) { return params[group]; });

みたいなことができる。


backboneを使っていてのっぴきならない理由で/path/to?category=hoge&type=fugaのようにparamsを使えない時に/path/to/hoge/fugaさせるために使った。

    fetch: function(options) {
      options = options ? _.clone(options) : {};
      var data = options.data;
      delete options.data;

      this.url = this.url_tmpl;
      if (data) {
        this.url = this.url.replace(/\:([^\/]*)/g, function(all, group) { return data[group]; });
      }
      return Backbone.Collection.prototype.fetch.call(this, options);
    },

AngularJSでhover

スマホサイト作っていると、擬似クラスの:hoverが使い物にならなかったりして、何らかの対応*1が必要だったりするんだけど、angularでどうしようかなと思ってng-mouseenterとか使おうかdirective書こうかみたいなこと悩んでいたら、ng-clickの仕組みでタップ時にng-click-activeっていうクラスがつくの発見してアンギュラーは偉大だって思った。という感動を記録に残しておく。

AngularJSでmoment.js使いたいとき

urish/angular-moment · GitHubってやつがあった。
ほかにもangular-momentjsって名前のやつがいくつかあるけど、↑のやつが一番よさそう。

こんな感じで使う。

$scope.date = new Date()
$scope.epoch = 1000000000000
<time am-time-ago="date"></time>
<time am-time-ago="epoch"></time>

数字を渡すと、エポック秒と判断して、内部でnew Date(value)してくれる。
2014/01/01 12:00:00みたいに文字列を渡したい場合は、

<time am-time-ago="'2014/01/01 12:00:00'" am-format="YYYY/MM/DD HH:mm:ss"></time>

ってやってあげると良いらしい。
am-time-agoのシングルクォーテーションを忘れずに。
am-formatに関する記述がREADMEになくて、最初使えないなーって思ってた。

他にも、

<time>{{ date | amDateFormat:'dddd, MMMM Do YYYY, h:mm:ss a'}}</time>

みたいなフィルターもあるけど、READMEに書いてあるので読めば分かる。

ngShowの表示非表示でアニメーションさせる

ng-hideにdisplay: none !importantがかかっているので、こんな感じにかけばいいらしい。
これで、アニメ終わったらdisplay: noneしてくれるので、アニメ要素が上にかぶってタップできない、みたいなことも起きないはず。


HTML

    <div class="animation-element" ng-show="show">
      なんかなんかなんかなんかなんかなんか
    </div>

SCSS

  .animation-element {
    @include transition(150ms linear all);

    // アニメ中はblockにしてやる
    &.ng-hide-add,
    &.ng-hide-remove {
      display: block !important;
    }

    // 表示→非表示
    &.ng-hide-add {
      @include translate3d(0, 0, 0);
      opacity: 1;
    }
    &.ng-hide-add-active {
      @include translate3d(0, 20px, 0);
      opacity: 0;
    }

    // 非表示→表示
    &.ng-hide-remove {
      @include translate3d(0, 20px, 0);
      opacity: 0;
    }
    &.ng-hide-remove-active {
      @include translate3d(0, 0, 0);
      opacity: 1;
    }
  }

同じ動き

これでもOKだけど、スペックの低いスマホの場合、クラスの付け替えでチカチカする恐れあるので上のほうが安全そう。

  .animation-element {
    @include transition(150ms linear all);
    @include translate3d(0, 0, 0);
    opacity: 1;

    // アニメ中はblockにしてやる
    &.ng-hide-add,
    &.ng-hide-remove {
      display: block !important;
    }

    &.ng-hide {
      @include translate3d(0, 20px, 0);
      opacity: 0;
    }
  }

AQUOS PHONEでposition: fixedを指定した要素より後でキーボードが開かない

ヘッダーとかフッターとか固定するのにposition: fixedを使用すると、Android2.3ではもろもろ問題が起こるんだけど、その一例としてAQUOS PHONEでキーボードが開かなくなるようだ。

どう解決したもんかなと思ったけど、ヘッダー/フッターみたいな感じで位置固定しているならbodyのいちばん後ろに書いても表示位置変わらないじゃんと思って、いちばん下に持って行ったら解決した。

Android2系滅びろ。