Casablanca: AngularJs feuert nicht

Hallo Forum,

ich arbiete mit c#-MVC. Da lade ich in einem Bereich via Links

@Ajax.ActionLink(@"MySite", "", "", new { id = id }, new AjaxOptions { UpdateTargetId = "MyContainer" })

unterschiedliche Teil-Datein (Partials), die jeweils eine eigene AngularJs-Controller haben. Das Problem ist, dass keiner der Controller feuert, wenn man die Dateien so zur Laufzeit lädt. Hat jemand eine Idee, wie man diesen Effekt beseitigt?

Danke im Voaus

  1. Tach!

    ich arbiete mit c#-MVC. Da lade ich in einem Bereich via Links unterschiedliche Teil-Datein (Partials), die jeweils eine eigene AngularJs-Controller haben.

    Wie "haben" sie den denn da? Was die Serverseite macht, ist egal. Wie sieht das aus, was der Client zu Gesicht bekommt (gekürzt auf einen nackigen Controller, aber das Drumherum muss sichtbar sein.)

    Das Problem ist, dass keiner der Controller feuert, wenn man die Dateien so zur Laufzeit lädt. Hat jemand eine Idee, wie man diesen Effekt beseitigt?

    Warum müssen die Controller zur Laufzeit eingebunden werden? Können die nicht statisch vorhanden sein?

    dedlfix.

    1. Hi,

      danke für deine Antwort. Ich glaube, ich verstehe nicht ganz, was du meinest. Ich versuche es anders: Gehen wir von 3 Seiten aus. Jede Seite hat als Inhalt nur das da:

      <div ng-controler"controller1 (bis 3)" ng-init="function1-3(id)">
         <span ng-binding="myValue1 (bis 3)"></span>
      <div>
      

      Jeder Controller hat ein Inteval, das den Wert des Span-Elements alle 5-Sekunden ändert. Dieses Interval ruft die function1-3, die jeweils in einem Controller steht auf.

      myApp.controller('controller1', ['$scope', function($scope, $interval) {
        $scope.function1 = function(value) { $scope.myValue1 = value * 2; };
      }]);
      
      $interval($scope.function1 ..., 5000)
      

      Und ich habe auch drei Links wie folgt:

      @Ajax.ActionLink(@"MySite1", "", "", new { id = id }, new AjaxOptions { UpdateTargetId = "MyContainer" })
      
      @Ajax.ActionLink(@"MySite2", "", "", new { id = id }, new AjaxOptions { UpdateTargetId = "MyContainer" })
      
      @Ajax.ActionLink(@"MySite3", "", "", new { id = id }, new AjaxOptions { UpdateTargetId = "MyContainer" })
      
      <div id="MyContainer"></div>
      
      

      Nun beim ersten mal und beim Einstieg wird die erste Seite geladen und da funktioniert auch alles gut. Wenn man aber über einen ActionLink eine andere Seite in den Container lädt, wird die entsprechende function in der Controller, die in ng-init drin steht, nicht meher aufgerufen.

      Gruß

      1. Tach!

        Und ich habe auch drei Links wie folgt:

        @Ajax.ActionLink(@"MySite3", "", "", new { id = id }, new AjaxOptions { UpdateTargetId = "MyContainer" })
        
        <div id="MyContainer"></div>
        

        Die interessieren für das Problem nicht, weil sie serverseitig arbeiten. Die einzige Information, die man daraus entnehmen kann, ist die ID von dem Element, in das das Ergebnis geladen wird. Die ID allein reicht aber nicht, um das Problem zu verstehen. Allerdings hast du diesmal noch eine Zeile hinzugefügt. Und die gibt nun wenigstens Auskunft über einen Teil der Gegebenheiten. Was auch immer du holst, wird also in ein div geladen.

        Was weiterhin fehlt ist die Information, was konkret der Ajax-Aufruf vom Server holt.

        <div ng-controler="controller1" ng-init="function1(id)">
           <span ng-binding="myValue1"></span>
        <div>
        

        Wo steht dieser Code? Bereits in der Seite oder ist das der Teil, der vom Ajax-Aufruf zurückkommt?

        myApp.controller('controller1', ['$scope', function($scope, $interval) {
          $scope.function1 = function(value) { $scope.myValue1 = value * 2; };
        }]);
        
        $interval($scope.function1 ..., 5000)
        

        Wo steht dieser Code? Bereits in der Seite oder ist das der Teil, der vom Ajax-Aufruf zurückkommt?

        Nun beim ersten mal und beim Einstieg wird die erste Seite geladen und da funktioniert auch alles gut. Wenn man aber über einen ActionLink eine andere Seite in den Container lädt, wird die entsprechende function in der Controller, die in ng-init drin steht, nicht meher aufgerufen.

        Tja, damit kann ich noch nichts anfangen, weil mir die Zusammenhäge noch nicht klar sind.

        Andere Idee: Reicht es nicht, wenn HTML (vielleicht auch als Angular-Template) und Javascript bereits in der Seite sind (direkt oder verlinkt ist dabei egal) und der Ajax-Aufruf nur Daten zurückgibt, die dann passend eingebaut werden? Dann wäre es vermutlich auch besser, wenn du den Ajax-Aufruf mit den Angular-Möglichkeiten ausführst. In dem Fall gibts ja dann auch ein Promise, in dessen then-Handler du machen kannst, was auch immer du machen musst.

        dedlfix.

        1. Hallo,

          dnake. Ich habe gedacht, ich habe bereits alles darüber, wo alles steht, angegeben. Dieser Code steht in der z.B. Index.cshtml

          @Ajax.ActionLink(@"Link1", "Partial1", "MyController", new { id = id }, new AjaxOptions { UpdateTargetId = "MyContainer" })
          
          @Ajax.ActionLink(@"Link2", "Partial2", "MyController", new { id = id }, new AjaxOptions { UpdateTargetId = "MyContainer" })
          
          @Ajax.ActionLink(@"Link3", "Partial3", "MyController", new { id = id }, new AjaxOptions { UpdateTargetId = "MyContainer" })
          
          <div ng-app="eventModule">
             <div id="MyContainer"></div>
          </div>
          

          und ruft jeweils die Partial1-3.cshtml, in denen jeweils diese Codes stehen:

          Partial1.cshtml:
          <div ng-controler="controller1" ng-init="function1(id)">
             <span ng-binding="myValue1"></span>
          <div>
          
          Partial2.cshtml:
          <div ng-controler="controller2" ng-init="function2(id)">
             <span ng-binding="myValue2"></span>
          <div>
          
          Partial3.cshtml:
          <div ng-controler="controller3" ng-init="function3(id)">
             <span ng-binding="myValue3"></span>
          <div>
          

          dieser Code wird in div-Element mit der id=MyContainer geladen. Die Controller stehen alle separat in einer js-Datei:

          eventModule.controller('controller1', ['$scope', function($scope, $interval) {
            $scope.function1 = function(value) { $scope.myValue1 = value * 2; };
          
            $interval($scope.function1 ..., 5000)
          }]);
          
          eventModule.controller('controller2', ['$scope', function($scope, $interval) {
            $scope.function2 = function(value) { $scope.myValue2 = value * 3; };
          
            $interval($scope.function2 ..., 5000)
          }]);
          
          eventModule.controller('controller3', ['$scope', function($scope, $interval) {
            $scope.function3 = function(value) { $scope.myValue3 = value * 4; };
          
            $interval($scope.function3 ..., 5000)
          }]);
          
          

          Ich hoffe, dass jetzt alles etwas besser zu verstehen ist ist.

          Gruß

          1. Tach!

            Ich habe gedacht, ich habe bereits alles darüber, wo alles steht, angegeben.

            Mir war das jedenfalls bisher nicht klar, weil deine Ausführungen mir zu viel Interpretationsspielraum gelassen haben. Jetzt hast du alles konkret benannt und damit kann ich was anfangen.

            Du lädst also außerhalb der Angular-Welt mit dem von ASP.NET MVC bereitgestellten Ajax-Mechanismus ein Stück HTML nach. Und nun kommt kein Angular vorbei, um selbiges zu parsen und den Controller darin zu erkennen.

            Es sieht zwar für den Anfang so aus, als ob Angular (selbst)ständig alles auf Veränderungen überprüft und dann tätig wird. Das ist aber keineswegs der Fall. Wenn sich nichts tut, macht auch Angular nichts. Erst wenn ein Ereignis auftritt, von dem Angular Wind bekommt - und das war der entscheidende Nebensatz - läuft der Digest-Zyklus los. Inwiefern es allerdings hinzugefügtes HTML feststellen kann, weiß ich nicht. Ich bin da eher skeptisch. Meines Erachtens wird das HTML nicht ständig geparst, nur einmal am Anfang und dann merkt sich Angular, wo was zu tun ist.

            Hmm, mal die Suche nach „angular add html ajax“ befragt, und da lautet die Antwort $compile. Damit kannst du deine ASP.NET-MVC-Ajax-Aufrufe (zumindest in der jetzigen Form) vergessen, weil die das HTML direkt einbinden und nicht als String zum Zwecke der Übergabe an $compile() liefern.

            Mein Vorschlag ist, dass du statt die Partials nachzuladen, dir stattdessen eine Direktive gemäß dem Angular-Weg erstellst. Zur Not geht auch fest verdrahteter HTML-Code (mit Angularzeugs drin). Diese Teile lässt du mit ng-if oder ng-show/ng-hide nach Bedarf verschwinden und auftauchen. Die variablen Daten holt sich JSON-verpackt ein Angular-Ajax-Aufruf. Lass das ASP.NET-MVC-Ajax-Zeug raus, das spielt nicht mit dem Angular zusammen.

            dedlfix.