Twitter typeahead добавляет пользовательские данные в набор данных

Я использую twitter typeahead для отображения предложений по категориям, которые мне подходят. Проблема с отображением подкатегорий. Если category has sub-categories then expand/collapse icon отображается вместе с предложением, если пользователь выбирает один из них, подкатегории должны отображаться под ним, я преуспел в части отображения, но cannot update the dataset типа впереди, так что, когда пользователь выбирает один, подкатегории он должен отображаться на входе. Please use keyboard on Jsfiddle because i have tried only in keypress. Ниже приведен мой массив json.

JSFIDDLE здесь

[{
    "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
}]

Я пробовал следующее:

_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 здесь

например: в категории «Развлечения» есть подкатегории «фильмы» и «спорт».

Надеюсь, кто-нибудь мне поможет....


person Nouphal.M    schedule 21.08.2014    source источник
comment
Я немного взломал его, но он не сохраняет значения правильно. Также похоже, что кнопка «дети» добавляется после создания html, поэтому она добавляет дополнительные из них, потому что индексация неверна. Надеюсь, это будет вам в чем-то полезно, но нужно копаться во всем файле typeahead.bundle то, что вы взламывали, сейчас слишком далеко. jsfiddle.net/82hmLprb/1   -  person iabw    schedule 31.08.2014
comment
Все данные добавляются через Bloodhound. Он создает токены, хэши и кеш. Я думаю, все будет хорошо, если мы сможем обновить предметы в объекте Bloodhound.   -  person Nouphal.M    schedule 01.09.2014
comment
@Nouphal.M Эй, почему я еще не получил свою награду, я решил твою проблему!   -  person user3995789    schedule 15.09.2014


Ответы (2)


Изменить версию 2

Я снова выполнил рефакторинг, теперь все работает идеально.

Я удалил свои предыдущие правки и реорганизовал функцию onEnterKeyed следующим образом.

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());

Правка версии 1 устарела

Я выполнил рефакторинг своего решения, и теперь оно работает должным образом.

Я удалил свои предыдущие правки и добавил эту строку в метод getSuggestionNode.

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

Устарело ниже

Я решил вашу проблему, хотя она требует доработки с вашей стороны.

// 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);

Таким образом, вам не нужна пользовательская функция updateChild, хотя я не знаю, как вы реализуете раскрывающийся список, это решение добавит дочерний элемент в раскрывающийся список и сразу же покажет их, не нажимая клавишу ввода в родительском узле. Вы должны настроить это самостоятельно.

person user3995789    schedule 03.09.2014
comment
Записи повторяются, и они не предлагаются в текстовом поле. И раскрывающийся список является частью плагина опережающего ввода. - person Nouphal.M; 07.09.2014
comment
Но здесь подкатегории отображаются при запуске. Мне нужно, чтобы он отображался только при нажатии кнопки ввода на входе развлечения. то есть то, что я ищу, это добавлять и удалять элементы при вводе ключевого события и щелчке мыши. надеюсь вы поняли мою мысль.. - person Nouphal.M; 07.09.2014
comment
Ваша рефакторинговая ссылка недействительна. Как я мог увидеть ваше решение? - person Nouphal.M; 15.09.2014
comment
@Nouphal.M Это действительно и работает, jsfiddle.net/8nqk6qrr. Также, если вы не можете заставить это работать, я использую gist, попробуйте это в своем jsfiddle, и это сработает. Ты мог просто сказать мне это раньше, и я с нетерпением жду этой награды. - person user3995789; 15.09.2014
comment
Да, это работает как шарм. Проверьте, получили ли вы свою награду. я принял ваше решение - person Nouphal.M; 15.09.2014
comment
нет, срок действия награды @Nouphal.M истек, если вы явно не дадите ее мне, я ее не получу, поэтому перезапустите награду (желательно с двойными баллами из-за задержки) и дайте ее мне, я трачу так много времени на нем, и я решил его более недели назад. - person user3995789; 15.09.2014
comment
Предоставили вашу щедрость. :) - person Nouphal.M; 15.09.2014
comment
@ Nouphal.M, извините, что беспокою вас дальше, я не получил награду, можете ли вы убедиться, что вы нажали синюю кнопку награды. - person user3995789; 17.09.2014

Здесь другой подход

Вы можете рассматривать каждую группу childCategories как собственный источник данных. Затем используйте парадигму Multiple Datasets, чтобы автоматически применять заголовок для дочерних Предметы.

Второй параметр $.typeahead(options, [*datasets]) принимает массив наборов данных. Мы можем преобразовать каждый набор дочерних элементов в собственный набор данных следующим образом:

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);
    }
});

Обратите внимание, что мы определили шаблон заголовка для элементов в этом источнике данных. Мы можем стилизовать его следующим образом:

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

Элементы, которые не были частью дочерней группы, могли быть добавлены как часть одного источника данных ungrouped:

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);
};

Преимущество этого решения состоит в том, что он минимально переопределяет существующий код typeahead и Bloodhound, работая в рамках платформы для обеспечения функциональности группировки.

Кроме того, он предоставляет интуитивно понятный пользовательский интерфейс для пользователей, которые могут знать название дочернего элемента, который они ищут, но не хотят щелкать по каждой категории, чтобы найти его. Большинство локальных поисков могут тривиально выполнять поиск по всем полям.

Рабочая демонстрация в jsFiddle

screenshot

Кроме того: я бы постарался избежать прямого изменения исходного кода. Из-за этого очень трудно увидеть, где вы внесли свои собственные изменения. Вместо этого попробуйте использовать CDN для всей библиотеки и написать плагин или оболочку поверх нее. Это значительно облегчит включение будущих изменений.

person KyleMit    schedule 06.09.2014
comment
В вашем примере я не могу выбрать элемент со значением eeen - person Nouphal.M; 07.09.2014
comment
@ Nouphal.M, да, это будет ограничением этого подхода. Конечно, вы можете добавить родительские элементы в несортированный список, если хотите, чтобы их можно было выбрать самостоятельно. Не совсем то, что вы имели в виду. Но по-прежнему предоставляет относительно интуитивно понятный интерфейс, который демонстрирует некоторый способ группировки. - person KyleMit; 08.09.2014
comment
Я хочу добавить кнопку развертывания/свертывания в раскрывающийся список, если какой-либо элемент имеет подкатегории и иметь возможность добавлять/удалять дочерние элементы на лету. - person Nouphal.M; 08.09.2014