AngularJS1.5に再挑戦 その10 Custom Angular Directive for Confirmed Click
概要
AngularJS1.5に再挑戦 その10 Custon Angular Directive for Confirmed Click
参考動画・参考サイト
AngularJS — Superheroic JavaScript MVW Framework
Custon Angular Directive for Confirmed Click
- 公式サイトはこちらを参照。htmlタグを使って、DOMを操作するようなイメージ。
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) } }); } } });