AngularJS - Wie kann ich programmgesteuert einen neuen, isolierten Bereich erstellen?


81

Ich möchte eine AlertFactory mit Angular.factory erstellen. Ich habe eine HTML-Vorlage wie folgt definiert

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

Der Titel wird vom aufrufenden Controller bereitgestellt und wie folgt angewendet

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

Wie kann ich also einen isolierten Bereich vom Controller an die Fabrik übergeben? Ich verwende im Controller den folgenden Code

AlertFactory.open($scope);

$ Scope ist jedoch eine globale Controller-Scope-Variable. Ich möchte nur einen kleinen Bereich für die Fabrik mit nur Titeleigenschaft übergeben.

Danke dir.

Antworten:


107

Sie können einen neuen Bereich manuell erstellen.

Sie können einen neuen Bereich erstellen $rootScope, indem Sie ihn einfügen oder nur aus Ihrem Controller-Bereich - dies sollte keine Rolle spielen, da Sie ihn isoliert machen.

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

AlertFactory.open(alertScope);

Der Schlüssel hier ist die Übergabe truean $new, die einen Parameter für akzeptiert isolate, wodurch vermieden wird, dass der Bereich vom übergeordneten Element übernommen wird.

Weitere Informationen finden Sie unter: http://docs.angularjs.org/api/ng.$rootScope.Scope#$new


10
Wenn Sie einen neuen Bereich manuell erstellen, müssen Sie ihn wahrscheinlich auch manuell zerstören. Normalerweise ist es besser, Bereiche nicht manuell zu erstellen.
Mark Rajcok

Ich habe einen Test gemacht, aber es funktioniert nicht. Bitte schauen Sie auf stackoverflow.com/questions/15565462/…
Premier

3
@MarkRajcok Sie erwähnen, dass es normalerweise besser ist, Bereiche nicht manuell zu erstellen. Was ist jedoch die Alternative, wenn Sie HTML dynamisch erstellen und eine Winkelanweisung in diesem HTML verwenden möchten?
Verlorene Übersetzung

Lebensretter! Musste dies tun, als ich einen Wrapper für Angular Bootstrap Modal schrieb .
Jonathan

9
Wenn Sie einen untergeordneten Bereich erstellen (isolieren oder nicht isolieren), zerstört Angular ihn automatisch, wenn sein übergeordneter Bereich zerstört wird. In diesem Beispiel $scopewird alertScopealso auch automatisch zerstört , wenn es zerstört wird. @MarkRajcok Dies ist also ein absolut gültiger Anwendungsfall und absolut sicher.
jkjustjoshing

22

Wenn Sie nur Dinge interpolieren müssen, verwenden Sie den Dienst $ interpolate anstelle von $ compile, und dann benötigen Sie keinen Bereich:

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

Testregler:

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

Geige


2
Was ist der Unterschied zwischen $ compile und $ interpolate? $ interpolate lässt nur Text ersetzen?
Premier

3
@Premier, das ist mein Verständnis. Siehe auch stackoverflow.com/a/13460295/215945 Wenn Ihre Vorlage Anweisungen enthält, funktioniert $ interpolate nicht - Sie müssten dafür $ compile verwenden.
Mark Rajcok

OK danke. Es ist nicht genug für meine Aufgabe, ich brauche einen Controller mit vollem Umfang.
Premier

1
@Premier, ich schlage vor, Sie versuchen, eine Geige oder einen Plunker von dem zu erstellen, was Sie versuchen. Es ist nicht klar, woher Ihr isolierter Bereich stammt.
Mark Rajcok


2

Folgendes sind die Schritte:

  1. Fügen Sie Ihren HTML-Code mithilfe von zum DOM hinzu var comiledHTML = angular.element(yourHTML);
  2. Erstellen Sie einen neuen Bereich, wenn Sie möchten var newScope = $rootScope.$new();
  3. Rufen Sie $ comile () auf; Funktion, die die Link-Funktion zurückgibtvar linkFun = $compile(comiledHTML);
  4. Binden Sie den neuen Bereich, indem Sie linkFun aufrufen var finalTemplate = linkFun(newScope);
  5. Hängen Sie finalTemplate an Ihr DOM an YourHTMLElemet.append(finalTemplate);

1
Ab var linkFun = $compile(comiledHTML);Schritt 2
iamdevlinph

2

Schau dir meinen Plunkr an. Ich generiere programmgesteuert eine Widget-Direktive mit einer Render-Direktive.

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

Ich nehme an, wenn Sie über einen isolierten Bereich sprechen, sprechen Sie über eine Richtlinie.

Hier ist ein Beispiel dafür. 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() {

        }
    };

});

Fügen Sie einen Controller grundsätzlich einer Direktive hinzu, die einen isolierten Bereich definiert hat. Der in den Direktivencontroller eingefügte Bereich ist ein isolierter Bereich. Im Direktiven-Controller können Sie Ihrer AlertFactory injizieren, an die Sie den Isolate-Bereich übergeben können.


grrr..plnkr.co scheint gerade offline zu sein. Hoffentlich funktioniert der Link immer noch, wenn er zurückkommt.
Rgaskill

Mmmm ich denke es ist keine gute Lösung für mich, ich brauche keine Direktive. Ich benötige eine Factory-Funktion, um einen modalen Warndialog anzuzeigen. Also muss ich Vorlage HTML in Dom Overlay anhängen und einen Controller verwenden, um Daten in der Warnansicht zu verwalten.
Premier

2
Ich würde argumentieren, dass Sie den Dom in einer Fabrik nicht manipulieren sollten. Sie mischen Ihre Ansichtslogik mit Ihrer Geschäftslogik. Sie könnten genau das tun, was Sie in einer Anweisung beschrieben haben, in der die Dom-Manipulation stattfinden soll.
Rgaskill

Siehe Brad Green's Antwort an Andy bezüglich der Verwendung eines Dienstes für ein Modal anstelle einer Direktive: blog.angularjs.org/2012/11/about-those-directives.html
Mark Rajcok

... Aber für diesen speziellen Bootstrap-Fall denke ich, dass er am besten mit einer Direktive gelöst werden kann. plnkr.co/edit/z4J8jH?p=preview
rgaskill
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.