2013-04-10 17 views
7

Sto cercando di ottenere i bootstrap UI angolari typeahead che funzionano con una risorsa REST che ho impostato. Ma non sono sicuro di come farlo funzionare con la sua natura asincrona.

Al momento ho adattato l'esempio fornito da Angular UI Bootstrap.

quindi il mio html sembra così, chiamando getLibs() per ottenere l'elenco per il menu a discesa typeahead.

<div class='container-fluid' ng-controller="TypeaheadCtrl"> 
    <pre>Model: {{selected| json}}</pre> 
    <input type="text" typeahead="lib.name for lib in getLibs($viewValue)" active='active' ng-model="selected" typeahead-min-length='3' > 
</div> 

la mia risorsa si presenta in questo modo:

angular.module('LibraryLookupService', ['ngResource']).factory('Library', 
    function($resource){ 
     return $resource( "../../api/seq/library/?name__icontains=:searchStr" , {} , 
     { 'get': {method:'GET'}, 
      'query': {method:'GET', params: {} , isArray:false }, 
     } 
    ) 
} 

);

mio controller sembra così (sto indovinando è qui che sto facendo qualcosa di sbagliato):

function TypeaheadCtrl($scope , Library){ 

    $scope.selected = undefined; 
    $scope.active = undefined ; 

    $scope.libs = [{name:'initial'} , {name:"values"}]; 

    $scope.getLibs = function(viewValue){ 
     console.log("value:", viewValue); 
     if (viewValue.length > 3) { 
      var return_vals = Library.query({searchStr:viewValue}, function() { 
       $scope.libs = return_vals.objects ; 
       console.log("here", $scope.libs) ; 
       }) ; 
      } 
     return $scope.libs 
    } 
} 

Quindi se ho capito bene, il menu typeahead viene popolato dal valore di ritorno delle getLibs () funzione. Quando viene chiamato getLibs() sta interrogando l'interfaccia REST, ma inizialmente viene restituito un valore vuoto. Questo viene popolato dalla funzione fornita al metodo Library.query() e ciò viene eseguito dopo che i dati sono stati restituiti dalla richiesta REST.

Ciò significa in sostanza che il menu viene aggiornato con una pressione di un tasto più tardi rispetto a quella che desidero. Scrivo "3456" e viene popolato con i risultati di una query "345" nell'interfaccia REST.

Come si ottiene il menu da aggiornare quando la risposta viene restituita dalla funzione Library.query()? Sto andando su questo correttamente?

risposta

6

La direttiva typeahead da http://angular-ui.github.io/bootstrap/ relè sull'API di promessa ($q) per gestire suggerimenti asincroni. Il problema con $resource è che viene utilizzato per mancanza di supporto per le promesse (è stato aggiunto solo di recente nel ramo instabile). Quindi hai 2 soluzioni qui:

1) relè su $http che funziona con le promesse (IMO $ http dovrebbe essere più che sufficiente per la maggior parte dei casi di completamento automatico). 2) Passare all'ultima versione instabile di AngularJS e lavorare con le promesse.

Lo scopo della risorsa $ è lavorare con il set completo di verbi HTTP per indirizzare gli endpoint RESTful. Se si desidera semplicemente eseguire query sui dati, è preferibile utilizzare $ http per questo scopo.

C'è una domanda simile su typeahead con una risposta che copre del suo utilizzo con $http: How to tie angular-ui's typeahead with a server via $http for server side optimization?

2

Se non si desidera utilizzare $ http (perché si vuole riutilizzare il $ risorse esistente), o non voglio passare al ramo instabile, puoi avvolgere la chiamata alla tua risorsa $ in una promessa. È un po 'prolisso, ma funziona. esempio rapido (usando AngularJS 1.0.6):

$scope.getLibs = function(input){ 
    var defer = $q.defer(); 
    if (input){ 
     Library.query({searchStr:viewValue}, 
      function(data,headers){ 
       if (!$scope.$$phase){ //check if digest is not in progress 
        $rootScope.$apply(function(){ 
         defer.resolve(data); 
        }); 
       } else { 
        defer.resolve(data); 
       } 
      }, 
      function(response){ 
       if (!$scope.$$phase){ 
        $rootScope.$apply(function(){ 
         defer.reject('Server rejected with status ' + response.status); 
        }); 
       } else { 
        defer.reject('Server rejected with status ' + response.status); 
       } 
      }); 
    } else { 
     if (!$scope.$$phase){ 
      $rootScope.$apply(function(){ 
       defer.reject('No search query '); 
       $log.info('No search query provided'); 
      }); 
     } else { 
      defer.reject('No search query '); 
      $log.info('No search query provided'); 
     } 
    } 
    return defer.promise; 
}; 
7

ho risolto in questo modo:

mia fabbrica:

angular.module('frontendApp') 
    .factory('PersonService', function($resource) { 
    // Service logic 
    // ... 

    return $resource(APP_CONFIG.prefixURLRest + '/person', { 
     //id: '@id' 
    }, { 
     search: { 
     method: 'POST', 
     isArray: true 
     } 
    }); 

    }); 

mio regolatore

... 
$scope.searchTypeAhead = function(name) { 
    var person = { 
    'name': name 
    }; 

    return PersonService.search(person) 
    .$promise.then(function(response) { 
     return response; 
    }); 
}; 
+7

In realtà si potrebbe semplicemente restituire il $ promise senza il metodo then() in quanto è ridondante. – mameluc

+0

Non capisco perché si passi l'oggetto persona quando si chiama PersonService poiché non vedo un oggetto Persona nella definizione di fabbrica. – peztherez

1

Basta tornare $ promessa risorsa:

UsuarioResource.query().$promise 
0

Questo codice è lavorando per angolare 1.6 e l'ultima di ui angolare bootstrap3-typeahead

risposta api endpoint per GET/città name = "nomeacaso":?

[ 
    {name: "somename", zipcode: 11111, etc: ""}, 
    {name: "somename", zipcode: 22222, etc: ""}, 
    {name: "somename", zipcode: 33333, etc: ""} 
] 

$ risorsa fabbrica:

getCities: { 
    url: '/cities', 
    method: 'GET 
} 

regolatore :

$scope.getCities = function(name) { 
    return City.getCity({ 
     name: name 
    }).$promise.then(function(response) { 
     return response; 
    }); 
}; 

vista:

<input ng-model-control data-ng-model="city" uib-typeahead="city.name for city in getCities($viewValue)" /> 

Sembra che questa soluzione non funziona con il filtraggio, vedi https://github.com/angular-ui/bootstrap/issues/1740.

Problemi correlati