読者です 読者をやめる 読者になる 読者になる

Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

AngularJS1.5に再挑戦 その10 Custom Angular Directive for Confirmed Click

概要

AngularJS1.5に再挑戦 その10 Custon Angular Directive for Confirmed Click

参考動画・参考サイト

Coding for Entrepreneurs

AngularJS — Superheroic JavaScript MVW Framework

Custon Angular Directive for Confirmed Click

  • 公式サイトはこちらを参照。htmlタグを使って、DOMを操作するようなイメージ。

AngularJS

  • js/app/utils フォルダを作成する。その中に、confirm-click.module.js, confirm-click.directive.jsを作成する。

  • confirm-click.module.jsに以下のようにコードを追記する。

'use strict';

angular.module('confirmClick', []);
  • confirm-click.directive.jsに以下のようにコードを追記する。
'use strict';

angular.module('confirmClick').
    directive('confirmClick', function(){
        return {
            link: function(scope, element, attr){
                console.log(scope)
                console.log(element)
                console.log(attr)
            }
        }
    })
  • app.module.jsにconfirmClickを追記する。
'use strict';

angular.module('try', [
    // external
    'ngResource',
    'ngRoute',
    // internal
    'blogDetail',
    'blogList',
    'confirmClick'
]);
  • blog-list.htmlのhtmltagにconfirm-clickを挿入してみる。
<h1>Blog List</h1>
<ul ng-if='items.length > 0'>
    <li ng-repeat='item in items' confirm-click><a ng-href='/blog/{{ item.id }}'>{{ item.title }} {{ item.publishDate }}</li>
</ul>

<span ng-if='items.length == 0'>Posts coming soon</span>
  • Error: eslement is not defined が表示されてしまう。。。これは、なぜか不明。と思ってたら、log(element)と書くべきところを、log(eselement)と書いていただけだった。凡ミス〜!

  • confirm-click.directive.jsを修正する。

'use strict';

angular.module('confirmClick').
    directive('confirmClick', function(){
        return {
            link: function(scope, element, attr){
                console.log(scope)
                console.log(eslement)
                console.log(attr.confirmClick)
                console.log(attr.ngHref)
                console.log(attr.href)
            }
        }
    });
  • confirm-click.directive.jsを少し修正する。
'use strict';

angular.module('confirmClick').
    directive('confirmClick', function(){
        return {
            template: "<a href=''>Are you sure?</a>",
            link: function(scope, element, attr){
                console.log(scope)
                console.log(element)
                console.log(attr.confirmClick)
                console.log(attr.ngHref)
                console.log(attr.href)
            }
        }
    });
  • blog-list.htmlにconfirm-clickを追加する。これで、confirm-clickでrenderingされたページが表示される。
<h1>Blog List</h1>
<ul ng-if='items.length > 0'>
    <li ng-repeat='item in items'>
        <a ng-href='/blog/{{ item.id }}'>{{ item.title }} {{ item.publishDate }}</a>
        <confirm-click></confirm-click>
        </li>
</ul>

<span ng-if='items.length == 0'>Posts coming soon</span>
  • 試しに、index.htmlを以下のように修正してみる。
<h1>Blog List</h1>
<ul ng-if='items.length > 0'>
    <li ng-repeat='item in items'>
        <a ng-href='/blog/{{ item.id }}' confirm-click>{{ item.title }} {{ item.publishDate }}</a>
        <confirm-click></confirm-click>
        </li>
</ul>

<span ng-if='items.length == 0'>Posts coming soon</span>
  • そうすると、ページには以下のように表示される。
 Are you sure? Are you sure?
Are you sure? Are you sure?
Are you sure? Are you sure?
Are you sure? Are you sure? 
  • つまり、directiveのmoduleをhtmlタグとして挿入すると、その内容を上書きできるということに何なる?

  • ここで上書きの制御に関する項目restrictを設定する。これを設定すると上書きはしないという設定なのかな?

'use strict';

angular.module('confirmClick').
    directive('confirmClick', function(){
        return {
            restrict: "E",
            template: "<a href=''>Are you sure?</a>",
            link: function(scope, element, attr){
                console.log(scope)
                console.log(element)
                console.log(attr.confirmClick)
                console.log(attr.ngHref)
                console.log(attr.href)
            }
        }
    });
  • 他にもscopeでcontextを設定できる。
'use strict';

