ITの隊長のブログ

ITの隊長のブログです。Rubyを使って仕事しています。最近も色々やっているお(^ω^ = ^ω^)

【AngularJs1.4.x】input[type="range"]で、何故かレンジ入力の位置が変わらないバグ

丸1日ハマりました。

何故か知らないけど、directiveで作成するhtmlの中のinput[type="range"]。それに初期値を入れようとすると何故か更新されないバグがあることがわかりました。

github.com

issueを見るとわかると思いますが、みんな回避作を色々用意しています。しかし、私の環境では動かない。

どうしたものか。。。

試行錯誤しながら色々試すと、$timeoutを使ったコードが一番しっくりきて、しかも修正できた。

github.com

  • app.js
app.directive('myDirective', ['$timeout', '$interval', function($timeout, $interval) {
    function setScopeValues(scope, attrs) {
        scope.min = attrs.min || 0;
        scope.max = attrs.max || 0;
        scope.value = attrs.value || 0;
    }

    return {
        restrict: 'A',
        require: '?ngModel',
        scope: {
            ngModel: '=',
            ngModelDisplay: '='
        },
        template:
        '<div class="col-sm-12">' +
        '   <input type="text" ng-model="ngModelDisplay">' +
        '</div>' +
        '<div class="col-sm-12">' +
        '       <input type="range" value="{{value}}" class="form-control" min="{{min}}" max="{{max}}" ng-model="ngModel">' +
        '</div>',
        transclude: true,
        link: function(scope, element, attrs, ngModel) {
            setScopeValues(scope, attrs);

            // 下記コードを追加したら修正できた
            $timeout(function() {
                if (scope.value === attrs.value) {
                    ngModel.$setViewValue(scope.value);
                }
            });
        }
    }
}]);

ちなみに、$timeoutが何を意味しているかはわからない(`・ω・’)

www.buildinsider.net

なるほど。描画の後に動作しているっぽいということね。(本当かな。。。)

IE系のブラウザでNumber.isFinite()が動作しないので、polyfillを使おう

とあるプロジェクトで、エラーがでたのでコンソールみたら、「isFinite()って関数はありません」ってエラー。

「まじか・・・」と思いつつ、調べたら「polyfill」使えばいけるって書いている記事を見つけたのでメモ。

qiita.com

isFiniteとは?

Javascriptに実装されている関数です。有限数かどうかを確認します。

有限数とは?

有限の大きさ:ある数Nに対してそれより大きな数Mが存在する。 ということ。

よくわからんけど。無限についてはなんとなく。無限という数値は(x+1)ということができないから。それ以外は有限数と。

ようはjsで計算ミスったときによくみるInfinityがそれにあたるのかなと思いました。

developer.mozilla.org

使ってみる

動いたよ!

だがしかし。。。

> isFinite(10)
true
> isFinite('10')
true

おうおうおう(^ω^;

数値と文字列の型チェックはしてくれないのね。ということで、ドキュメントにもありますが、堅牢性の高いチェックをするならNumber.isFinite('0')を使いなさい。とのこと。

developer.mozilla.org

> Number.isFinite(10)
true
> Number.isFinite('10')
false

うむ。

しかしIEには実装されていない(´;ω;`)ブワッ

_人人人人人人人人人人人人人人人人_
Internet Explorer 未サポート<
 ̄YYYYYYYYYYYYYYYY ̄

泣いた

polyfillを使えばいける

polyfillとは?

hblog.glamenv-septzen.info

要するにHTML/JS/CSSの最新仕様や、まだドラフトとか提案段階の機能を、古いブラウザとかでも先取りして動かせるようにしてくれるライブラリをまとめて "Polyfill" というカテゴリで扱ってるらしい

ふーむ。

使ってみる

Qiitaの記事にはこう書いてある。

Number.isFinite = Number.isFinite || function(any) {
  return typeof any === 'number' && isFinite(any);
};

これでいけました!

(jsって動的にメソッドを追加できるんかいな・・・phpみたいやな)

まとめ

jsの型について知らないことが多くて困っています。。。

NaNとか一回一覧を用意して覚えたほうがいいなぁー。

【AngularJS1.4.x】 DirectiveからControllerのメソッドを呼ぶための設定

すごくハマりました。

やりたいこととして、とあるdirectiveからとあるcontrollerのメソッドを実行したかった。

が、方法がわからずにすごく時間がかかりました。とりあえずできたのでメモ。

環境

  • chrome 51.0.2704.103 (64-bit)
  • angularjs 1.4.9

実装

app.controller('myController', function($scope) {
    $scope.controllerMethod = funciton() {
        // controllerの処理
    };
});

app.directive('myDirective', ['$timeout', '$interval', function($timeout, $interval) {

    var getContentUrl = function() {
        return './js/template/template.html';
    };

    return {
        restrict: 'A',
        require: '?ngModel',
        scope: {
            ngModel: '=',
            ngModelDisplay: '='
        },
        templateUrl: getContentUrl(),
        controller: 'myController', // ここ大事!
        link: function(scope, element, attrs, ngModel) {
          // 省略
          scope.$apply('controllerMethod()');
        }
    }
}]);

コードの通りの実装をすればいける(はず)

directiveからcontrollerのメソッドを使う場合は、linkの中でscope.$applyにメソッド名を渡せばよい。

次に大切なことは、directiveのreturnで返すパラメータの中のcontrollerの箇所。ここをdirectiveから使用したいcontrollerのメソッドが存在するcontroller名を指定しないと使えないことがわかった。今回はこれにすごくハマりました。。。orz

仕組みはいまいちまだよくわかっていないが、とりあえずこれでできるようになりましたとさ。。。続く。