javascript - Twitter typeahead add custom data to dataset - Stack Overflow

I am using twitter typeahead to show category suggestions which works fine for me. The problem is with

I am using twitter typeahead to show category suggestions which works fine for me. The problem is with the display of sub-categories. If a category has sub-categories then expand/collapse icon is shown along with the suggestion, if the user selects one them the sub-categories has to be shown below it, i have succeeded in the display part but cannot update the dataset of typeahead so that when the user selects one the sub-categories it should be displayed in the input. Please use keyboard on Jsfiddle because i have tried only in keypress. The following is my json array

JSFIDDLE here

[{
    "id": "38",
    "value": "Entertaintment",
    "parent_id": "27",
    "children": "1",
    "childCategories": [{
        "id": "28",
        "value": "Movies",
        "parent_id": "38"
    }, {
        "id": "29",
        "value": "Sports",
        "parent_id": "38"
    }]
}, {
    "id": "40",
    "value": "eeen",
    "parent_id": "27",
    "children": "1",
    "childCategories": [{
        "id": "41",
        "value": "een child 1",
        "parent_id": "40"
    }]
}, {
    "id": "41",
    "value": "een child 1",
    "parent_id": "40",
    "children": "0",
    "childCategories": false
}]

I have tried the following:

_onEnterKeyed: function onEnterKeyed(type, $e) {
    var cursorDatum, topSuggestionDatum;
    cursorDatum = this.dropdown.getDatumForCursor();
    topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();
    //My custom condition, if category has children show sub-categories below 
    if (cursorDatum.raw && cursorDatum.raw.children == "1") {
        //below line is my failed try  
        //this.dropdown.updateChild('',cursorDatum.raw.childCategories,false); 
        var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;
        var childHTML='';
        $('.ttchild').remove();
        //adding the sub-categories to dropdown
        $.each(cursorDatum.raw.childCategories,function(i,v){
            childHTML += '<div class="tt-suggestion ttchild"><div class="suggestions"><span>'+this.value+'</span></div></div>';
        });
        $(childHTML).insertAfter('.tt-cursor');
        return;
    }

    if (cursorDatum) {
        this._select(cursorDatum);
        $e.preventDefault();
    } 
    else if (this.autoselect && topSuggestionDatum) {
        this._select(topSuggestionDatum);
        $e.preventDefault();
    }
},

//This is my custom function trying to update the dataset, but i know its totally wrong.
updateChild: function updateChild(query,childs) {
    var that = this;
    this.query = query;
    this.canceled = false;
    this.source(query, render);

    function render(childs) {
        if (!that.canceled && query === that.query) {
            that._render(query, childs);
        }
    }
},

JSFIDDLE here

e.g: The Entertainment category has subcategories movies and sports.

Hope any one would help me....

I am using twitter typeahead to show category suggestions which works fine for me. The problem is with the display of sub-categories. If a category has sub-categories then expand/collapse icon is shown along with the suggestion, if the user selects one them the sub-categories has to be shown below it, i have succeeded in the display part but cannot update the dataset of typeahead so that when the user selects one the sub-categories it should be displayed in the input. Please use keyboard on Jsfiddle because i have tried only in keypress. The following is my json array

JSFIDDLE here

[{
    "id": "38",
    "value": "Entertaintment",
    "parent_id": "27",
    "children": "1",
    "childCategories": [{
        "id": "28",
        "value": "Movies",
        "parent_id": "38"
    }, {
        "id": "29",
        "value": "Sports",
        "parent_id": "38"
    }]
}, {
    "id": "40",
    "value": "eeen",
    "parent_id": "27",
    "children": "1",
    "childCategories": [{
        "id": "41",
        "value": "een child 1",
        "parent_id": "40"
    }]
}, {
    "id": "41",
    "value": "een child 1",
    "parent_id": "40",
    "children": "0",
    "childCategories": false
}]

I have tried the following:

_onEnterKeyed: function onEnterKeyed(type, $e) {
    var cursorDatum, topSuggestionDatum;
    cursorDatum = this.dropdown.getDatumForCursor();
    topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();
    //My custom condition, if category has children show sub-categories below 
    if (cursorDatum.raw && cursorDatum.raw.children == "1") {
        //below line is my failed try  
        //this.dropdown.updateChild('',cursorDatum.raw.childCategories,false); 
        var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;
        var childHTML='';
        $('.ttchild').remove();
        //adding the sub-categories to dropdown
        $.each(cursorDatum.raw.childCategories,function(i,v){
            childHTML += '<div class="tt-suggestion ttchild"><div class="suggestions"><span>'+this.value+'</span></div></div>';
        });
        $(childHTML).insertAfter('.tt-cursor');
        return;
    }

    if (cursorDatum) {
        this._select(cursorDatum);
        $e.preventDefault();
    } 
    else if (this.autoselect && topSuggestionDatum) {
        this._select(topSuggestionDatum);
        $e.preventDefault();
    }
},

//This is my custom function trying to update the dataset, but i know its totally wrong.
updateChild: function updateChild(query,childs) {
    var that = this;
    this.query = query;
    this.canceled = false;
    this.source(query, render);

    function render(childs) {
        if (!that.canceled && query === that.query) {
            that._render(query, childs);
        }
    }
},

JSFIDDLE here

e.g: The Entertainment category has subcategories movies and sports.

Hope any one would help me....

