2016-04-05 3 views
1

Also baue ich eine Website für einen Kunden. Auf unserer Suchseite beobachte ich die Suchleiste und bei jedem Tastendruck wird eine neue Suchanfrage ausgelöst, damit die Ergebnisse während der Eingabe aktualisiert werden. Mein Problem ist, wenn ich einen Suchbegriff wirklich schnell eintippe, kann der Server "hickup" und gibt meine Ergebnisse nicht in der Reihenfolge zurück, in der ich sie angefordert habe. Dies führt dazu, dass nur einige Teile meines Markups, die an die zurückgegebenen Daten gebunden sind, die falschen Werte anzeigen. Beispielsweise. Wenn ich das Wort "Video" eintippe. 99% der Zeit bekomme ich die richtigen Ergebnisse und alle meine Etiketten sehen korrekt aus. In 1% der Fälle wird meine Suche nach "vide" jedoch nach meiner Suche nach dem "Video" zurückkehren, was dazu führt, dass die falschen Ergebnisse und die falsche Summe angezeigt werden. Leider kann ich aufgrund einer Geheimhaltungsvereinbarung keine Live-Demo verlinken, aber ich kann den Code posten, der das ausführt. Wir befinden uns in den späten Phasen der Produktion, daher ist es wichtiger, sie so schnell wie möglich funktionsfähig zu machen, als Best Practice zu verwenden. Einige Stücke der html:Während der Eingabe von Angular nach genauen Ergebnissen suchen, wenn der Server die Daten nicht in der angeforderten Reihenfolge zurückgibt?

<h1>Search</h1> 
       <p ng-cloak class="results-message fade-in"> 
        <span ng-if="items.loaded &amp;&amp; term">{{total}} results for "{{term}}" </span>   
        <span ng-if="!total &amp;&amp; !term">No query was entered </span> 
        <span ng-if="!items.loaded &amp;&amp; term">Searching...</span> 
       </p> 
       <div class="search-container">   
        <input type="search" name="term" value="asd" ng-init="term='asd'" ng-model="term" placeholder="Enter your search term" ng-keydown="$event.keyCode == 13 ? $event.preventDefault() : 0;" class="search"> 
        <input type="image" name="submit" src="/_res/astoncarter/img/images/search-icon.gif" alt="Submit"> 
       </div> 
      </div> 

<ul ng-cloak ng-class="{loading: loading}" class="results"> 
       <li ng-if="items.loaded && !items.length && term" class="fade-in"> 
        <h2>No results were found for {{term}}</h2> 
       </li> 
       <li ng-if="!term" class="fade-in"> 
        <p class="text-center">Please enter a search query</p> 
       </li> 
       <li ng-repeat="item in items" class="fade-in"> 
        <h2><a href="{{item.url}}">{{item.title}}</a></h2> 
        <p>{{item.teaser}}</p> 
       </li> 
      </ul> 
     </div> 
    </div> 
</div> 
<p ng-if="count == 10" class="load-more"><a href="" ng-if="!loading" ng-click="loadQuery()" class="btn">Load More</a><a href="" ng-if="loading" disabled class="btn"><i class="fa fa-spinner fa-spin"> </i> LOAD</a></p> 

Die JS:

