AngularJS-プログラムで新しい分離スコープを作成するにはどうすればよいですか?


81

Angular.factoryを使用してAlertFactoryを作成したいと思います。次のようなhtmlテンプレートを定義しました

var template = "<h1>{{title}}</h1>";

タイトルはコントローラーを呼び出すことによって提供され、次のように適用されます

var compiled = $compile(template)(scope);
body.append(compiled);

では、分離されたスコープをコントローラーからファクトリに渡すにはどうすればよいですか?私はコントローラーのフォローコードで使用しています

AlertFactory.open($scope);

ただし、$ scopeはグローバルコントローラースコープ変数です。タイトルプロパティだけでファクトリの小さなスコープを渡したいだけです。

ありがとうございました。

回答:


107

新しいスコープを手動で作成できます。

$rootScope注入した場合から、またはコントローラースコープからのみ、新しいスコープを作成できます。これは、分離するため、問題ではありません。

var alertScope = $scope.$new(true);
alertScope.title = 'Hello';

AlertFactory.open(alertScope);

ここで重要なのは、に渡すtrueことです$new。これは、の1つのパラメーターを受け入れisolate、親からスコープを継承することを回避します。

詳細については、http//docs.angularjs.org/api/ng.$ro​​otScope.Scope#$newをご覧ください。


10
新しいスコープを手動で作成する場合は、おそらく手動で破棄する必要があります。通常、スコープを手動で作成しないことをお勧めします。
Mark Rajcok 2013年

テストを行いましたが、機能しません。stackoverflow.com/questions/15565462/を
プレミア

3
@MarkRajcokは、通常、スコープを手動で作成しない方がよいと述べています。ただし、htmlを動的に作成する必要があり、そのhtml内で角度ディレクティブを使用する場合の代替手段は何ですか?
lostintranslation 2015

命の恩人!Angular Bootstrap Modalのラッパーを書いていたので、これを行う必要がありました。
ジョナサン

9
子スコープを作成すると(分離するかしないか)、Angularは親が破棄されると自動的に子スコープを破棄します。したがって、この例では、$scopeが破棄されるalertScopeと自動的に破棄されます。したがって、@ MarkRajcokは完全に有効なユースケースであり、完全に安全です。
jkjustjoshing 2015

22

補間するだけでよい場合は、$ compileの代わりに$ interpolateサービスを使用すると、スコープは必要ありません。

myApp.factory('myService', function($interpolate) {
    var template = "<h1>{{title}}</h1>";
    var interpolateFn = $interpolate(template);
    return {
        open: function(title) {
            var html = interpolateFn({ title: title });
            console.log(html);
            // append the html somewhere
        }
    }
});

テストコントローラー:

function MyCtrl($scope, myService) {
    myService.open('The Title');
}

フィドル


2
$ compileと$ interpolateの違いは何ですか?$ interpolateはテキストのみを置き換えますか?
プレミア

3
@プレミア、それは私の理解です。stackoverflow.com/a/13460295/215945も参照してください 。テンプレートにディレクティブが含まれている場合、$ interpolateは機能しません。そのために$ compileを使用する必要があります。
Mark Rajcok 2013年

はい、ありがとうございます。私のタスクには十分ではありません。完全なスコープを持つコントローラーが必要です。
プレミア

1
@Premier、私はあなたがしようとしているもののフィドルまたはプランカーを作成してみることをお勧めします。分離スコープがどこから来ているのかは明確ではありません。
Mark Rajcok 2013年

そうそう、私は1つのstackoverflow.com/questions/15565462/
プレミア

2

手順は次のとおりです。

  1. を使用してHTMLをDOMに追加します var comiledHTML = angular.element(yourHTML);
  2. 必要に応じて新しいスコープを作成します var newScope = $rootScope.$new();
  3. $ comile();を呼び出します。リンク関数を返す関数var linkFun = $compile(comiledHTML);
  4. linkFunを呼び出して、新しいスコープをバインドします var finalTemplate = linkFun(newScope);
  5. finalTemplateをDOMに追加します YourHTMLElemet.append(finalTemplate);

1
var linkFun = $compile(comiledHTML);ステップ2に
iamdevlinph

2

私のプランカーをチェックしてください。レンダリングディレクティブを使用してウィジェットディレクティブをプログラムで生成しています。

https://plnkr.co/edit/5T642U9AiPr6fJthbVpD?p=preview

angular
  .module('app', [])
  .controller('mainCtrl', $scope => $scope.x = 'test')
  .directive('widget', widget)
  .directive('render', render)

function widget() {
  return {
    template: '<div><input ng-model="stuff"/>I say {{stuff}}</div>'
  }
}

function render($compile) {
  return {
    template: '<button ng-click="add()">{{name}}</button><hr/>',
    link: linkFn
  }

  function linkFn(scope, elem, attr) {
    scope.name = 'Add Widget';
    scope.add = () => {
      const newScope = scope.$new(true);
      newScope.export = (data) => alert(data);
      const templ = '<div>' +
                      '<widget></widget>' +
                      '<button ng-click="export(this.stuff)">Export</button>' +
                    '</div>';
      const compiledTempl = $compile(templ)(newScope);
      elem.append(compiledTempl);
    }
  }
}

1

分離スコープについて話しているときは、ディレクティブについて話していると思います。

これがその方法の例です。 http://jsfiddle.net/rgaskill/PYhGb/

var app = angular.module('test',[]);

app.controller('TestCtrl', function ($scope) {
    $scope.val = 'World';
});

app.factory('AlertFactory', function () {

    return {
        doWork: function(scope) {
            scope.title = 'Fun';    
            //scope.title = scope.val;  //notice val doesn't exist in this scope
        }
    };

});

app.controller('DirCtrl', function ($scope, AlertFactory) {
    AlertFactory.doWork($scope);  
});

app.directive('titleVal',function () {
    return {
        template: '<h1>Hello {{title}}</h1>',
        restrict: 'E',
        controller: 'DirCtrl',
        scope: {
            title: '='
        },
        link: function() {

        }
    };

});

基本的に、分離スコープを定義したディレクティブにコントローラーをアタッチします。ディレクティブコントローラーに挿入されるスコープは、分離スコープになります。ディレクティブコントローラーでは、分離スコープを渡すことができるAlertFactoryを挿入できます。


grrr..plnkr.coは現在オフラインのようです。うまくいけば、リンクが戻ってきてもリンクは機能します。
rgaskill 2013年

うーん、それは私にとって良い解決策ではないと思います、私は指令を必要としません。モーダルアラートダイアログを表示できるファクトリが必要です。したがって、テンプレートhtmlをdomオーバーレイに添付し、コントローラーを使用してアラートビューでデータを管理する必要があります。
プレミア

2
工場でdomを操作するべきではないと私は主張します。ビューロジックとビジネスロジックを混在させています。dom操作を実行する必要があるディレクティブで説明したことを正確に実行できます。
rgaskill 2013年

ディレクティブではなくモーダルにサービスを使用することに関するBradGreenの
Mark Rajcok 2013年

...しかし、この特定のブートストラップの場合は、ディレクティブを使用して解決するのが最適だと思います。 plnkr.co/edit/z4J8jH?p=preview
rgaskill
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.