2016-06-15 6 views
4

Ich habe ‚Frage‘ Controller, die für Arten von Eingängen eine Reihe von Richtlinien im HTML enthält:Angular/Ionic: Wie kann ich eine Anweisung aktualisieren, wenn ich Variablen im Controller aktualisiere?

<my-text ng-attr-ref="{{ref}}" ng-if="type=='text'"></my-text> 
<my-integer ng-attr-ref="{{ref}}" ng-if="type=='integer'"></my-integer> 
<my-decimal ng-attr-ref="{{ref}}" ng-if="type=='decimal'"></my-decimal> 

etc

zwischen jeder Frage zu navigieren, ich aktualisieren Sie einfach die ‚ref‘ auf die nächste Frage 'ref' und dann aktualisieren Sie den Typ der Frage usw., und Winkel zeigt die entsprechende Art der Eingabe, basierend auf den oben genannten Anweisungen, und verbirgt die vorherige Eingabe.

Ich verwende eine Link-Funktion in meinen Anweisungen für jeden der oben genannten, um den Fragetext einzurichten und an die Antwort für jede Frage zu binden.

angular.module('question.directives') 
/** 
* Text directive 
*/ 
.directive('myText', function ($compile, PARAMETERS) { 
    return { 
     restrict: 'E', 
     templateUrl: PARAMETERS.COMPONENTS_PATH + 'question/inputs/text/my-text.html', 
     scope: true, 
     link: function (scope, element, attrs) { 
      // Get closest parent scope 
      var parent = scope.$parent; 
      // Question input details 
      var inputDetails = parent.inputs[attrs.ref].data; 
      scope.question = inputDetails.question; 
      // Set the answer for this question (based on answers stored in parent scope) 
      scope.answer = parent.answers[attrs.ref]; 
     } 
    }; 
}); 

Dies funktioniert gut, bis ich von einer Texteingabe navigieren, zum Beispiel an einem anderen Texteingabe, und die Richtlinie nicht aktualisiert wird und so sehe ich die gleiche Frage zweimal in Folge. Navigieren von einem Typ zu einem anderen Typ funktioniert gut.

Dies war in einem Versuch, das Flackern von dynamischen Variablen zu reduzieren, da ich zuvor $ state.go() verwendet habe, um zum gleichen Controller zu gehen und die Ansicht mit den aktualisierten Fragedetails neu zu laden. Auf diese Weise verwende ich den gleichen HTML-Code und aktualisiere nur die Anweisungen, die ich brauche, anstatt die gesamte Ansicht neu zu erstellen.

Hat jemand anderes dieses Problem mit flackernden ionischen Variablen in Ansichten, oder kann jemand vorschlagen, wie ich den Controller zwingen kann, die Direktive zu aktualisieren? Ich habe cache-view="false" bereits in der Ansicht festgelegt.

Here's a simple plunker. Wie Sie sehen werden, wenn ich auf "weiter" von Frage 3 zu Frage 4 klicke, sehe ich Frage 3 zweimal, weil ich die my-text Direktive zweimal hintereinander benutze. In ähnlicher Weise zeigt das Klicken auf "vorher" aus Frage 5, Frage 4 zweimal hintereinander.

Danke!

EDIT: Also was ich getan habe, war ein Objekt params zum Controller-Bereich hinzufügen und currentIndex als eine Eigenschaft hinzufügen. Als ich das über scope.$watch('params.currentIndex', update); in der Link-Funktion beobachtet habe, hat es korrekt die Update-Funktion aufgerufen, die die Parameter in meiner Direktive aktualisiert hat.

Ich habe hinzugefügt this neue Plocker, um die Änderungen, die ich gemacht habe, zu reflektieren.

+0