angular.module('confirmClick').
    directive('confirmClick', function(){
        return {
            scope: {
                message: "@message",
            },
            restrict: "E",
            template: "<a href=''>Are you sure?</a>",
            link: function(scope, element, attr){
                console.log(scope.message)
                console.log(element)
                console.log(attr.confirmClick)
                console.log(attr.ngHref)
                console.log(attr.href)
            }
        }
    });
  • blog-list.htmlで、messageに引数を渡す。
<h1>Blog List</h1>
<ul ng-if='items.length > 0'>
    <li ng-repeat='item in items'>
        <a ng-href='/blog/{{ item.id }}' confirm-click>{{ item.title }} {{ item.publishDate }}</a>
        <confirm-click message='メッセージ!'></confirm-click>
        </li>
</ul>

<span ng-if='items.length == 0'>Posts coming soon</span>
  • 同様に、文字列だけではなく、計算した数字なども渡せる。試しに、blog-list.htmlに設定してみる。
<h1>Blog List</h1>
<ul ng-if='items.length > 0'>
    <li ng-repeat='item in items'>
        <a ng-href='/blog/{{ item.id }}' confirm-click>{{ item.title }} {{ item.publishDate }}</a>
        <confirm-click message='メッセージ!' eq='10+100+10'></confirm-click>
        </li>
</ul>

<span ng-if='items.length == 0'>Posts coming soon</span>
  • confirm-click.directive.jsに渡してみる。これで、eqには計算された数字が代入される。
            scope: {
                message: "@message",
                eq: "=eq",
            },
...
            link: function(scope, element, attr){
                console.log(scope.eq)
  • 変数を代入することもできる。例えば、以下のように変数を代入してみる。
<confirm-click message='メッセージ!' eq='10+100+10' post='item'></confirm-click>
  • confirm-click.directive.jsをいかのように設定する。
...
        return {
            scope: {
                message: "@message",
                eq: "=eq",
                post: "=post"
            },
...
                console.log(scope.post)
  • そうすると、コンソールには、以下のようにインスタンスの要素リストが表示される。
Object { title: "Some Title", id: 1, description: "This is a book", publishDate: "2017-01-08", $$hashKey: "object:6" }
  • さらにこれを発展させて、この変数をdirectives内のtemplateに埋め込むこともできる。
...
        return {
            scope: {
                message: "@message",
                eq: "=eq",
                post: "=post"
            },
...
            template: "<a href=''>{{ post.title }}</a>",
            link: function(scope, element, attr){
                console.log(scope.post)
...
  • blog-list.htmlの表示を担当していた箇所をそのまま、templateに埋め込んでみる。
 template: "<a ng-href='/blog/{{ post.id }}'>{{ post.title }} {{ post.publishDate }}</a>",
  • console.log(scope.post), console.log(attr.post) の違いは、scopeは多分、valueを表示して、attrは属性(もしくはそのままの数値、式だったら、式をそのまま表示する)ということなのかな。

  • 次に、clickした時のイベントを設定する。

                var msg = scope.message || "Are you sure?"
                element.bind("click", function(event){
                    if (window.confirm(msg)){
                        console.log('/blog/' + scope.post.id)

                    }
                })
  • これは、comfirmするかしないかに関わらず、画面が遷移するので、confirmが会った時のみ画面を遷移するように設定し直す。
...
// $rootScope, $locationをimportする。
directive('confirmClick', function($rootScope, $location){
...
//templateでのurl遷移はなくす
            template: "<a ng-href='#'>{{ post.title }} {{ post.publishDate }}</a>",
            link: function(scope, element, attr){
                var msg = scope.message || "Are you sure?"
                element.bind("click", function(event){
                    if (window.confirm(msg)){
                        // console.log('/blog/' + scope.post.id)
// rootScopeと、locationで、画面遷移を設定する。
                        $rootScope.$apply(function(){
                            $location.path("/blog/" + scope.post.id)
                        })
                    }
                })
...
  • 最終的には以下のようになる。この部分の解説はなかったなぁ(^ ^;)
'use strict';

angular.module('confirmClick').
    directive('confirmClick', function(){
        return {
            restrict: "A",
            link: function(scope, element, attr){
                var msg = attr.confirmClick || "Are you sure?";
                var clickAction = attr.confirmedClick;
                element.bind("click", function(event){
                    if (window.confirm(msg)){
                        scope.$eval(clickAction)
                    }

                    });
                }
            }
    });