2

I have structured data, with various types of data in it. For the sake of simplicity, let's say I have something like this:

{
  person : [
    { 
      name : 'paul',
      title : 'prof',
      profession : 'teacher',
      start: '2010-10-10'
    },
    { 
      name : 'joe',
      title : 'dr',
      profession : 'scientist',
      start: '2000-01-01'
    }
  ]
  book : [
    {
       title : 'the cat in the hat'
    }
  ] 
}

I would like to have an autocomplete box in javascript that lets me choose the names of these structured elements so the following results would be returned given the letter typed:

't' : {'person.title', 'book.title'}
'p' : {'person', 'person.profession'}

What is important to me is that the person might know the name of any of the variables within the tree. So if they type in the name of the top level variable, I only want to show that one and none of it's sub-elements, but if they type in the name of sub-element, I want the full path to that sub-element displayed. If they type in a top-level variable ("person"), I don't want to display all the sub-elements, only ones that always begin with that same set of letters.

Are there any libraries out there that can currently do this (provide a way of doing auto-complete on structured data) as opposed to normal auto-complete?

Clarification: I guess what I need is the ability to tell the auto-complete library a map of inputs and outputs to work with, such that typing "p" will end up hitting on the inputs "person" and "profession" and thus return "person" and "person.profession", and typing "t" hits on "title" for "person.title" and "title" for "book.title".

4
  • Let me clarify. Are you saying you want autocomplete on the property names or their values? Commented Nov 15, 2012 at 7:53
  • Property names could be served better(easily) with a dropdown. Not that i am saying autocomplete can't do the same... Commented Nov 15, 2012 at 7:57
  • @Pushpesh, I agree. For non-freeform input dropdowns FTW. They, too, have autocompletion. Commented Nov 15, 2012 at 8:06
  • This was a contrived example: A drop down would be hundreds of lines long and thus not user friendly. Commented Nov 15, 2012 at 8:50

3 Answers 3

1

Just wrote a function that recurses over an object to retrieve the fullpath property names as an array e.g. person.title. The array can then be used with jQueryUI autocomplete functionality. Please look at the fiddle to confirm this is what you wanted.

Fiddle here

var retrieveUniqueProps = ( function ( ) {

    var result = [];
    var added = {};

    isArray = function( o ) { 
        return Object.prototype.toString.call( o ) === "[object Array]";
    };

    isObject = function( o ) { return typeof o === "object"; };

    return function ( obj, parentPath ) {

        if( isArray( obj ) ) {

            for( var i = 0; i < obj.length; i++ ) {

                if( isArray( obj[i] ) || isObject( obj[i] ) ){ 
                    retrieveUniqueProps( obj[i], parentPath ); 
                }
            }

        } else if ( isObject( obj ) ) {

            for( var a in obj ) {

                if( obj.hasOwnProperty( a ) ) {

                    var fullpath = parentPath ? parentPath + "." + a : a;
                    if( !added[ fullpath ] ) {
                        result.push( fullpath );
                        added[ fullpath ] = true;
                    }

                    if( isArray( obj[a] ) || isObject( obj[a] ) ){ 
                        retrieveUniqueProps( obj[a], parentPath ? parentPath + "." + a : a ); 
                    }
                }
            }
        }

        return result;
    };


}());

var uniquePropertyNames = retrieveUniqueProps( o, "" );

UPDATE I have amended the source option of autocomplete to filter out the results as per your requirements. The last word must match what you have typed into the input. Check out the fiddle for the updated version.

 $("#props").autocomplete({
    source: function(request, response) {

                // The term the user searched for;
                var term = request.term;

                // Extract matching items:
                var matches = $.grep(uniquePropertyNames, function(item, index) {
                // Build your regex here:
                var subArray = item.split( "." );

                if( subArray[subArray.length - 1].indexOf( term ) !== 0 ) return false;
                return true;
            });

            // let autocomplete know the results:
            response(matches);        
        }
});
Sign up to request clarification or add additional context in comments.

3 Comments

This is the default functionality of autocomplete, and not what I want. My desired outcome differs in 2 main ways from your solution: 1) When I type 'p', I should only see words that start with that letter so not "anotherProp" (likely an easy fix via some parameter change). 2) I only want to see the results "person" and "person.profession", not "person.title".
@0xdabbad00 can I just clarify. So you want to return all entries whose last word starts with a p because the example you gave was type t return person.title and book.title.
That's correct. Your fix worked. You rock! Thank you. This work was for the site icebuddha.com, I'll make sure to credit you on there.
1

Take a look at the autocomplete jQuery-ui functionality : http://jqueryui.com/autocomplete/

You'll need to use the source parameter. Just read the api documentation.

Comments

-1

You can use the Object.getOwnProperty method to read all the keys of an object and run an autocomplete over the results.

Some discussions here - How to get an object's properties in JavaScript / jQuery?

1 Comment

You mean Object.getOwnPropertyNames. However, Object.keys is better. Compare the output of Object.keys([ 1, 2, 3 ]) and Object.getOwnPropertyNames([ 1, 2, 3 ]).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.