Search code examples
buttonsearchjavafxreusabilityobservablelist

Reusable search function javafx


I have a program that searches an observable list and displays all of the matching cases on the table. The search works fine, but I am only able to run this part of the program once. The search button stops responding after the program has returned to displaying the full observable list.

I have a separate class(Search.class) that handles all of the logic for searching the observable list.

The code for the search button and text field are below:

partSearchBtn.setOnAction(searchPartEvent ->{
    ObservableList<Part> searchPartDisplay = FXCollections.observableArrayList();

    String searchQuery = partSearchField.getText();

    try{
        searchPartDisplay = Search.searchPartByNumber(Integer.parseInt(searchQuery));
        partTable.setItems(searchPartDisplay);

        partSearchBtn.setText("Clear");
        partSearchBtn.setOnAction(clearSearchEvent ->{
            partSearchBtn.setText("Search");
            partTable.setItems(Inventory.partBin);
        });

    } catch(NumberFormatException hasText){
        searchPartDisplay = Search.searchPartByText(searchQuery);
        partTable.setItems(searchPartDisplay);

        partSearchBtn.setText("Clear");
        partSearchBtn.setOnAction(clearSearchEvent ->{
            partSearchBtn.setText("Search");
            partTable.setItems(Inventory.partBin);
        });
    }
});

What changes would I need to make to re-run the search process? Or should I turn this into a method as part of my Search class that I can reuse?

The search logic is below:

package inventorymngmnt;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Search {

    public static ObservableList<Part> searchPartByNumber(int inNum){
        ObservableList<Part> searchBin = FXCollections.observableArrayList();
        for(Part e: Inventory.partBin){

            boolean typeCaseIn = (e.getClass() == Inhouse.class);            
            if(typeCaseIn == true){
                Inhouse testIn = (Inhouse) e;
                if(inNum == testIn.getMachineID())
                    searchBin.add(e);
            }
            if((inNum == e.getPartID()) || (inNum == e.getInstock()) || (inNum == e.getMax()) 
                    || (inNum == e.getMin()) || ((double)inNum == e.getPrice()) 
                    || (Integer.toString(inNum).contains(e.getName()))){
               searchBin.add(e);
            }
        }
        return searchBin;
    }

    public static ObservableList<Part> searchPartByText(String inString){
        ObservableList<Part> searchBin = FXCollections.observableArrayList();
        for(Part e: Inventory.partBin){
            boolean typeCaseOut = (e.getClass() == Outsourced.class);
            if(typeCaseOut == true){
                Outsourced testOut = (Outsourced) e;
                if(inString.equals(testOut.getCompanyName())){
                    searchBin.add(e);
                }
            }
            if(inString.equals(e.getName())){
                searchBin.add(e);
            }
        }        
        return searchBin;
    }

    public static ObservableList<Part> searchProdByNumber(int inNum){
        ObservableList<Part> searchProd = FXCollections.observableArrayList();
        for(Part e: Inventory.partBin){

            boolean typeCaseIn = (e.getClass() == Inhouse.class);            
            if(typeCaseIn == true){
                Inhouse testIn = (Inhouse) e;
                if(inNum == testIn.getMachineID())
                    searchProd.add(e);
            }
            if((inNum == e.getPartID()) || (inNum == e.getInstock()) || (inNum == e.getMax()) 
                    || (inNum == e.getMin()) || ((double)inNum == e.getPrice()) 
                    || (Integer.toString(inNum).equals(e.getName()))){
               searchProd.add(e);
            }
        }
        return searchProd;
    }

    public static ObservableList<Part> searchProdByText(String inString){
        ObservableList<Part> searchProd = FXCollections.observableArrayList();
        for(Part e: Inventory.partBin){
            boolean typeCaseOut = (e.getClass() == Outsourced.class);
            if(typeCaseOut == true){
                Outsourced testOut = (Outsourced) e;
                if(inString.equals(testOut.getCompanyName())){
                    searchProd.add(e);
                }
            }
            if(inString.equals(e.getName())){
                searchProd.add(e);
            }
        }        
        return searchProd;
    }
}

Solution

  • It doesn't work, because when you clear the search, the action on the button is still set to clear the search...

    Consider a different strategy entirely. You can use a FilteredList as the list for the table. Then just toggle the predicate on the list:

    Predicate<Part> noFilter = part -> true;
    FilteredList<Part> filteredParts = new FilteredList<>(Inventory.partBin, noFilter);
    partTable.setItems(filteredParts);
    
    partSearchBtn.setOnAction(searchPartEvent -> {
        if (filteredParts.getPredicate()==noFilter) {
            String searchQuery = partSearchField.getText();
            try {
                int searchNumber = Integer.parseInt(searchQuery);
                filteredParts.setPredicate(part -> Search.filterByNumber(part, searchNumber));
            } catch (NumberFormatException exc) {
                filteredParts.setPredicate(part -> Search.filterByText(part, searchQuery));
            }
        } else {
            filteredParts.setPredicate(noFilter);
        }
    });
    
    partSearchButton.textProperty().bind(Bindings
        .when(filteredParts.predicateProperty().isEqualTo(noFilter))
        .then("Search")
        .otherwise("Clear"));
    

    and

    public class Search {
    
        public static boolean filterByNumber(Part part, int number) {
            if (part.getClass() == Inhouse.class) {
                Inhouse testIn = (Inhouse) part ;
                if (testIn.getMachineID() == number) {
                    return true ;
                }
            }
            if((number == part.getPartID()) || (number == part.getInstock()) || (number == part.getMax()) 
                    || ( number == part.getMin()) || ((double) number == part.getPrice()) 
                    || (Integer.toString(number).contains(part.getName()))){
               return true ;
            }
            return false ;
        }
    
        public static boolean filterByText(Part part, String text) {
            //similarly...
        }
    }