Jump to content

Sort with select dropdown


remove
 Share

Recommended Posts

I need some help, and trying to understand, how to create a select dropdown for sorting items. The goal is something like sorting on PW modules pages (included image).

Page structure:

Muzikanten

-Bassisten

--Bassist A

--Bassist B

--Bassist C

-Fluitisten

--Fluitist A

--Fluitist B

--Fluitist C

-Trombonisten

--Trombonist A

--Trombonist B

--Trombonist C

Results I have created.

All

<?php
	$items = $page->child->title;
	foreach($page->children as $item) {
	$items = $item->title;
			echo"<ul>";
			foreach($item->children as $childchild) {
			echo "<li><a href='{$childchild->url}'>{$childchild->title}</a></li>";
			}
			echo "</ul>";
		}
?>

Show only a subgroup

<?php
	$items = $pages->get("/muzikanten/bassisten/")->children;
	foreach ($items as $item) {
		echo "</ul>";
		echo "<li><a href='{$item->url}'>{$item->title}</a></li>";
		echo "</ul>";
	}
?>

Eventually I would like a dropdown. How can I approach this the best way? The thing I do not understand is how a page can refresh and show selected results? Or is every result a different page? Do I need to make a tree with result pages to which the dropdown can refer too?

post-2698-0-96947800-1418140863_thumb.pn

Link to comment
Share on other sites

Do I need to make a tree with result pages to which the dropdown can refer too?

No, although you could use the parent pages you already have: Bassisten, Fluitisten, and Trombonisten.

In your example, the groups only go up to C. If you’re only dealing with a few items, it might be fine to do all filtering with Javascript. You could add an id attribute with the group’s name to your <ul> element, and simply hide all the others if the user selects a filter. Sorting could be implemented this way as well.

However, that’s not a ProcessWire solution. To do the filtering server-side with PW, you will want to accept GET parameters in your page template. GET parameters are those values that sometimes appear at the end of URLs. On your page, it could look something like this:

http://www.deliciousthoothpaste.nl/muzikanten/?filter=bassisten
or
http://www.deliciousthoothpaste.nl/muzikanten/?sort=descending
or even
http://www.deliciousthoothpaste.nl/muzikanten/?filter=bassisten&sort=descending

Now the page /muzikanten/ has these variables built in and you can use them in your template. They are in the $input->get API variable.

$sort = 'title';
if ($input->get->sort === 'descending')
    $sort = '-title'; //Put a - in front to sort Z-A

$muzikanten = $item->children("sort=$sort, sort=id"); //always sort by id to break ties consistently
foreach($muzikanten as $muzikant) {
    ...
}

Now you just need to get the user to visit your page with the GET parameter in the URL. As soon as he selects a sorting option, you send him to it using Javascript:

window.location = '/?sort=' + selection;

As you can see, Javascript is sort of required if you want the changes to apply (i. e. to reload the page) immediately. You can however avoid this by setting up a form with a submit button. The downside is, of course, that the user has to press the button in addition to selecting a value from your dropdown.

<form method="GET"> <!-- If you leave out the action attribute, it will just reload the page, but with the added parameters -->
    <select name="sort"> <!-- this is the parameter name that will be in $input->get -->
        <option value="ascending">A-Z</option>
        <option value="descending">Z-A</option>
    </select>
    <input type="submit" value="Apply Filters" /> <!-- gotta click here to do stuff -->
</form>

(Not too firm on the HTML syntax here, best read up on it yourself)

  • Like 1
Link to comment
Share on other sites

Are you sure you are talking about the same thing? :rolleyes:

@toothpaste
Do you mean this?
http://jqueryui.com/sortable/

or that?

<form action="{$page->url}" method="post">
<select name="muzikanten" onchange="this.form.submit()">
<option value="A">Muzikant A</option>
<option value="B">Muzikant B</option>
<option value="C">Muzikant C</option>
</select>
</form>

or both?


@JanRomero
urlSegments are nicer than raw GET parameters.
 

Link to comment
Share on other sites

@kize: My goal is a dropdown with sort options: all, ascending, descending, all fluitisten, all bassisten, all trombonisten. 

@jan romero: Thank you for your thorough explanation. I still can't put the two things together.

This code gives an Internal Server Error. I assume that the sort part works as a container. Do all links must be visible in the foreach(muzikanten as muzikant) so they can be sorted?  

<?php
	$sort = 'title';
	if ($input->get->sort === 'descending')
	$sort = '-title'; //Put a - in front to sort Z-A
					
	$muzikanten = $item->children("sort=$sort, sort=id"); //always sort by id to break ties consistently
	foreach($muzikanten as $muzikant) {
					   					   
		$items = $page->child->title;
		foreach($page->children as $item) {
		$items = $item->title;
		echo"<ul>";
		foreach($item->children as $childchild) {
		echo "<li><a href='{$childchild->url}'>{$childchild->title}</a></li>";
			}
		echo "</ul>";
		}
						
	}