app.controller('ListingCtrl', function ($scope, $element, $timeout, acAPIservice, $location, $interval) { 
    // Grabbing and using the attribute from the dom is not the Angular way 
    // but a compromize if we want BE developers to be able to set the API 
    // Other options would be to set a global variable to be output and used 
    $scope.apiUrl = $element.attr('data-api-url'); 
    $scope.pageSize = $element.attr('data-page-size'); 
    $scope.language = $element.attr('data-language'); 
    $scope.timer = 3; 

    $scope.term = undefined; 
    $scope.items = []; 
    $scope.start = 0; 
    $scope.end = 0; 
    $scope.total = 0; 
    $scope.loading = false; 


// main worker to get data 
// lists that need data should call this on ng-init 
$scope.loadQuery = function(){ 
    $scope.loading = true; 

    var payload = { 
    pageSize : $scope.pageSize, 
    start : $scope.end+1, 
    language : $scope.language 
    }; 
    if($scope.term) { 
    payload.term = $scope.term 
    } 

    acAPIservice.getSearch($scope.apiUrl, payload) //this just hits a factory with the url and payload and returns the data object 
    .success(function (data) { 
    $scope.timer = 3; //reset the timer 
    $scope.items = $scope.items.concat(data.results); 
    $scope.start = data.start; 
    $scope.end = data.end; 
    $scope.total = data.total; 
    $scope.loading = false; 
    $scope.items.loaded = true; 
    $scope.count = data.count; 
    }) 
    .error(function(data, status, headers, config){  
    $scope.items = []; 
    $scope.items.loaded = true; 
    }); 
}; 

// cheating a bit here. We let the ng-init attribute for term trigger 
// the first batch. Also grabs new batches when term is updated 
$scope.$watch('term', function(newValue, oldValue) { 
// reset everything 
$scope.items = []; 
$scope.start = 0; 
$scope.end = 0; 
$scope.total = 0; 
// if we still have a search term go get it 
if($scope.term){ 
    $scope.loadQuery(); 

    //because you can't turn off async in angular we need to set a timer that gets reset every time you load a query.  After 1 second we recall to make sure our total reflects the accurate num 
    var promise = $interval(function(){ 
     $scope.timer = $scope.timer-1; 
     if($scope.timer === 0){ //if the timer runs out it means that no terms have been entered in 1 second, which we will then cancel the interval and and do one last load 
     $interval.cancel(promise); 
     $scope.loadQuery(); 
     } 
    }, 500); 
} 
    }); 
}); 

Es zeigt immer die richtige Suchbegriff ein, aber es wird angezeigt die {{total}}, von welcher zurückgegeben letzte und es scheint, wie die Ergebnisse der letzten 2 Rückmeldungen zusammengefügt werden.

Ich habe gerade versucht, das Intervall zu implementieren, um die Ergebnisse zu "sortieren", nachdem eine Sekunde vergangen ist, ohne dass der Benutzer tippt, aber manchmal kann der Server länger als 1 Sekunde dauern, was bedeutet, dass er immer noch mit der falschen Information aktualisiert wird. Bitte stellen Sie mir Fragen, wenn Sie mich etwas aufklären müssen. Es fällt mir manchmal schwer, meine Probleme zu erklären. Entschuldigen Sie auch die Formatierung :(

+0

Haben Sie über eine Entprellung nachgedacht? Dies wird das Problem nicht beheben, aber es wird es mildern ... Siehe https://docs.angularjs.org/api/ng/directive/ngModelOptions#! –

Antwort

0

Geben Sie einfach den Text zurück, nach dem in den Ergebnissen gesucht wurde. Wenn das Versprechen gelöst ist, wenn der zurückgegebene Text nicht dem aktuellen Text entspricht, kehren Sie aus der Funktion zurück.

acAPIservice.getSearch($scope.apiUrl, payload) 
    .success(function (data) { 
    if (data.term !== $scope.term) { 
     return; 
    } 

    $scope.timer = 3; //reset the timer 
    $scope.items = $scope.items.concat(data.results); 
    $scope.start = data.start; 
    $scope.end = data.end; 
    $scope.total = data.total; 
    $scope.loading = false; 
    $scope.items.loaded = true; 
    $scope.count = data.count; 
    }) 
    .error(function(data, status, headers, config){  
    $scope.items = []; 
    $scope.items.loaded = true; 
    }); 
+0

Dies ist genau die Antwort, nach der ich gesucht habe. Ich melde mich zurück, wenn ich meinen Web-Service aktualisiert habe – Paidenwaffle

0

um Ihre Fragen zu unreif Suchergebnisse zu lösen, verwenden debounce wie folgt aus:.

ng-model-options="{ debounce: 1000 }" 

Es verzögert die Abfrage 1000 ms, in diesem Beispiel sendet also Sie werden die Ergebnisse für „Video“ erhalten und nicht "vide"

Verwandte Themen