2015-10-02 5 views
15

Ich benutze select2 version 4 mit mehreren Auswahl und ich unterstütze Benutzer neue Tags hinzufügen, aber ich möchte verhindern, dass Menschen ein neues Tag wählen, wenn dieses Tag bereits in meinem Backend existiert.Wie kann ich bei Verwendung des jquery select2-Plugins verhindern, dass neue Tags ausgewählt werden, wenn ein gültiger Wert des bereits aufgeführten Ajax-Aufrufs vorhanden ist?

Gerade jetzt, wenn ein Benutzer ein Tag gibt, das bereits existiert und ich habe Tags: true dann zeigt es zwei Elemente im Dropdown (das bestehende und das neue). Hier ein Beispiel:

enter image description here

wie Sie sehen können, „testTag2“ ist ein gültiger Tag von meinem Backend, so dass es bei der Auswahl zeigt sich aber wegen der templateResult Funktion und der Tatsache, dass Tags : true Es wird auch als zweites Element angezeigt (wodurch der Benutzer denkt, dass er es als neues Tag auswählen kann).

Gibt es trotzdem, nur die "NEUE" Tag-Auswahl in der Dropdown-Liste anzuzeigen, wenn dieser Text NICHT in der Dropdown-Liste als eine andere Option aufgeführt ist?

hier ist mein Javascript-Code:

function SetupAppTags() { 
$("#Tags").select2({ 
    theme: "classic", 
    width: "98%", 
    tags: true, 
    ajax: { 
     url: "/Tag/Search", 
     dataType: 'json', 
     delay: 300, 
     data: function(params) { 
      return { q: params.term }; 
     }, 
     processResults: function(data, params) { 
      return { results: data }; 
     }, 
     cache: false 
    }, 
    escapeMarkup: function(markup) { return markup; }, 
    minimumInputLength: 3, 
    templateResult: tagFormatResult, 
    templateSelection: tagSelectionResult 
}); 
} 

function tagFormatResult(tag) { 

if (tag.loading) { 
    return "Loading . . . <img src='/Content/Images/ajax-loader.gif' />"; 
} else { 

    if (tag.name) { 
     var existsAlready = $("#Tags option[value='" + tag.id + "']").length > 0; 
     if (existsAlready) { 
      return null; 
     } 
     return tag.name; 
    } 

    var length = $('#tagsContainer .select2-selection__choice').filter(function() { 
     return $(this).attr("title").toUpperCase() === person.text.toUpperCase(); 
    }).length; 

    if (length == 1) { 
     return null; 
    } 
    return tag.text + " [NEW]"; 
} 

}

+0

kann es Ihnen möglich ist, eine Geige für diese zu schaffen? Wenn Ajax nicht möglich ist, reicht sogar ein einfaches Array von Daten aus. – vijayP

Antwort

4

Bitte korrigieren Sie mich, wenn ich Ihre Frage falsch verstanden. Aber nach meinem Verständnis habe ich folgende Lösung gefunden.

Für Demo-Zwecke habe ich vorbelastet paar <option> Elemente innerhalb <select> Box und statt ajax Datenfeed select2 I Ebene JavaScript array Objekt imitiert ajax Antwort verwenden.

Die Aktualisiert Geige Link: https://jsfiddle.net/vijayP/akyzt9Ld/11/

Die HTML ist wie folgt:

<div id="tagsContainer"> 
    <select id="Tags" multiple="" name="Tags"> 
     <option value="white">white</option> 
     <option value="green">green</option> 
    </select> 
</div> 

Hier können wir sehen, dass die letzte <option> in Drop-Down hat Text green.

JSON data Objekt, das ajax Antwort nachahmen sieht aus wie folgt:

var data = [{ id: 0, name:'yellow', text: 'yellow' }, 
       { id: 1, name:'green', text: 'green' }, 
       { id: 2, name:'cyan', text: 'cyan' }, 
       { id: 3, name:'violet', text: 'violet' }, 
       { id: 4, name:'gray', text: 'gray' } 
       ]; 

Auch hier ist die green an der Hausnummer 2.

select2 Initialisierung und unterstützt JavaScript-Code lautet:

var uniqueTexts = null; //array for holding unique text 
    $("#Tags").select2({ 
     tags: true, 
     data: data, 
     templateResult: tagFormatResult, 
     escapeMarkup: function (markup) { 
      uniqueTexts = null; 
      return markup; 
     }, 
     matcher: function (params, data) { 
      if(!uniqueTexts){ 
       uniqueTexts = []; 
      } 
      var modifiedData = null; 

      if ($.trim(params.term) === '' || data.text.indexOf(params.term) > -1) { 
       if(uniqueTexts.indexOf(data.text) == -1) 
       { 
        modifiedData = data; 
        uniqueTexts.push(modifiedData.text); 
       } 
      } 

      if(modifiedData) 
      { 
       return modifiedData; 
      } 

      return null; 
     } 
    }); 

    function tagFormatResult(tag) { 
     if (tag.loading) { 
      return "Loading . . . <img src='/Content/Images/ajax-loader.gif' />"; 
     } 
     else 
     { 
      var length = $('#tagsContainer .select2-selection__choice').filter(function() { 
       return $(this).attr("title").toUpperCase() === tag.text.toUpperCase(); 
      }).length; 

      if (length == 1) { 
       return tag.text; 
      } 

      if (tag.text) { 

       if(getOptionCount(tag.text) >1) 
        return tag.text; 
       else 
        return tag.text + " [NEW]"; 
      } 
      return tag.text + " [NEW]"; 
     } 
    } 

    function getOptionCount(tagText) 
    { 
     var count = 0; 
     var selectBoxOptions = $("#Tags option"); 
     $(selectBoxOptions).each(function(){ 
      if(tagText == $(this).text()) 
       count++;//increment the counter if option text is matching with tag text 
     }); 
     return count; 
    } 