?>

...still so much to learn....

Link to comment
Share on other sites

Your code looks very mixed up.

We’ll assume that we’re working on the parent page of Bassisten, Fluitisten, and Trombonisten. Thus, those three pages are in $page->children. We’ll refer to them as $categories. Each category has a number of artists as its children (grandchildren of $page).

Each category should have one <ul> element containing the artists. We’ll call an artist page $muzikant and create an <li> element.

First of all, let’s get the categories. Create a $categories variable and fill it with the children of $page.

$categories = $page->children();

Now loop over these categories and create a <ul> for each one.

foreach($categories as $category) {
    echo "<h3>$category->title</h3>";
    echo '<ul>';
    echo '</ul>';
}

Inside the foreach we now have the variable $category, which refers to a single category. Let’s get its children and call them $muzikanten. Then loop over $muzikanten the same way and echo <li>s. Our complete code now looks like this:

$categories = $page->children();
foreach($categories as $category) {
    echo "<h3>$category->title</h3>";
    echo '<ul>';
        $muzikanten = $category->children();
        foreach($muzikanten as $muzikant) {
            echo "<li>$muzikant->title</li>";
        }
    echo '</ul>';
}

This should just give us all the categories and all the artists in whatever order they come in.

To get only one specific category, we need a selector. If you’re unfamiliar with selector strings, take a quick look at the docs. We’re going to use the "sort=" selector to order our $muzikanten, and the "name=" selector to filter the $categories.

For example, to get only Bassisten, the selector would be "name=bassisten" (provided that’s the actual name of the page).

Let’s put that between the parentheses of $page->children():

$categories = $page->children("name=bassisten");

Now the page shows only Bassisten, but there’s still no order (probably). To sort, we have to know by which field to sort. We’ll use the title field. The selector for that is "sort=title". To sort Z-A instead of A-Z, it would be "sort=-title", with a minus/hyphen symbol.

So we have:

$categories = $page->children("name=bassisten");
foreach($categories as $category) {
    echo "<h3>$category->title</h3>";
    echo '<ul>';
        $muzikanten = $category->children("sort=title");
        foreach($muzikanten as $muzikant) {
            echo "<li>$muzikant->title</li>";
        }
    echo '</ul>';
}

The next step would be to use $input->get to determine what goes into our selectors. Let’s assume our address should look like this at the end:

?selectedcategory=bassisten&sortby=-title

(You will want to do this differently in reality, but let’s roll with it for now)

As soon as you add that part to the address in your browser, $input->get will have two new properties: selectedcategory and sortby. Store them in some variables.

$selectedCategory = $input->get->selectedcategory;
$sortby = $input->get->sortby;

Now we can use these variables inside our selector strings. Our finished code:

$selectedCategory = $input->get->selectedcategory;
$sortby = $input->get->sortby;

$categories = $page->children("name=$selectedCategory");
foreach($categories as $category) {
    echo "<h3>$category->title</h3>";
    echo '<ul>';
        $muzikanten = $category->children("sort=$sortby");
        foreach($muzikanten as $muzikant) {
            echo "<li>$muzikant->title</li>";
        }
    echo '</ul>';
}
Link to comment
Share on other sites

@toothpaste -

are you looking for something like any of these examples? I could post code for these if that helps:

using processwire, search function - page reloads on select (this is great since you can bookmark results)

http://www.ohmspeaker.com/speaker-finder/

using jQueryDataTables - no page reload, but also fast filterable results with many dropdowns:

http://katonahartcenter.com/pages/daily-schedule/

  • Like 2
Link to comment
Share on other sites

@macrura: Looks very nice, but first want to solve this one.

@jan romero: Again, thank you for your detailed answer. Very helpful. Now I understand the relation between input and the effect on the URL. Changing the URL gives a different result. This works pretty neat.

I created a pulldown to select different categories.  

<select name="form" onchange="location = this.options[this.selectedIndex].value;">
	<option value="">Sort</option>
	<option value="/testpagina/muzikanten/?selectedcategory=bassisten&sortby=title">Bassisten</option>
	<option value="/testpagina/muzikanten/?selectedcategory=fluitisten&sortby=title">Fluitisten</option>
	<option value="/testpagina/muzikanten/?selectedcategory=trombonisten&sortby=title">Trombonisten</option>
</select>

Is it possible with this setup to show all categories? I mean the result that you get without a string. 

$categories = $page->children();

$muzikanten = $category->children(); 
Link to comment
Share on other sites

Sure, just link to the page without the GET parameters, check if they’re in $input->get or not, and build (or omit) your selector strings accordingly. I’m sure you can figure it out :)

By the way, you should read up on sanitizers and use them with $input, because you’re essentially letting anyone modify the variables in your PHP script now.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...