Share Improve this question edited Aug 21, 2014 at 7:01 Rory McCrossan 338k41 gold badges320 silver badges351 bronze badges asked Aug 21, 2014 at 6:52 Nouphal.MNouphal.M 6,3381 gold badge19 silver badges28 bronze badges 3
  • I was hacking on it a little bit, but it's not saving the values correctly. It also looks like the 'haschildren' button is added after the html is generated, so it's adding extra of those because the indexing is wrong. Hopefully this is helpful to you in some way, but digging through the whole typeahead.bundle file you've been hacking on is a bridge too far right now. jsfiddle/82hmLprb/1 – iabw Commented Aug 31, 2014 at 14:05
  • All the data is added through bloodhound. It creates the tokens,hashes and cache. I think everything will be ok if we can update the items in bloodhound object – Nouphal.M Commented Sep 1, 2014 at 7:05
  • @Nouphal.M Hey, why haven't I got my bounty yet, I solved your problem! – user3995789 Commented Sep 15, 2014 at 10:50
Add a ment  | 

2 Answers 2

Reset to default 2 +400

Edit v.2

I refactored again, now it works perfect.

I removed my previous edits and refactored onEnterKeyed function as follows

var dataSet = this.dropdown.datasets[0];

// childHTML is replaced by childDom
// var childHTML='';
var childDom = $('<div></div>');
$('.ttchild').remove();
$.each(cursorDatum.raw.childCategories,function(i,v){

    var div = $('<div class="tt-suggestion ttchild"></div>');
    div.append('<div class="suggestions"><span>'+this.value+'</span></div>');


    var suggestion = v;

    // TODO console log this is duplicated from dataset
    var datasetKey = "ttDataset", valueKey = "ttValue", datumKey = "ttDatum";


    // this is what makes it show in the input box
    // set these data for the child element.
    div.data(datasetKey, dataSet.name);
    div.data(valueKey, dataSet.displayFn(suggestion));
    div.data(datumKey, suggestion);

    childDom.append(div);
});

// childHtml is replaced by childDom
$('.tt-cursor').append(childDom.children());

Deprecated Edit v.1

I refactored my solution, now it works as expected.

I removed my previous edits and added this line in the getSuggestionNode method.

for (var key in suggestion.childCategories) {
    var value = suggestion.childCategories[key];
    $el.append(getSuggestionNode(value));
}

Deprecated Below

I solved your problem, though it needs improvement on your part.

// I added this line
// add the child nodes to the suggestions.
suggestions = suggestions.reduce(function(res, num) { res.push(num); for (var i=0;i<num.children;i++) res.push(num.childCategories[i]);  return res; }, [])

// nodes are calculated based on suggestions
// but child nodes are not added to suggestions so their data is not set (see below line)
nodes = _.map(suggestions, getSuggestionNode);

// inside the suggestions.map function
// here .data sets the necessary values required to render the input on cursor change.
// since child nodes are not mapped they are ignored.
$el = $(html.suggestion).append(that.templates.suggestion(suggestion))
    .data(datasetKey, that.name)
    .data(valueKey, that.displayFn(suggestion))
    .data(datumKey, suggestion);

So you don't need a custom updateChild function, though I don't know how you implement the dropdown stuff, this solution will add the child to the dropdown and show them instantly, without pressing enter in the parent node. You should configure that on your own.

Here's a different approach

You could treat each group of childCategories as it's own datasource. Then use the Multiple Datasets paradigm to automatically apply a header for child items.

The second parameter to $.typeahead(options, [*datasets]) takes an array of datasets. We can convert each set of child elements into it's own dataset like this:

var dataSources = [];
$.each(movies, function(index, movieItem) {
    if (movieItem.childCategories) {
        var bloodhoundEngine = createBlounhoud(movieItem.childCategories, 'value');
        var dataSource = {
            name: movieItem.value,
            displayKey: 'value',
            source: bloodhoundEngine.ttAdapter(),
            templates: {
                header: '<h3 class="typeahead-group">' + movieItem.value + '</h3>'
            }
        };
        dataSources.push(dataSource);
    }
});

Notice that we've defined a header template for items in this datasource. We can style it like this:

.typeahead-group {
  margin: 0 20px 5px 10px;
  padding: 3px 0;
  border-bottom: 1px solid #ccc;
}

Elements that were not part of a child group could could all get added as part of a single ungrouped datasource:

var ungrouped = [];
$.each(movies, function(index, movieItem) {
    if (!movieItem.childCategories) {
        ungrouped.push(movieItem);
    }
});

function addUngroupedItems() {
    var bloodhoundEngine = createBlounhoud(ungrouped, 'value');
    var dataSource = {
        name: 'ungrouped',
        displayKey: 'value',
        source: bloodhoundEngine.ttAdapter()
    };
    // add to first position of array so it doesn't look like it's part of the group above it
    dataSources.unshift(dataSource);
};

This solution has the benefit of minimally overriding existing typeahead and bloodhound code while working within the framework to provide grouping functionality.

Also, it provides an intuitive UI for users that might know the name of the name of a child item they're looking for, but don't want to have to click through each category to find it. Most local searches can trivially search on all fields.

Working Demo in jsFiddle

Aside: I would try to avoid modifying the source code directly. It makes it very difficult to see where you have made your own modifications. Instead, try using a CDN for the whole library and writing a plugin or wrapper on top of it. This will make incoporating future revisions much easier.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745377021a4625046.html

相关推荐

  • javascript - Twitter typeahead add custom data to dataset - Stack Overflow

    I am using twitter typeahead to show category suggestions which works fine for me. The problem is with

    10小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信