user10753862
user10753862

Reputation:

Is it possible to filter already fetched data with jQuery

I am using the Laravel framework and fetching data. Now I am trying to filter the data with Ajax and jQuery. But a couple problem that I am facing...

UPDATED 4

When I start filter, there is this error looping:

"/var/www/html/laravel/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php", "line": 255, "trace": [ { "file": "/var/www/html/laravel/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php", "line": 242, "function": "methodNotAllowed", "class": "Illuminate\Routing\RouteCollection", "type": "->" },

is there that I am missing something about the controller? or routing? Thank you for help!

Laravel Controller:

public function search(Request $request)
{
  $q = $request->q;
  $sortbyprice = $request->sortbyprice;
  $region = $request->region;
  $rooms = $request->rooms;
  $price = $request->price;
  $max = $request->input('max');
  $min = $request->input('min');

  $paginationData = [
      'q' => $q
  ];

  $estates = \DB::table('allestates')
      ->where('lat', '!=', '')
      ->where('lng', '!=', '')
      ->where('price', '!=', '')
      ->when($q, function($query, $q) use ($paginationData) {
          $paginationData['q'] = $q;
          return $query->where(function($query) use ($q) {
                      $query->where("building_name", "LIKE", "%" . $q . "%")
                          ->orWhere("address", "LIKE", "%" . $q . "%")
                          ->orWhere("company_name", "LIKE", "%" . $q . "%")
                          ->orWhere("region", "LIKE", "%" . $q . "%")
                          ->orWhere("rooms", "LIKE", "%" . $q . "%");
                  });
      })
      ->when($sortbyprice, function($query, $order) use ($paginationData) {
          if(!in_array($order, ['asc','desc'])) {
              $order = 'asc';
          }
          $paginationData['sortbyprice'] = $order;
          return $query->orderBy('price', $order);

      }, function($query) {
          return $query->orderBy('price');
      })
      ->when($region, function($query, $regionId) use ($paginationData) {
          $paginationData['region'] = $regionId;
          return $query->where('region', $regionId);
      })
      ->when($rooms, function($query, $roomsId) use ($paginationData) {
          $paginationData['rooms'] = $roomsId;
          return $query->where('rooms', "LIKE", "%" . $roomsId . "%");
      })
      ->when($max, function($query, $max) use ($min, $paginationData) {
          $paginationData['min'] = $min;
          $paginationData['max'] = $max;
          return $query->whereBetween('price', [$min, $max]);
      })
      // ->toSql()
      ->paginate(100);

  $paginationData = array_filter($paginationData);

  return view("home", compact('estates', 'q','paginationData'));
}

var displayList = $('#display-wrapper ol');
var selectedOptions = {
    sortbyprice: '',
    rooms: '',
    region: ''
};


$('html').click(function () {
    console.log(selectedOptions);
});

$('a.region').on('click', function () {

    var selectValue = $(this).data('value');

    $('#region').text(selectValue);
    selectedOptions.region = selectValue;
    fetchDataFromServer(selectedOptions);
});

$('a.rooms').on('click', function () {
    var selectValue = $(this).data('value');

    $('#rooms').text(selectValue);
    selectedOptions.rooms = selectValue;
    fetchDataFromServer(selectedOptions);
});

$('a.sortbyprice').on('click', function () {
    var selectValue = $(this).text();

    selectedOptions.sortbyprice = selectValue;
    fetchDataFromServer(selectedOptions);
});

function serialize(options) {
    var arr = [];

    for (var key in options) {
        arr.push(key + '=' + options[key]);
    }

    return encodeURI(arr.join('&'));
}

function fetchDataFromServer(options) {
    $.ajax({
        type: 'POST',
        url: '/home',
        data: serialize(options),
        success: function (response) {
            if (response.error) {
                console.error(response.error);
            } else {
                console.log(response);
               
                updateDisplay(displayList);
            }
        },
        error: function (html, status) {
            console.log(html.responseText);
            console.log(status);
        }
    });
}

function updateDisplay(node, data) {
    var template = data.reduce(function (acc, item) {
        return acc + '<li><p>Region: ' + item.region + '</p><p>Price: ' + item.price + '</p><p>Rooms: ' + item.rooms + '</p></li>';
    }, '');

    node.empty();
    node.append(template);
}
#filter-wrapper {
    margin-top: 15px
}

