Monday, March 2, 2009

jQuery optionTree demo

This is the demo for my jQuery optionTree plugin.

Update: Version 1.2 of the plugin is now capable of loading trees via AJAX - this is not possible to demonstrate on this blog, so I moved the demonstration to a separate site - see the new demo page.

This jquery plugin converts passed JSON option tree into dynamically created SELECT elements allowing you to choose one nested option from the tree.
It should be attached to a (most likely hidden) INPUT element. It requires an option tree object. Object property names become labels of created select elements, each non-leaf node in the tree contains other nodes. Leaf nodes contain one value - it will be inserted into attached INPUT element when chosen.


The plugin also supports loading additional levels via AJAX calls and preselecting given items at load.


Example 1




<input type="text" name="demo1" />

    var option_tree = {
       "Option 1": {"Suboption":200},
       "Option 2": {"Suboption 2": {"Subsub 1":201, "Subsub 2":202},
             "Suboption 3": {"Subsub 3":203, "Subsub 4":204, "Subsub 5":205}
            }
    };

    $('input[name=demo1]').optionTree(option_tree);

Example 2 - change event and configuration




<input type="hidden" name="demo2" />

    var option_tree = {
       "Option 1": {"Suboption":200},
       "Option 2": {"Suboption 2": {"Subsub 1":201, "Subsub 2":202},
             "Suboption 3": {"Subsub 3":203, "Subsub 4":204, "Subsub 5":205}
            }
    };

    var options = {empty_value: -1, choose: '...'};

    $('input[name=demo2]').optionTree(option_tree, options)
                          .change(function() { alert('Field ' + this.name  + ' = ' + this.value )});


Example 3 - preselected options




<input type="hidden" name="demo3" />

    var option_tree = {
       "Red": {"Default":100},
       "Blue": {"Variant 1": {"Default":100, "Another":101},
        "Variant 2": {"Default":100, "Another":102, "and another":103}
       }
    };

    var options = {preselect: {'demo3': 100}}; // value for default option (include field name)

    $('input[name=demo3]').optionTree(option_tree, options)
                          .change(function() { alert('Field ' + this.name  + ' = ' + this.value )});


More info

Plugin is dual licensed undel MIT / GPL licenses.
Additional information about this plugin is available on its google code pages. You may download the plugin from there or from its jQuery plugin site. It has been tested with jQuery 1.3 and 1.4. Feel free to comment on the plugin and suggest additional features on google code project site.

34 comments:

Anonymous said...

Does the preselect feature actually work? And if so, how exactly? (I'm not getting any pre-selection anywhere, not even in the demo)

Krzysztof Kotowicz said...

Yes, it does work, but it might be explained poorly - see the discussion under this issue

Bedouga said...

Thanks so much for this, I've been searching for something jsut like it for days.

One thing that I can't seem to figure out is how to turn the <\input type="text" name="demo1"> into <\input type="hidden" name="demo1" vlaue="###">. I just want the resulting value to be hidden. Any help?

Krzysztof Kotowicz said...

Bedouga: I'm not sure if I understand - the plugin will work with [input type="hidden"] instead of type=text given in the first example. That's how I use it on my sites. So the only thing you should do is to change the HTML, no changes in Javascript should be required.

Alan said...

Hi Krzysztof

Very nice piece of code. I have managed to get it to work in a Wordpress sidebar.

2 quick questions.

1) If I have say 3 fields, and I choose say "Big" in field 1, "Green" in field 2, and "Widgets in field 3 ... how do I get the resulting output to equal "Big Green Widgets" instead of just the value assigned to "Widgets" ?

2) How do I place the fields vertically instead of next to each other. I have tried using a BR tag before the SELECT in line 56, but this keeps inserting blank lines between the last field and the forms submit button if the fields are changed.

Best regards

Alan

Krzysztof Kotowicz said...

@Alan

As for the 1st question - use display: block for select elements

As for 2nd - use custom event handler

I've added the demo answering your exact use case in the repository - see example 4:

http://code.google.com/p/jquery-option-tree/source/browse/trunk/demo/demo.html?spec=svn4&r=4

