AngularJS - Programlı olarak yeni, yalıtılmış bir kapsam nasıl oluşturabilirim?


81

Angular.factory ile bir AlertFactory oluşturmak istiyorum. Follow gibi bir html şablonu tanımladım

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

Başlık denetleyiciyi çağırarak sağlanır ve aşağıdaki gibi uygulanır

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

Peki, yalıtılmış kapsamı denetleyiciden fabrikaya nasıl geçirebilirim? Kontrolcü takip kodunu kullanıyorum

AlertFactory.open($scope);

Ancak $ kapsam, genel denetleyici kapsam değişkenidir. Sadece tapu mülküyle fabrika için küçük bir kapsam geçmek istiyorum.

Teşekkür ederim.

Yanıtlar:


107

Manuel olarak yeni bir kapsam oluşturabilirsiniz.

$rootScopeEnjekte ettiğinizden veya sadece kontrolör kapsamınızdan yeni bir kapsam oluşturabilirsiniz - bu, onu izole edeceğiniz için önemli olmamalıdır.

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

AlertFactory.open(alertScope);

Burada geçen bir anahtar trueiçin $newiçin bir parametre kabul, isolateebeveynden kapsamı kalıtım yoluyla önler.

Daha fazla bilgi şu adreste bulunabilir: http://docs.angularjs.org/api/ng.$rootScope.Scope#$new


10
Manuel olarak yeni bir kapsam oluşturursanız, muhtemelen manuel olarak da imha etmeniz gerekecektir. Normalde kapsamları manuel olarak oluşturmamak daha iyidir.
Mark Rajcok

Bir test yaptım ama işe yaramıyor. Lütfen stackoverflow.com/questions/15565462/… sayfasına bakın
Premier

3
@MarkRajcok, kapsamları manuel olarak oluşturmamanın normalde daha iyi olduğunu söylüyorsunuz. Bununla birlikte, html'yi dinamik olarak oluşturmanız gerekiyorsa ve bu html içinde açısal bir yönerge kullanmak istiyorsanız, alternatif nedir?
lostintranslation

Hayat kurtarıcı! Angular Bootstrap Modal için bir sarmalayıcı yazarken bunu yapmak zorundaydım .
Jonathan

9
Bir alt kapsam oluşturduğunuzda (izole edin veya izole etmeyin), Angular, üst öğesi yok edildiğinde onu otomatik olarak yok eder. Yani bu örnekte, $scopeyok alertScopeedildiğinde otomatik olarak da yok edilir. Yani @MarkRajcok, bu tamamen geçerli bir kullanım durumu ve tamamen güvenlidir.
jkjustjoshing

22

Yalnızca bir şeyleri enterpolate etmeniz gerekiyorsa , $ compile yerine $ interpolate hizmetini kullanın, o zaman bir kapsama ihtiyacınız olmaz:

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
        }
    }
});

Test kontrolörü:

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

Vaktini boşa harcamak


2
$ Compile ve $ interpolate arasındaki fark nedir? $ interpolate yalnızca metnin yerini alır?
Premier

3
@Premier, bu benim anlayışım. Ayrıca bkz. Stackoverflow.com/a/13460295/215945 Şablonunuz yönergeler içeriyorsa, $ interpolate çalışmaz - bunun için $ compile kullanmanız gerekir.
Mark Rajcok

Tamam teşekkürler. Görevim için yeterli değil, tam kapsamlı bir denetleyiciye ihtiyacım var.
Premier

1
@Premier, denediğiniz şeyden bir keman veya plancı yaratmayı denemenizi öneririm. İzolat kapsamınızın nereden geldiği belli değil.
Mark Rajcok


2

Adımlar aşağıda verilmiştir:

  1. Kullanarak HTML'nizi DOM'a ekleyin var comiledHTML = angular.element(yourHTML);
  2. İsterseniz yeni bir Kapsam oluşturun var newScope = $rootScope.$new();
  3. $ Comile (); bağlantı işlevini döndüren işlevvar linkFun = $compile(comiledHTML);
  4. LinkFun'u çağırarak yeni kapsamı bağlayın var finalTemplate = linkFun(newScope);
  5. FinalTemplate'i DOM'nuza ekleyin YourHTMLElemet.append(finalTemplate);

1
var linkFun = $compile(comiledHTML);2. adımdan itibaren
iamdevlinph

2

plunkr'ımı kontrol et. Oluşturma yönergesiyle programlı olarak bir pencere öğesi yönergesi oluşturuyorum.

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

İzole kapsamdan bahsederken bir direktiften bahsettiğinizi varsayıyorum.

İşte nasıl yapılacağına dair bir örnek. 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() {

        }
    };

});

Temel olarak, bir izolat kapsamı tanımlayan bir yönergeye bir denetleyici ekleyin. Yönerge denetleyicisine enjekte edilen kapsam, ayrı bir kapsam olacaktır. Yönerge denetleyicisinde, izolat kapsamını geçirebileceğiniz AlertFactory'nizi enjekte edebilirsiniz.


grrr..plnkr.co şu anda çevrimdışı görünüyor. Umarım bağlantı geri geldiğinde hala çalışır.
rgaskill

Mmmm, bunun benim için iyi bir çözüm olmadığını düşünüyorum, bir yönergeye ihtiyacım yok. Kalıcı uyarı iletişim kutusunu göstermek için fabrika özelliklerine ihtiyacım var. Bu yüzden, etki alanı katmanına şablon html eklemem ve uyarı görünümünde verileri yönetmek için bir denetleyici kullanmam gerekiyor.
Premier

2
Bir fabrikada domu manipüle etmemen gerektiğini iddia ediyorum. Görünüm mantığınızı iş mantığınızla karıştırıyorsunuz. Dom manipülasyonunun gerçekleşmesi gereken bir yönergede tanımladığınız şeyi tam olarak yapabilirsiniz.
rgaskill

Brad Green'in Andy'ye, bir direktif yerine modal bir hizmet kullanımıyla ilgili cevabına bakın
Mark Rajcok

... Ama bu özel önyükleme vakası için, bence en iyisi bir yönerge ile çözülür. plnkr.co/edit/z4J8jH?p=preview
rgaskill
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.