2017-08-23 2 views
1

Je construis une application qui prend une liste de restaurants et les affiche sur une carte Google. J'affiche également cette liste afin que l'utilisateur puisse voir les noms des restaurants.Comment afficher les résultats d'une liste filtrée à l'aide de Knockout.Js?

Je veux filtrer la liste en utilisant Knockout.js de sorte que lorsque quelqu'un commence à taper le nom du restaurant, seuls ceux qui correspondent à la requête apparaissent.

HTML + knock-out Manchettes

<div> 
    <div id="search"> 
    <input type="text" placeholder="Filter" data-bind="textInput:query"> 
    </div> 
    <ul data-bind="foreach: restaurants"> 
    <li data-bind="text: name"></li> 
    </ul> 
</div> 
<div id="map"></div> 

JavaScript

var restaurants = [ 
    {name: 'Chez Simone', location: {lat:48.8603937, lng: 2.3430545}}, 
    {name: 'Cafe Coutume', location: {lat:48.851599, lng: 2.3162123}}, 
    {name: 'Café Pinson', location: {lat:48.863732, lng: 2.3631037}}, 
    {name: 'Sol Semilla', location: {lat:48.8730959, lng: 2.363135900000001}}, 
    {name: 'Juice Lab Marais', location: {lat:48.8563595, lng: 2.3637123}} 
]; 

//viewModel 
var viewModel = function(){ 
    var self = this; 
    self.restaurantList = ko.observableArray(restaurants); 

    //Stores user input 
    self.query = ko.observable(''); 

    // Filters through observableArray and filters results using util.arrayFilter(); 
    self.search = ko.computed(function(){ 
    var query = this.query().toLowerCase(); 
    if(!query) { 
     return self.restaurantList(); 
    } else { 
     //go through restaurant list and for each restaurant, check if the letters in query 
     // appear in restaurant name. If so, display name. else don't. 
     var restaurantList = self.restaurantList(); 
     for(i = 0; i < restaurantList.length; i++){ 
     var restaurant = restaurantList[i]; 
     var restaurantName = restaurant.name; 
     // check if query letter/s appears in restaurant name 
     if(restaurantName.toLowerCase().indexOf(query) > -1){ 
     // Help! This is where I'm stuck. 
     return restaurantName; 
     } 
     } 
    } 
    }, self); 
}; // viewModel ends ` 

La logique que j'ai tellement fonctionne bien - si je l'utilise console.log(restaurantName) il imprime seulement le bon Restaurants. Je ne peux pas le faire apparaître dans la vue.

Comment l'afficher dans la liste?

+0

cela ressemble assez à https://stackoverflow.com/questions/45422066/set-marker-visible-with-knockout-js-ko-utils-arrayfilter J'ai mis à jour le violon pour utiliser vos emplacements. https://jsfiddle.net/dy70fe16/3/ –

+0

Copie possible de [Définir le marqueur visible avec knockout JS ko.utils.arrayFilter] (https://stackoverflow.com/questions/45422066/set-marker-visible-with- knockout-js-ko-utils-arrayfilter) –

Répondre

2

Votre computed propriété search doit toujours retourner un array afin que vous puissiez lier le foreach à la collection filtrée.

Vous avez déjà eu la première partie:

if (!query) return self.restaurantList(); 

En d'autres termes, si vous ne recherchez pas, montrer tous les restaurants.

Vous avez également réussi à faire fonctionner la majeure partie de la dernière partie, excepté la partie où vous bouclez et retournez.

Vous devrez utiliser restaurantList.filter (ou, comme vous le mentionnez dans votre commentaire, util.arrayFilter) pour créer un tableau d'éléments correspondant à votre requête.

return self.restaurantList().filter(function(restaurant) { 
    return (restaurant.name.toLowerCase().indexOf(query) > -1) 
}); 

Puis, avec foreach: search, vous obtiendrez l'extrait ci-dessous:

var restaurants = [ 
 
    {name: 'Chez Simone', location: {lat:48.8603937, lng: 2.3430545}}, 
 
    {name: 'Cafe Coutume', location: {lat:48.851599, lng: 2.3162123}}, 
 
    {name: 'Café Pinson', location: {lat:48.863732, lng: 2.3631037}}, 
 
    {name: 'Sol Semilla', location: {lat:48.8730959, lng: 2.363135900000001}}, 
 
    {name: 'Juice Lab Marais', location: {lat:48.8563595, lng: 2.3637123}} 
 
]; 
 

 
//viewModel 
 
var viewModel = function(){ 
 
    var self = this; 
 
    self.restaurantList = ko.observableArray(restaurants); 
 

 
    //Stores user input 
 
    self.query = ko.observable(''); 
 

 
    self.search = ko.computed(function(){ 
 
    var query = this.query().toLowerCase(); 
 
    if(!query) { 
 
     return self.restaurantList(); 
 
    } else { 
 
     var restaurantList = self.restaurantList(); 
 
     return restaurantList.filter(function(restaurant) { 
 
     var restaurantName = restaurant.name; 
 
     return (restaurantName.toLowerCase().indexOf(query) > -1) 
 
     }); 
 
    } 
 
    }, self); 
 
}; 
 

 
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> 
 

 
<div> 
 
    <div id="search"> 
 
    <input type="text" placeholder="Filter" data-bind="textInput:query"> 
 
    </div> 
 
    <ul data-bind="foreach: search"> 
 
    <li data-bind="text: name"></li> 
 
    </ul> 
 
</div> 
 
<div id="map"></div>

Notez que la mise à jour des marqueurs dans les cartes google interface utilisateur, vous devrez abonnez-vous à search et mettez à jour votre carte en conséquence.

+0

Merci pour l'aide. Je l'ai essayé, mais rien ne change quand je tape quelque chose dans l'entrée. En d'autres termes, la liste ne filtre pas, elle reste la même. Des idées de pourquoi cela pourrait-il être? –

+0

Dus vous changez la liaison pour se référer à la liste calculée plutôt que la source originale? – user3297291

+0

C'était tout. J'avais oublié de changer le foreach pour chercher. –