Haben Sie versucht [dies] (http://stackoverflow.com/questions/19338684/angularjs-force-re-rendering-full-refresh-a-directive-template)? U sollte versuchen, auch Scope-Variable anstelle von 'ng-attr-ref' zu verwenden. – zion

+0

@zion Danke für den Link, aber ui-wenn scheint aus eckigen entfernt worden, und die ng-wenn ich bereits benutze. Es scheint, dass der Wechsel von einer Texteingabe zu einer anderen Texteingabe so schnell geschieht, dass es keine Chance zum Aktualisieren erhält. Ich habe versucht, 'currentQuestion.type' auf null zu setzen und dann ein setTimeout hinzuzufügen, das um 500ms verzögert wurde, wobei ich 'currentQuestion.type' wieder auf 'text' setzte und das funktionierte. Ich will aber kein setTimeout dort ... – Antonio

+0

Noch ein Vorschlag, ist die Direktiven in ein Div am Anfang .. Wenn eine vorherige oder nächste Schaltfläche geklickt wird .. 1. Leeren Sie das Div 2. kompilieren Sie die Direktiven 3. Fügen Sie sie der Div ... Es ist ein Hack, aber das sollte funktionieren .. – zion

Antwort

1

Okay, Sie verwenden die Link-Funktion, um den angezeigten Wert zu aktualisieren, aber die Link-Funktion wird nur einmal zur Kompilierzeit aufgerufen. Also auf der ersten Seite laden Sie Ihre Anweisung kompiliert und Link heißt. Dann gehen Sie zur nächsten Frage, die einen anderen Typ hat, der bewirkt, dass ng-if ausgelöst wird. Jetzt entfernt ng-if die erste Direktive aus dem dom und fügt die zweite zu dom hinzu, die jetzt die Link-Methode aufruft.

Wenn Sie Ihre erste Anweisung beibehalten, ruft sie die Link-Funktion nicht auf, weil Sie die Direktive wiederverwenden.

Ich würde vorschlagen, nur Standard eckigen Bindungen und nicht die Link-Funktion verwenden, weil es nur automatisch für Sie aktualisieren wird.

Wenn Sie weitere Hilfe benötigen, füge ich Beispielcode hinzu.

EDIT:

angular 
    .module('question.directives') 
    .directive('myText', MyTextDirective); 

function MyTextDirective($compile, PARAMETERS) { 
    return { 
     restrict: 'E', 
     scope: { 
      ref: '&' 
     }, 
     templateUrl: PARAMETERS.COMPONENTS_PATH + 'question/inputs/text/my-text.html', 
     controller: MyTextController 
    }; 
} 

function MyTextController($scope) { 
    $scope.$watch(() => this.ref, update); 

    function update() { 
     $scope.question = $scope.$parent.inputs[this.ref].question; 
     $scope.answer = $scope.$parent.answers[this.ref]; 
    } 
} 

Was dies tut, ist es eine Direktive mit dem Attribut 'ref' registriert und einen Controller. Der Controller registriert einen Watcher für das Attribut 'ref' und ruft update() jedes Mal auf, wenn sich der Wert von 'ref' ändert.

update() funktioniert genauso wie in der Link-Funktion, nur mit unterschiedlicher Formatierung.

Das ist jetzt nicht super effizient, aber es sollte funktionieren. Abhängig von Ihrer eckigen Version und dem umgebenden Code könnten Sie eine Komponente implementieren, die anstelle einer Referenz die Frage und die Antwort erhält, wodurch die Notwendigkeit eines Beobachters entfällt.

Sie könnten auch eine Funktion verfügbar machen, die aufgerufen wird, wenn die nächste Frage angezeigt werden soll, und dann den Watcher entfernen.

+0

Ja, genau. Wenn Sie einen Beispielcode hinzufügen könnten, wäre das sehr hilfreich, da ich mir nicht ganz sicher bin, wie ich zu den Bindungen über die Link-Funktion wechseln würde. Vielen Dank! – Antonio

+0

Hinzugefügt ein Beispiel Code (ungetestet aber sollte so funktionieren) –

+0

Großartig! Dank dafür. Was ich getan habe, war, den Code in der Link-Funktion zu belassen und den Watcher dort anzubringen, indem ich 'params.currentIndex' beobachtete (ich musste die Eigenschaft eines Scope-Objekts und nicht eine Eigenschaft des Scope selbst beobachten) um die Veränderungen zu reflektieren. – Antonio

0

versuchen nur noch einen Versuch,

index.html

<div id="question"> 
    <my-text ng-if="currentQuestion.type=='text'"></my-text> 
    <my-integer ng-if="currentQuestion.type=='integer'"></my-integer> 
</div> 

script.js

$scope.next = function() { 
    if ($scope.currentIndex < ($scope.questions.length - 1)) { 
     $scope.currentIndex++; 
     $scope.currentQuestion = $scope.questions[$scope.currentIndex]; 
    } 
    updateDiv(); 
    } 

    var updateDiv = function(){ 
    var elem = angular.element(document.querySelector('#question')); 
    elem.html(""); 
    var html = "<div><my-text ng-if=\"currentQuestion.type=='text'\"></my-text><my-integer ng-if=\"currentQuestion.type=='integer'\"></my-integer></div>"; 
    var compiledHTML = $compile(html)($scope); 
    elem.append(compiledHTML); 
    } 

    $scope.previous = function() { 
    if ($scope.currentIndex > 0) { 
     $scope.currentIndex--; 
     $scope.currentQuestion = $scope.questions[$scope.currentIndex]; 
    } 
    updateDiv(); 
    } 

Es ist ein Fehler kommt, aber es behoben werden kann. Ich versuche das herauszufinden.

Verwandte Themen