2017-07-26 5 views
1

Ich bin ein kompletter Anfänger in Angular (1.x) und ich habe versucht, es in die App, die ich gerade entwickle, zu sticken.Force Refresh auf verschachtelte Funktion in Angular

Es empfängt im Grunde die gesamten Benutzerdaten über Ajax (mehrere verschachtelte Arrays) und fährt fort, sie mit verschachtelten ng-repeat-Anweisungen zu rendern. In der innersten Wiederholung führe ich eine Funktion aus, die Daten basierend auf dem aktuellen Datum zurückgibt.

<div ng-repeat="i in rootArray"> 
 
    <div ng-repeat="h in i.array1"> 
 
    <div ng-repeat="j in h.array2"> 
 
     <span>{{dateBasedFunction(j.data)}}</span> 
 
    </div> 
 
    </div> 
 
</div>

Die Daten aus den Funktionsänderungen im Laufe der Zeit (auch wenn der Eingang gleich bleibt), und ich möchte es laufen, um wieder diese Änderungen widerzuspiegeln, ohne erneut die gesamte Struktur Rendering .

Ist es möglich? Ich bin mir nicht sicher, ob ich die Praktiken des besten Frameworks befolge, vielleicht gibt es einen besseren Ansatz?

Danke! hier

+1

hi, wenn Sie ng-repeat verwenden, eckig machen Sie eine schmutzige Beobachtung des Objekts, und aktualisieren Sie die Ansicht auf Änderungen. Du musst es nicht tun. Schräg 1.x machen es alleine –

+0

@ ÁlvaroTouzón ist leider nicht der Fall, da sich die Daten im Objekt selbst nicht ändern. Was sich wirklich ändert, ist die Systemzeit (innerhalb der Funktion), also gibt es keine Möglichkeit, dies herauszufinden ... Ich muss eine Intervallprüfung durchführen, aber ich habe keine Ahnung, welcher Code darauf ausgeführt werden soll! – arvere

+0

Sie müssen wissen, wenn Objekt geändert wird, und diese Änderung wird nicht von Ihrer Verantwortung (wie Ajax, Eingabe ...) getan. Dann müssen Sie einen Beobachter hinzufügen https://docs.angularjs.org/api/ng/type/$rootScope.Scope –

Antwort

0

Hintergrund

Die ng-Wiederholungen keine Probleme verursachen. Wir müssen uns auf die interpolation expression konzentrieren: {{dateBasedFunction(j.data)}}

Angular ist ein watcher zu schmutzig überprüfen den Ausdruck dateBasedFunction(j.data) bei jeder Iteration des digest Zyklus zu schaffen. Wenn sich der resultierende Wert seit dem letzten Digest geändert hat, wird das DOM mit dem neuen Wert aktualisiert.

Das Problem ist, dass nichts in Ihrem Code einen Angular-Digest-Zyklus auslöst.

Arbeitsbeispiel

Hier können wir Ihre Situation sehen durch Arbeiten manuell über Interaktion mit dem Benutzer auslösenden verdauen:

var myApp = angular.module('myApp', []); 
 