#filter-wrapper ul {
    list-style: none;
    position: relative;
    float: left;
    margin: 0;
    padding: 0
}

#filter-wrapper ul a {
    display: block;
    color: #333;
    text-decoration: none;
    font-weight: 700;
    font-size: 12px;
    line-height: 32px;
    padding: 0 15px;
    font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif
}

#filter-wrapper ul li {
    position: relative;
    float: left;
    margin: 0;
    padding: 0
}

#filter-wrapper ul li.current-menu-item {
    background: lightblue;
}

#filter-wrapper ul li:hover {
    background: #f6f6f6
}

#filter-wrapper ul ul {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    background: #fff;
    padding: 0
}

#filter-wrapper ul ul li {
    float: none;
    width: 200px
}

#filter-wrapper ul ul a {
    line-height: 120%;
    padding: 10px 15px
}

#filter-wrapper ul ul ul {
    top: 0;
    left: 100%
}

#filter-wrapper ul li:hover>ul {
    display: block
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="filter-wrapper">
              <ul>
                  <li><a class="sortbyprice" href="javascript:" data-value="sortbyprice">Cheapest</a></li>
                  <li class="dropdown">
                      <a href="#" id="rooms">間取り</a>
                      <ul class="init" name="rooms">
                          <li><a class="rooms" href="javascript:" data-value="1DK">1DK</a></li>
                          <li><a class="rooms" href="javascript:" data-value="2LDK">2LDK</a></li>
                          <li><a class="rooms" href="javascript:" data-value="3LDK">3LDK</a></li>
                      </ul>
                  </li>

                  <li class="dropdown">
                      <a href="#" id="region">エリア</a>
                      <ul class="init" name="region">
                          <li><a class="region" href="javascript:" data-value="関西">関西</a></li>
                          <li><a class="region" href="javascript:" data-value="関東">関東</a></li>
                          <li><a class="region" href="javascript:" data-value="北海道">北海道</a></li>
                      </ul>
                  </li>
              </ul>
          </div>

          <div id="display-wrapper">
              <ol></ol>
          </div>

Upvotes: 6

Views: 1246

Answers (2)

Ray Chan
Ray Chan

Reputation: 1180

The main idea is to create a variable to store all the options selected by the user, and on each ajax request, you send the corresponding data to the server in order to get the filtered result.

I removed the hidden HTML form, and choose to use an object instead.

The ajax request in this code snippet is not working because there is no end-point '/home' for me to get the resources, but I think this will work on your machine.

As a side note, the id attribute should be unique, or else, the behavior might not be what you'd expected. And for the onclick handlers, if you have a lot of dropdowns, you should consider generating them with a loop instead of copy and pasting like I did, but for demo purposes, I will leave it as it is for now.

// a sample display
var displayList = $('#display-wrapper ol');
// create an object to store the selected options
var selectedOptions = {
    sortbyprice: '',
    rooms: '',
    region: ''
};

// this event handler is for logging out the selectedOptions
// so that you can see what happens to the variable
// you should remove this in production
$('html').click(function () {
    console.log(selectedOptions);
});

$('a.region').on('click', function () {
    // I guess what you're trying to do here is to update the dropdown
    // text into the selected value, e.g replace エリア with 関西
    var selectValue = $(this).data('value');

    $('#region').text(selectValue);
    selectedOptions.region = selectValue;
    fetchDataFromServer(selectedOptions);
});

$('a.rooms').on('click', function () {
    var selectValue = $(this).data('value');

    $('#rooms').text(selectValue);
    selectedOptions.rooms = selectValue;
    fetchDataFromServer(selectedOptions);
});

$('a.sortbyprice').on('click', function () {
    // var selectValue = $(this).text();
    // selectedOptions.sortbyprice = selectValue;
    selectedOptions.sortbyprice = 'asc';
    fetchDataFromServer(selectedOptions);
});

function fetchDataFromServer(options) {
    $.ajax({
        type: 'GET',
        url: '/home',
        data: options,
        success: function (response) {
            if (response.error) {
                // sweetAlert("Oops...", response.data, "error");
                console.error(response.error);
            } else {
                console.log(response);
                // I assume the data structure of the response is something like
                // var reponse = {
                //     data: [
                //         {
                //             price: 123,
                //             rooms: '1DK',
                //             region: '関西'
                //         },
                //         ......
                //     ]
                // }
                // This is an example function for updating the UI
                // You can replace this function according to your needs
                updateDisplay(displayList, response.data);
            }
        },
        error: function (html, status) {
            console.log(html.responseText);
            console.log(status);
        }
    });
}

