Onyx
Onyx

Reputation: 5782

I'm having trouble creating some basic filtering using Laravel

My index page displays all images from my images table with the newest submissions on top. I'm trying to add some basic filtering so I can grasp the concept but I'm doing something wrong. My idea is:

Add 2 <a> elements with URLs to www.domain.com and www.domain.com/ascending. If the user goes to www.domain.com, the images will be displayed in descending order and if he goes to www.domain.com/ascending they will be displayed in ascending order.

Then I make my home route Route::get('/', 'PagesController@index')->name('home'); have an optional parameter like Route::get('/{filter?}', 'PagesController@index')->name('home');

Based on the optional parameter, I'll send different $images variable to the view:

public function index($filter){    
    switch($filter) {
        case 'ascending'    : $images = Image::orderBy('created_at', 'asc')->get();break;
        default             : $images = Image::orderBy('created_at', 'desc')->get();
    }

    return view('home', ['images' => $images]);
}

As soon as I did this, I got 2 problems so far:

Firstly, when I go to www.domain.com, I get "Type error: Too few arguments to function App\Http\Controllers\PagesController::index(), 0 passed and exactly 1 expected"

Secondly, after adding the optional parameter to the route Route::get('/{filter?}', 'PagesController@index')->name('home'); I get send to my index page even when I'm going to URLs like http://example.com/admin or http://example.com/albums.

I believe this happens because my code assumes that /admin and /albums are the optional parameter in my http://example.com url and not a separate url like it should be.

Route::get('/{filter?}', 'PagesController@index')->name('home');
Route::get('/image/{id}', 'PagesController@specificImage')->name('specificImage');
Route::get('/tags', 'PagesController@tags')->name('tags');

So even if I go to the tags route, the index view will be displayed instead of the tags view.

Upvotes: 0

Views: 282

Answers (3)

omitobi
omitobi

Reputation: 7334

First and foremost, using query parameter looks best for filtering in this situation instead of having two (or more) url endpoints.

However, if you want to stick with your implementation there are few things to do:

  1. Declare your routes without leading slash, e.g:

      Route::get('{filter?}', 'PagesController@index')->name('home') 
    

    Not so sure this does make any difference though, but something I personally watchout for (slashes everywhere)

  2. Use optional path variable with restricted values, by using where() after the route declaration:

    Route::get('{filter?}', 'PagesController@index')->name('home')->where('filter', 'ascending|');
    

    It accepts ascending or nothing.

  3. Pass a default parameter to your controller method:

    public function index($filter = null)
    {
        .....
    }
    

    Just in case nothing was passed. This is one of the important points to note with optional path variables.

Finally, you can avoid if statement totally, by using a Ternary operator before making the query:

public function index($filter = null){    
    $order = $filter === 'ascending' ? 'asc' : 'desc';

    $images = Image::orderBy('created_at', $order)->get();

    return view('home', ['images' => $images]);
}

Upvotes: 0

Ricardo Castillo
Ricardo Castillo

Reputation: 381

you can do this www.domain.com?orderby=asc

Route::get('/', 'PagesController@index')->name('home');

public function index(Request $request){

  $images = array();

  $images = Image::orderBy('created_at', $request->get('orderBy') ?? 'desc')->get();

  return view('home', ['images' => $images]);
}

Upvotes: 3

Xixis
Xixis

Reputation: 909

I suggest you use get params in this case to avoid conflicting urls. So that request to / should now be

/?order=asc or /?order=desc

and rather switch the get param order to know whether to show the page in descending or ascending order.

Upvotes: 1

Related Questions