web-dev-qa-db-ja.com

その場でtemplateUrlを変更できますか?

ディレクティブのスコープで値を渡すことで、templateUrlをその場で変更することは可能ですか?ディレクティブから渡されたデータに基づいてページをレンダリングするコントローラーにデータを渡したい

多分そのように見える何か:

<div> 
   <boom data="{{myData}}" />
</div> 

.directive('boom', function {
        return {
            restrict: 'E',
            transclude: true,
            scope: 'isolate',
            locals: { data: 'bind' },
            templateUrl: "myTemplate({{boom}}})" // <- that of course won't work.
        }
    });
26
iLemming

可能ですが、ロードするテンプレートがスコープデータに依存している場合、ディレクティブのtemplateUrlプロパティを使用できなくなり、低レベルAPI、つまり$httpを使用する必要があります。および$compile

おおよそ必要なこと(リンク機能でのみ可能)は、$httpを使用してテンプレートのコンテンツを取得し($templateCache!を含めることを忘れないでください)、テンプレートのコンテンツを「手動で」コンパイルします。

大変な作業のように聞こえるかもしれませんが、実際にはかなり簡単です。このパターンが使用されているngIncludeディレクティブ sources を確認することをお勧めします。

このようなディレクティブのスケルトンは次のとおりです。

app.directive('boom', function($http, $templateCache, $compile, $parse) {
        return {
            restrict: 'E',
            link: function(scope , iElement, iAttrs) {                            
              var boom = $parse(iAttrs.data)(scope);
              $http.get('myTemplate'+boom, {cache: $templateCache}).success(function(tplContent){
                iElement.replaceWith($compile(tplContent)(scope));                
              });              
            } 
        }
    });

<boom data='name'></boom>として使用されると仮定します。ここでの作業プランク: http://plnkr.co/edit/TunwvhPPS6MdiJxpNBg8?p=preview

おそらくテンプレートは最初に一度だけ決定されるべきなので、属性評価を{{name}}から属性解析に変更したことに注意してください。

53

これはAngularバージョン1.1.4+の新機能です。現在の不安定版(1.1.5)を使用すると、ディレクティブのテンプレートURLに関数を渡すことができることがわかりました。関数の2番目のパラメーターは、以下に示すように属性ディレクティブの値です。

未公開ドキュメント へのリンクは公式な変更を示しています。

partials/template1.htmlをテンプレートURLとして使用するには

HTML:

<div sub_view="template1"></div>

指令:

.directive('subView', [()->
  restrict: 'A'
  # this requires at least angular 1.1.4 (currently unstable)
  templateUrl: (notsurewhatthisis, attr)->
    "partials/#{attr.subView}.html"
])
16
EpiphanyMachine

Pkozlowski.opensourceからの回答を少し変更しました。

から:

var boom = $parse(iAttrs.data)(scope);

に:

var boom = scope.data.myData

それは私のために働いた、それは使用することが可能です

<boom data="{{myData}}" /> 

ディレクティブで。

2
user1947850

同様の問題がありました

 return {
        restrict: 'AE',
        templateUrl: function(Elm,attrs){return (attrs.scrolled='scrolled' ?'parts/scrolledNav.php':'parts/nav.php')},
        replace: true,
partnersSite.directive('navMenu', function () {
    return {
        restrict: 'AE',
        templateUrl: function(Elm,attrs){return (attrs.scrolled='scrolled' ?'parts/scrolledNav.php':'parts/nav.php')},
        replace: true,
        link: function (scope, Elm, attrs) {
            scope.hidden = true;
            //other logics
        }
    };
});
<nav-menu scrolled="scrolled"></nav-menu>
2
Karb

この問題は、次のようにng-includeで修正されます。

MyApp.directive('boom', function() {
    return {
      restrict: 'E',
      transclude: true,
      scope: 'isolate',
      locals: { data: 'bind' },
      templateUrl: '<div ng-include="templateUrl"></div>',
      link: function (scope) {
        function switchTemplate(temp) {
          if (temp == 'x')
          { scope.templateUrl = 'XTemplate.html' }
          else if (temp == 'y')
          { scope.templateUrl = 'YTemplate.html' }
        }
      }
    }
});

ディレクティブのリンク関数で任意のtempパラメーターを指定してswitchTemplate関数を呼び出します。

1
Iman Bahrampour

これは、以前の回答に関するいくつかの問題に対処するフォローアップ回答です。特に、テンプレートを一度だけコンパイルします(ページ上にこれらがたくさんある場合は重要です。リンクされた後、テンプレートへの変更を監視します。また、元の要素からクラスとスタイルをテンプレート(「replace:true」を使用すると、angularは内部的に非常にエレガントな方法ではありません。テンプレートまたはtemplateUrlの関数を使用する現在のangularサポート方法とは異なり、スコープ情報を使用してロードするテンプレートを決定します。

.directive('boom', ['$http', '$templateCache', '$compile', function ($http, $templateCache, $compile) {
    //create a cache of compiled templates so we only compile templates a single time.
    var cache= {};
    return {
        restrict: 'E',
        scope: {
            Template: '&template'
        },
        link: function (scope, element, attrs) {
            //since we are replacing the element, and we may need to do it again, we need
            //to keep a reference to the element that is currently in the DOM
            var currentElement = element;
            var attach = function (template) {
                if (cache[template]) {
                    //use a cloneAttachFn so that the link function will clone the compiled elment instead of reusing it
                    cache[template](scope, function (e) {
                        //copy class and style
                        e.attr('class', element.attr('class'));
                        e.attr('style', element.attr('style'));
                        //replace the element currently in the DOM
                        currentElement.replaceWith(e);
                        //set e as the element currently in the dom
                        currentElement = e;
                    });
                }
                else {
                    $http.get('/pathtotemplates/' + template + '.html', {
                        cache: $templateCache
                    }).success(function (content) {
                        cache[template] = $compile(content);
                        attach(template);
                    }).error(function (err) {
                        //this is something specific to my implementation that could be customized
                        if (template != 'default') {
                            attach('default');
                        }
                        //do some generic hard coded template
                    });
                }
            };

            scope.$watch("Template()", function (v, o) {
                if (v != o) {
                    attach(v);
                }
            });
            scope.$on('$destroy', function(){
                currentElement.remove();
            });
        }
    };
} ])
1
Joe Enzminger

これらの答えは良いですが、専門的ではありません。よく使用しないtemplateUrlを使用する構文があります。urlを返す関数でもかまいません。関数にはいくつかの引数があります。ここにもっと欲しいなら、クールな記事があります

http://www.w3docs.com/snippets/angularjs/dynamically-change-template-url-in-angularjs-directives.html

0