function updateDisplay(node, data) {
    // build the html for the node(<ol> tag)
    var template = data.reduce(function (acc, item) {
        return acc + '<li><p>Region: ' + item.region + '</p><p>Price: ' + item.price + '</p><p>Rooms: ' + item.rooms + '</p></li>';
    }, '');

    // add the template to the node(<ol> tag)
    node.empty();
    node.append(template);
}
#filter-wrapper {
    margin-top: 15px
}

/*
 *  I added this line for demo purpose
 *  Not sure whether you'll need this in your app
 *  Feel free to remove this
 */
#filter-wrapper::after {
    content: '';
    clear: both;
    display: block;
}

#filter-wrapper ul {
    list-style: none;
    position: relative;
    float: left;
    margin: 0;
    padding: 0
}

#filter-wrapper ul a {
    display: block;
    color: #333;
    text-decoration: none;
    font-weight: 700;
    font-size: 12px;
    line-height: 32px;
    padding: 0 15px;
    font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif
}

#filter-wrapper ul li {
    position: relative;
    float: left;
    margin: 0;
    padding: 0
}

#filter-wrapper ul li.current-menu-item {
    background: lightblue;
}

#filter-wrapper ul li:hover {
    background: #f6f6f6
}

#filter-wrapper ul ul {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    background: #fff;
    padding: 0
}

#filter-wrapper ul ul li {
    float: none;
    width: 200px
}

#filter-wrapper ul ul a {
    line-height: 120%;
    padding: 10px 15px
}

#filter-wrapper ul ul ul {
    top: 0;
    left: 100%
}

#filter-wrapper ul li:hover>ul {
    display: block
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="filter-wrapper">
    <ul>
        <li><a class="sortbyprice" href="javascript:" data-value="sortbyprice">Cheapest</a></li>
        <li class="dropdown">
            <a href="#" id="rooms">間取り</a>
            <ul class="init" name="rooms">
                <li><a class="rooms" href="javascript:" data-value="1DK">1DK</a></li>
                <li><a class="rooms" href="javascript:" data-value="2LDK">2LDK</a></li>
                <li><a class="rooms" href="javascript:" data-value="3LDK">3LDK</a></li>
            </ul>
        </li>

        <li class="dropdown">
            <a href="#" id="region">エリア</a>
            <ul class="init" name="region">
                <li><a class="region" href="javascript:" data-value="関西">関西</a></li>
                <li><a class="region" href="javascript:" data-value="関東">関東</a></li>
                <li><a class="region" href="javascript:" data-value="北海道">北海道</a></li>
            </ul>
        </li>
    </ul>
</div>

<div id="display-wrapper">
    <ol></ol>
</div>

Upvotes: 1

JasonB
JasonB

Reputation: 6368

Yes you can. This is often done on the server, but if your data set is small enough it can work. If you set the filterable data points as data elements of your items you can just compare the selected value from the filter. jQuery's each function is one way to loop through the elements and you can then use the data function to access the appropriate data attribute.

$('#room-filter').on('change', function() {
  const numRooms = $(this).val();
  $('.card').each(function() {
    if (numRooms && numRooms != $(this).data('rooms')) {
      $(this).slideUp();
    } else {
      $(this).slideDown();
    }
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Rooms:
<select id="room-filter">
  <option value="">Show All</option>
  <option value="1">1 Room</option>
  <option value="2">2 Rooms</option>
  <option value="3">3 Rooms</option>
</select>

<div class="card text-left" data-rooms="1">
  <div class="card-body d-flex" id="content-card">
    <h2>Shack</h2>
    <p class="main-text">1 room</p>
  </div>
</div>

<div class="card text-left" data-rooms="1">
  <div class="card-body d-flex" id="content-card">
    <h2>Second Shack</h2>
    <p class="main-text">1 room</p>
  </div>
</div>

<div class="card text-left" data-rooms="3">
  <div class="card-body d-flex" id="content-card">
    <h2>Bungalo</h2>
    <p class="main-text">3 rooms</p>
  </div>
</div>

Upvotes: 2

Related Questions