[解決済み] データベースから動的な HTML 文字列をコンパイルする
質問
状況
Angular アプリの中には、Page というディレクティブがあり、コントローラによってバックアップされ、ng-bind-html-unsafe 属性を持つ div が含まれています。これは 'pageContent' という $scope 変数に割り当てられています。この変数には、データベースから動的に生成されたHTMLが代入されます。ユーザーが次のページをめくると、DBへの呼び出しが行われ、pageContent変数にこの新しいHTMLが設定され、ng-bind-html-unsafeによって画面上にレンダリングされるのです。以下はそのコードです。
ページディレクティブ
angular.module('myApp.directives')
.directive('myPage', function ($compile) {
return {
templateUrl: 'page.html',
restrict: 'E',
compile: function compile(element, attrs, transclude) {
// does nothing currently
return {
pre: function preLink(scope, element, attrs, controller) {
// does nothing currently
},
post: function postLink(scope, element, attrs, controller) {
// does nothing currently
}
}
}
};
});
ページディレクティブのテンプレート (上記のtemplateUrlプロパティから"page.html")
<div ng-controller="PageCtrl" >
...
<!-- dynamic page content written into the div below -->
<div ng-bind-html-unsafe="pageContent" >
...
</div>
ページコントローラ
angular.module('myApp')
.controller('PageCtrl', function ($scope) {
$scope.pageContent = '';
$scope.$on( "receivedPageContent", function(event, args) {
console.log( 'new page content received after DB call' );
$scope.pageContent = args.htmlStrFromDB;
});
});
これでうまくいきました。DBからのページのHTMLがブラウザできれいにレンダリングされているのがわかります。ユーザーが次のページに移動すると、次のページのコンテンツが表示される、という具合です。ここまではいい感じです。
問題点
ここでの問題は、ページのコンテンツの中にインタラクティブなコンテンツを持ちたいことです。例えば、HTMLにサムネイル画像が含まれていて、ユーザーがそれをクリックすると、Angularはポップアップモーダルウィンドウを表示するなど、何か素晴らしいことをするはずです。私はデータベースにあるHTML文字列にAngularのメソッドコール(ng-click)を配置しましたが、もちろんAngularは何らかの方法でHTML文字列を解析し、それらを認識してコンパイルしない限り、メソッドコールもディレクティブも認識することはできないでしょう。
私たちのDBでは
1ページ目のコンテンツです。
<p>Here's a cool pic of a lion. <img src="lion.png" ng-click="doSomethingAwesone('lion', 'showImage')" > Click on him to see a large image.</p>
2ページ目のコンテンツです。
<p>Here's a snake. <img src="snake.png" ng-click="doSomethingAwesone('snake', 'playSound')" >Click to make him hiss.</p>
Pageコントローラに戻って、対応する$scope関数を追加します。
ページコントローラ
$scope.doSomethingAwesome = function( id, action ) {
console.log( "Going to do " + action + " with "+ id );
}
DBからのHTML文字列の中から、その「doSomethingAwesome」メソッドを呼び出す方法がわかりません。Angularが何らかの方法でHTML文字列をパースしなければならないことは理解していますが、どのように?私は$compileサービスについての曖昧なつぶやきを読み、いくつかの例をコピーして貼り付けましたが、何も動作しません。また、ほとんどの例では、動的コンテンツはディレクティブのリンクフェーズで設定されるだけです。私たちは、アプリのライフサイクルを通じて、Pageが生き続けることを望んでいます。ユーザーがページをめくっている間、常に新しいコンテンツを受信し、コンパイルし、表示します。
抽象的な意味では、私たちはAngularアプリの中でAngularのチャンクを動的にネストしようとしており、それらを交換できる必要があると言えるかもしれません。
私はAngularのドキュメントの様々な部分を何度も読み、あらゆる種類のブログ記事も読み、JSは人々のコードに手を加えました。私は完全にAngularを誤解しているのか、単純な何かを見逃しているのか、あるいは私が遅いのかわかりません。いずれにせよ、私はいくつかのアドバイスを得ることができました。
どのように解決するのですか?
ng-bind-html-unsafe
は、コンテンツをHTMLとしてレンダリングするだけです。これはAngularのスコープを結果的にDOMにバインドするものではありません。そのため
$compile
サービスを使う必要があります。私が作った
このプランカー
を使用する方法を示すために
$compile
を使用して、ユーザが入力した動的な HTML をレンダリングし、コントローラのスコープにバインドするディレクティブを作成する方法を示します。ソースは以下に掲載します。
demo.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="[email protected]" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<h1>Compile dynamic HTML</h1>
<div ng-controller="MyController">
<textarea ng-model="html"></textarea>
<div dynamic="html"></div>
</div>
</body>
</html>
script.js
var app = angular.module('app', []);
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
function MyController($scope) {
$scope.click = function(arg) {
alert('Clicked ' + arg);
}
$scope.html = '<a ng-click="click(1)" href="#">Click me</a>';
}
関連
-
[解決済み] jQueryを使ってドロップダウンリスト(セレクトボックス)から選択されたテキストを取得する
-
[解決済み] リンクのように動作するHTMLボタンを作成する方法
-
[解決済み] PHPでHTML/XMLをパースして処理する方法とは?
-
[解決済み] HTML 5: Is it <br>, <br/>, or <br />?
-
[解決済み] HTMLのid属性に有効な値は何ですか?
-
[解決済み] HTMLページからのリダイレクト
-
[解決済み] マークダウンにおける相互参照 (名前付きアンカー)
-
[解決済み] div内の画像の下に余分なスペースがある
-
[解決済み] ng-repeat内のng-click関数にパラメータを追加しても、うまくいかないようです。
-
[解決済み】なぜHTMLは "chucknorris "を色と見なすのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] HTMLとCSSによるテーブルスクロール [重複]について
-
[解決済み] ローカルストレージとCookieの比較
-
[解決済み] クリック可能なラベルを持つチェックボックスを作成するには?
-
[解決済み] クリアフィックスとは何ですか?
-
[解決済み] AngularJSのコントローラからビューにHTMLを挿入する
-
[解決済み] 特定のクラスや属性を持たない要素を選択するCSSセレクタは書けますか?
-
[解決済み] 静的な HTML ページにファビコンを追加する
-
[解決済み] label要素の中にinput要素を入れるべきですか?
-
[解決済み] CSSでdivを縦にスクロールできるようにする
-
[解決済み] 配列上で繰り返すのではなく、定義された回数をng-repeatする方法?