myApp.controller('MyCtrl', ['$scope', MyCtrl]); 
 

 
function MyCtrl($scope) { 
 
    
 
    $scope.rootArray = [{ 
 
    "array1": [{ 
 
     "array2": [{ 
 
     "data": "hello" 
 
     }, { 
 
     "data": "world" 
 
     }] 
 
    }] 
 
    }]; 
 

 
    //Dummy $watch alerts whenever digest is called 
 
    $scope.$watch(function() { 
 
    console.log('Digest called'); 
 
    }); 
 

 
    $scope.dateBasedFunction = function(x) { 
 
    var d = new Date(); 
 
    return x + ' (' + d.getMinutes() + ":" + d.getSeconds() + ")"; 
 
    } 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<div ng-app="myApp"> 
 
    <div ng-controller="MyCtrl"> 
 
    
 
    <button ng-click="">ng-click calls digest()</button> 
 
    
 
    <div ng-repeat="i in rootArray"> 
 
     <div ng-repeat="h in i.array1"> 
 
     <div ng-repeat="j in h.array2"> 
 
      <span>{{dateBasedFunction(j.data)}}</span> 
 
     </div> 
 
     </div> 
 
    </div> 
 
    
 
    </div> 
 
</div>

jedes Mal, wenn Sie auf die Schaltfläche klicken, ng-click ein Trigger Winkelverdauung. Dies wertet dateBasedFunction neu aus. Da sich der Wert geändert hat, wird das DOM neu gezeichnet.

Aber ich nehme an, dass Sie sich nicht auf ng-click s verlassen wollen, um das DOM aktualisiert zu halten. Sie möchten, dass Ihr DOM regelmäßig aktualisiert wird, da es sich auf das aktuelle Datum/die aktuelle Uhrzeit ändert.

Mögliche Lösungen

  1. auf einer Frequenz Entscheiden, die sinnvoll für Ihre Bedürfnisse macht, und einen Digest Zyklus periodisch erzwingen:

var myApp = angular.module('myApp', []); 
 
myApp.controller('MyCtrl', ['$scope', MyCtrl]); 
 

 
function MyCtrl($scope) { 
 
    
 
    $scope.rootArray = [{ 
 
    "array1": [{ 
 
     "array2": [{ 
 
     "data": "hello" 
 
     }, { 
 
     "data": "world" 
 
     }] 
 
    }] 
 
    }]; 
 

 
    //Dummy $watch alerts whenever digest is called 
 
    $scope.$watch(function() { 
 
    console.log('Digest called'); 
 
    }); 
 

 
    $scope.dateBasedFunction = function(x) { 
 
    var d = new Date(); 
 
    return x + ' (' + d.getMinutes() + ":" + d.getSeconds() + ")"; 
 
    } 
 
    
 
    //Call $scope.$apply() every second. 
 
    setInterval(function() { 
 
    //$scope.$apply() triggers a digest cycle 
 
    $scope.$apply(); 
 
    }, 1000); 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<div ng-app="myApp"> 
 
    <div ng-controller="MyCtrl"> 
 
    
 
    <div ng-repeat="i in rootArray"> 
 
     <div ng-repeat="h in i.array1"> 
 
     <div ng-repeat="j in h.array2"> 
 
      <span>{{dateBasedFunction(j.data)}}</span> 
 
     </div> 
 
     </div> 
 
    </div> 
 
    
 
    </div> 
 
</div>

  1. Wenn Sie die Häufigkeit der Aktualisierungen kennen, sollten Sie eine Direktive schreiben, die das DOM zur richtigen Zeit direkt aktualisiert, ohne apply() für den gesamten Bereich aufzurufen. Dies wird effizienter, erfordert jedoch mehr Entwicklungsaufwand.

    Genau das macht angular-moment mit ihrer am-time-ago directive. Diese Richtlinie hat ein ähnliches Ziel: Daten zu aktualisieren, die sich als Reaktion auf das aktuelle Datum/die aktuelle Uhrzeit ändern.

  2. Verwenden Angular das Modell für alle Änderungen zu sehen, aber das Datum/die zeitbasierte Änderungen außerhalb von Angular handhaben:

var myApp = angular.module('myApp', []); 
 
myApp.controller('MyCtrl', ['$scope', MyCtrl]); 
 

 
function MyCtrl($scope) { 
 

 
    $scope.rootArray = [{ 
 
    "array1": [{ 
 
     "array2": [{ 
 
     "data": "hello" 
 
     }, { 
 
     "data": "world" 
 
     }] 
 
    }] 
 
    }]; 
 

 
    //Dummy $watch alerts whenever digest is called 
 
    $scope.$watch(function() { 
 
    console.log('Digest called'); 
 
    }); 
 
} 
 

 
function dateBasedFunction(x) { 
 
    var d = new Date(); 
 
    return x + ' (' + d.getMinutes() + ":" + d.getSeconds() + ")"; 
 
} 
 

 
setInterval(function() { 
 
    $('[data-date-based-value]').each(function() { 
 
    this.textContent = dateBasedFunction(this.dataset['dateBasedValue']); 
 
    }); 
 
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<div ng-app="myApp"> 
 
    <div ng-controller="MyCtrl"> 
 

 
    <div ng-repeat="i in rootArray"> 
 
     <div ng-repeat="h in i.array1"> 
 
     <div ng-repeat="j in h.array2"> 
 
     
 
      <!--Set a data-date-based-value attribute--> 
 
      <!--Angular will keep the attribute value updated--> 
 
      <!--But the element's text will be updated via jQuery--> 
 
      <span ng-attr-data-date-based-value="{{j.data}}"></span> 
 
      
 
     </div> 
 
     </div> 
 
    </div> 
 

 
    </div> 
 
</div>

Beachten Sie, dass diese Lösung die Updates DOM direkt, ohne zusätzliche Digest-Zyklen auszuführen.

This article erklärt den Digest-Zyklus gut, wenn Sie mehr über Angular erfahren möchten.