Alan said...

Hi Krzysztof

That is working very well. I would NEVER have suspected that the solution was on the main page part. I would have been editing the .js file. Shows my lack of expertise in js unfortunately :-(

There is one thing, and I am sure its a simple fix.

When I have selected say "Big" in foeld 1, "Green" in foeld 2, and "Widget" in field 3 then the alert box now correctly displays "Big Green Widget".

But, the value that is inserted into the form field is the numerical value of "Widget" (the 3rd selection).

Is it possible to make the resulting form field be "Big Green Widget" instead ?

Many thanks

Alan

Krzysztof Kotowicz said...

>Is it possible to make the resulting form field be "Big Green Widget" instead ?

Of course - just assign the appropriate value to the field in the chage() event.

In the 4th example I've given:
replace alert(xxx) with $(this).val(xxx)

This should work - if not, debug - it's javascript, you can do it ;)

Alan said...

Hi Krzysztof

It works perfectly now. You can see it in the right hand side of my test site at http://www.uwantwefind.com .. its the widget called "Combo Search".

Many thanks for your very kind help. Much appreciated.

If you have any Wordpress affiliate blogs that run phpBay, or phpZon, or Wordbay (or any plugin that uses [sometag] type notation on a page or post) then drop me a note to ppcisme at gmail.com and i'll send you across a copy of this plugin when its done. Its very neat for generating new posts/pages (auto content) when users make selections.

Have a great day.

Alan

blues said...

Hi, this is working great so far, but I'm wondering if there's a way to change the choose text per select box. I'm aware of the choose option but that changes the value across all select boxes, what I'm looking for is something that let's me make a chain such as:

"Select Brand" => "Select Series" => "Select Colour"

Nguyen Tot said...

Hi
That good plugins but i see some detail, when select option that value of option and text of option is the same. Can modify value difference text of option ?

Notícias de Alagoas said...

Thanks for your nice job.

Just a tip: although you said that you tested with JQuery 1.2 and 1.3, when I use JQuery 1.2.1, the default item displayed on combobox will always be the last one, instead of "choose..." at the top. It almost drove me crazy, until I find out that using a newer JQuery (1.3.2) will solve this problem.

Cheers from Brazil!

MB34 said...

Is there any way to have the options dynamically generated like from a PHP script?

I'm building a UI to display the taxonomy for Google Base product types: http://www.google.com/basepages/producttype/taxonomy.txt

It has 3700+ items with 20 base categories and up to 7 levels.

Is this possible with this plugin?

Krzysztof Kotowicz said...

@MB34

Yes, it is possible, that is the most common use case (to serve the options from a server-side script).

The easiest way would be similar to this:
http://gist.github.com/592387

but you have to figure out yourself how to convert the taxonomy file to a nested array.

MB34 said...

Please place info in your blog and maybe modify your demo to show the capabilities of dynamically loading this control.

MB34 said...

Since this is such a huge number of items, I want to be able to get them "on-the_fly".

This means that when I select an item in the first one, I want the second one to be dynamically loaded.

The code at github doesn't show how to use the events to do that.
I have found that the change event takes place too soon to do this.

Can you show more usage of the even mechanisms of this control?

MB34 said...

Krzysztof,
I think I've got it but the one thing I can't get is that you must
select all the way down the chain before the .change happens.
Is there an event thrown for each selection?

For instance, based on the github code, here's the array I'm passing
in array.php:
$a = array(
'Live Animals' => '100',
'Pet Supplies' => array(
'Amphibian Supplies' => '101',
'Bird Supplies' => '102',
'Bug Supplies' => '103',
'Cat Supplies' => array('Cat Food' => '104'),
'Dog Supplies' => array('Dog Food' => '105'),
'Ferret Supplies' => '106',
'Fish Supplies' => array(
'Aquarium Supplies' => '107',
'Aquariums' => '108'),
'Horse Supplies' => '109',
'Rabbit Supplies' => '110',
'Reptile Supplies' => '111',
'Rodent Supplies' => '112'));

Now, if I want only Cat Supplies, I have to go all the way to Cat Food, then reselect '...' in order to get that chain displayed.

A demo page of how I'm using it is located here:
http://www.partreports.com/treetest.php

I'd also like to know how to preload the thing with a certain value, like 'Fish Supplies > Aquarium Supplies'

Krzysztof Kotowicz said...

@MB34

You might be interested in newest trunk version:

http://code.google.com/p/jquery-option-tree/source/browse/#svn/trunk

I've added the functionality, together with the demos, that might help you - the version number is now 1.1.

The demo in source files uses Google Base taxonomy & lazy loads each item.

Soon it will make a post about new functionality, but for now - checkout the trunk and try hacking with it.

MB34 said...

I have already figure a bunch of stuff out. The thing I'm currently stucj on is how to preload them with a value. I am going to be storing the value in a database and want to be able to preload them when the user returns to the page. Right now, I'm thinking of just having a label with their current selection.

I'm glad you liked my idea.

MB34 said...

Here is how to load the taxonomy file directly from Google:
$reader = new LazyTaxonomyReader('http://www.google.com/basepages/producttype/taxonomy.txt');

MB34 said...

Krzysztof,
What a great plugin. I've been able to do in less than a day what took me over a month to do with the mcDropdown plugin.

The last thing I need is to know how to pre-load this thing.

I am saving the full path to a database but if I just need to save the value, then that is ok.

One thing, though. If, for some reason, I selected something like
"Arts & Entertainment > Artwork > Paintings" and really wanted
"Arts & Entertainment > Artwork",
I would select "Choose level 3" in the third select. This results in a NULL value being sent. Is there a way to get the last value of the select that doesn't have 'Choose" in the text?

John Doe said...

Is it possible to add a title per <select> element? Currently it only creates a <select> element per level. But what I would really like is a way to add something like this:

<label for="SELECT__">TITLE FOR CURRENT LEVEL</label>
<select name="SELECT__">
<options......>
</select>

So the visitor has a better understanding what each <select> element represents.

Krzysztof Kotowicz said...

@ John Doe

Use the version 1.1 and pass a function to the choose option (see the demo in the zip file). Inside the function you might add new elements, but I'd recommend just changing the "choose" text based on current level.

MB34 said...

I've finally figured out hos to solve all but one of my problems.

This code will not add the items when you have 'Choose' in the selection and removes all the selects down to the one where you chose 'Choose..."

.each(function() {
str = $(this).text();
if(str.indexOf("Choose Level") == -1) {
labels.push(str);
} else {
// don't allow the first one to be removed
if(this.parentNode.name != 'primary_product_type_') {
$("select[name^='"+this.parentNode.name+ "']").remove();
}
}


Now, if I can just get some help on the preloading thing...

I would like to see it where I could pass the preload like this:
preselect: {["Arts & Entertainment"],["Crafts & Hobbies"],["Leather Crafts"]}
or something similar...

Krzysztof Kotowicz said...

@MB34

This is now possible with version 1.2 of the plugin.

Senor Bob said...

I like this but I want something more. I am looking for something that is like of shopping websites where you can modify the search (add a price range, etc.). Is there a way to do this without having individual pages, so like have something that makes the page out of what it has as information.

denis said...

Hi, u make very cool plugin. But i have some problems with it. I have structure like {"fruit":["apple","orange"]}
first select is "fruit" but the second is indexes of array 0 and 1, how i can get apple and orange, not indexes. Its possible?

kkotowicz said...

Use {"fruit": {"apple":"apple","orange":"orange"}}

Mr B said...

Oh, and I also don't understand how to make an "All Programs option with value "ALL". Each time I add it the the tree variable, I get empty select items.

BvB said...

There's been no activity here for a while, but if anyone is interested in discussing some of the fine points of OptionTree, please respond. My immediate question is how to turn off the spinner when you're done building any more selects. I stop the process by just passing nothing back from my on_each_change script, but that last spinner goes until the user clicks something to give me an event to turn it off with.

Huanhai24 said...

nice

86522543 said...

很好~~

homezzm said...

mark

firefly said...

so cool. thanks for your work.