var uniqueTexts ist ein Array, in dem eindeutiger Text angezeigt werden soll an den Endbenutzer. Beim Initiieren setzen wir es auf null. Die Idee ist also immer dann, wenn sich der Benutzer auf die Auswahlbox konzentriert ODER Suchbegriff eingibt; matcher: Callback wird für jede Option aufgerufen. Wir prüfen jede Option und sehen, ob sie bereits in uniqueTexts[] vorhanden ist oder nicht. Wenn es ein erstes Vorkommen ist, erlauben wir es zu zeigen; Andernfalls geben wir null zurück, um zu vermeiden, dass es das 2. Mal angezeigt wird.

Ich fügte auch einen escapeMarkup: Callback-Handler hinzu, der immer dann aufgerufen wird, wenn dem Endbenutzer Optionen angezeigt werden. Dies ist der Punkt, an dem wir uniqueTexts erneut auf null setzen können. Dies ist die komplette Zyklusrunde. Der Benutzer kann sich wieder fokussieren oder eintippen, um das Feld auszuwählen.

funktioniert wie folgt:

1) Zunächst wird geprüft, ob aktuelle Tag ist bereits ausgewählt worden sind oder nicht. Wenn es bereits dann ausgewählt wird, fügen Sie nicht „[NEW]“ Text tag.text

2) Zweitens wird geprüft, ob Strom tag.text vorhanden ist als select option Text mehr als einmal oder nicht. Wenn es an mehr als einer Stelle vorhanden ist, fügen Sie auch nicht "[NEW]" zu tag.text hinzu.

3) In allen anderen Fällen gehen Sie voran und fügen Sie "[NEW]" zu tag.text hinzu.

Ich hoffe, dass dir das ein bisschen hilft. Aktualisiert Link-: https://jsfiddle.net/vijayP/akyzt9Ld/11/

+0

Wenn ich ein Tag 'grün' eintrage und dann wieder grün einginge, sehe ich 2 Auswahlmöglichkeiten im Dropdown, die beide "grün" anzeigen. Das scheint die Frage nicht zu beantworten. Mein Ziel ist es, nur den einen Artikel zu zeigen und keine Duplikate in der Dropdown-Liste – leora

+0

@leora, ich werde es in der kommenden Woche überprüfen. – vijayP

+0

@leora. Die Antwort wurde aktualisiert. Bitte sehen Sie es sich an. – vijayP

9

zu Select2 Nach Options

Ändern der Optionen angepasst werden bei der Suche Wenn Benutzer durch Eingabe der Suchbegriffe die Ergebnisse filtern nach unten in das Suchfeld verwendet Select2 ein interner "Matcher", um Suchbegriffe mit Ergebnissen abzugleichen. Wenn ein Remote-Datensatz verwendet wird, erwartet Select2, dass die zurückgegebenen Ergebnisse bereits gefiltert wurden.

Key-Matcher Wert Eine Funktion, die Suchparameter und das Datenobjekt abfragt. Select2 übergibt die einzelnen Datenobjekte, die übergeben wurden, einzeln vom Datenadapter zurück in den Matcher, um zu ermitteln, wenn sie angezeigt werden sollen. Es werden nur die Objekte der ersten Ebene übergeben. Wenn Sie also mit verschachtelten Daten arbeiten, müssen Sie diese einzeln anpassen: .

matcher: function (params, data) { 
    // If there are no search terms, return all of the data 
    if ($.trim(params.term) === '') { 
    return data; 
    } 

    // `params.term` should be the term that is used for searching 
    // `data.text` is the text that is displayed for the data object 
    if (data.text.indexOf(params.term) > -1) { 
    var modifiedData = $.extend({}, data, true); 
    modifiedData.text += ' (matched)'; 

    // You can return modified objects from here 
    // This includes matching the `children` how you want in nested data sets 
    return modifiedData; 
    } 

    // Return `null` if the term should not be displayed 
    return null; 
} 

Ich denke, dies ist der typische Fall, mit der Ausnahme, dass Sie („angepasst“) mit („“) ersetzen soll, und fügen Sie sonst noch hinzufügen „[NEW]“ in Ihrem Fall.

Die vom ajax-Aufruf zurückgegebenen Daten sollten die Eingabe für Ihren Matcher sein.

so Ihr Code sollte wie folgt aussehen:

matcher: function (params, data) { 
    // If there are no search terms, return all of the data 
    if ($.trim(params.term) === '') { 
    return data; 
    } 

    // `params.term` should be the term that is used for searching 
    // `data.text` is the text that is displayed for the data object 
    if (data.text.indexOf(params.term) > -1) { 
    var modifiedData = $.extend({}, data, true); 
    //match was found then just show it. 
    // modifiedData.text += ' (matched)'; 

    // You can return modified objects from here 
    // This includes matching the `children` how you want in nested data sets 
    return modifiedData; 
    } 
    else 
    { 
    //there is not match found , suggest adding NEW Tag. 
    modifiedData.text += '[NEW]'; 
    return modifiedData; 
    } 

    // Return `null` if the term should not be displayed 
    return null; 
}