Creating minLength exception in jQueryUI autocomplete - javascript

I have a collection of data whereby the requirements are for the autocomplete to show results after 3 characters have been written. However, there is one piece of data that which is only two characters long.. ('LG').
So my question is;
Is there a way to keep :minLength:3 whilst creating an exception for when certain characters are typed, such as ('LG')?
I've been trying to hard code the result within the success parameter, as can be seen below but it's not working as intended. I'm hoping I'm on the right track though?
Here is a code snippet, and plunk of complete code thus far;
success: function (LG, resp) {
if (LG.length === 2) {
LG.push({
label: 'LG',
value: 'LG',
});
}
response(LG);
var results = [];
$.each(resp.Q0, function(k, v) {
if (v.indexOf(request.term.toUpperCase()) >= 0) {
results.push(v);
}
});
response(results);
}
});
},
https://plnkr.co/edit/wfAoi0sZDdDd0pCufQi9

I think an option is modify the minChars and modify the success function.
Here i add you the code, tell me if would suit your problem.
$(document).ready(function() {
setTimeout(function() {
$('#_Q0').autocomplete({
source: function(request, response) {
$.ajax({
url: "brands.json",
dataType: "JSON",
type: "GET",
success: function (resp) {
var results = [];
$.each(resp.Q0, function(k, v) {
if (request.term.length >= 3 && v.indexOf(request.term.toUpperCase()) >= 0) {
results.push(v);
}
if (request.term.length == 2 && request.term.toUpperCase() == v) {
results.push(v);
}
});
response(results);
}
});
},
autoFocus: true,
minLength: 2,
response: function(event, ui) {
if (!ui.content.length) {
var noResult = {
value: "",
label: "No results found"
};
ui.content.push(noResult);
}
}
});
var render = $('#_Q0').autocomplete('instance')._renderMenu;
$('#_Q0').autocomplete('instance')._renderMenu = function(ul, items) {
items.push({
label: 'AUTRE MARQUE',
value: 'AUTRE MARQUE',
last: true
});
render.call(this, ul, items);
};
}, 100);
});
The point i dont like too much is i had to hardcode the minChars into the success function, maybe we could find the way to recover the value from the property "minChars"
https://plnkr.co/edit/ygtMteIH1J5EI5KUMU3C?p=preview

Related

Select2 group with Infinite scroll

I am using select2 group option with infinite scroll and data are coming by Ajax calling per page 10. Here is some problem arises, suppose user 1 has 15 data and user 2 has 15 data, at first 10 data are coming from user 1 and in next page 10 (5 data for user1 and 5 data for user2). no problem for data getting but the problem is user 1 group showing double. How can I prevent double display to my select2 options group? Has there any way to make an option group again?
HTML CODE
<div class="container">
<form id="frm">
<h1>Solution 1</h1>
<div class="row">
<div class="col-4">
<div class="form-group">
<label for="tagInput">Get data by ajax calling</label>
<select class="form-control" id="pictures_tag_input">
</select>
<small class="form-text text-muted"><p class="text-info">Infinite Scroll</p></small>
</div>
</div>
</div>
</form>
</div>
JS CODE
$(document).ready(function() {
// solution 1
//example.com/articles?page[number]=3&page[size]=1
http: $("#pictures_tag_input").select2({
placeholder: "Search for options",
ajax: {
url: "https://jsonplaceholder.typicode.com/users/1/todos",
dataType: "json",
global: false,
cache: true,
delay: 250,
minimumInputLength: 2,
data: function(params) {
// console.log(params.page || 1);
return {
q: params.term, // search term
_page: params.page || 1,
_limit: 10 // page size
};
},
processResults: function(data, params) {
params.page = params.page || 1;
var datx = getNestedChildren(data);
// console.log(datx);
return {
results: datx,
pagination: {
more: true
}
};
} //end of process results
} // end of ajax
});
function getNestedChildren(list) {
var roots = [];
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (roots.length === 0) {
var obj = {
text: "User " + node.userId,
children: [{ id: node.id, text: node.title }]
};
roots.push(obj);
} else {
var obj = {
text: "User " + node.userId,
children: [{ id: node.id, text: node.title }]
};
var rootArray = $.map(roots, function(val, i) {
var vl = "User " + node.userId;
if (val.text === vl) return val;
else return undefined;
});
if (rootArray.length > 0) {
var obj1 = {
id: node.id,
text: node.title
};
rootArray[0].children.push(obj1);
} else {
roots.push(obj);
}
}
}
return roots;
}
});
Demo
https://codepen.io/mdshohelrana/pen/MLVZEG
Just try to use the following code
templateResult: function(data) {
if (typeof data.children != 'undefined') {
$(".select2-results__group").each(function() {
if (data.text == $(this).text()) {
return data.text = '';
}
});
}
return data.text;
}
NOTE: Need to group from server side, Other wise you have to make master details from client side.
the accepted answer didn't work for me and I don't see why should that work. A return in the $.each will not return from the templateResult() function.
Here is an approach that worked for me.
It is not necessary to build a nested list by getNestedChildren(list) on javascript side. It is much easier to build it on server side instead.
The appearance of search results in the dropdown (options and the optgroups) can be customized by using the templateResult option. I removed the duplicated optgroups and labels by this option.
check the templateResult: formatOptions, part of the code
$(document).ready(function() {
$("#pictures_tag_input").select2({
placeholder: "Search for options",
templateResult: formatOptions,
ajax: {
url: "https://jsonplaceholder.typicode.com/users/1/todos",
dataType: "json",
global: false,
cache: true,
delay: 250,
minimumInputLength: 2,
data: function(params) {
return {
q: params.term,
_page: params.page || 1,
_limit: 10
};
},
processResults: function(data, params) {
params.page = params.page || 1;
return {
results: data,
pagination: {
more: true
}
};
} //end of process results
} // end of ajax
});
function formatOptions(item, container, $el) {
// optgroups section
if (item.children && item.children.length > 0) {
// don't format the repeated optgroups!
if ($(".select2-results__group").text() === item.text) {
return;
}
if ($('[aria-label="' + item.text + '"]').length > 0) {
return;
}
// the first occasion of the given optgroup
return $el;
}
// options section
// here you can implement your own logic
// if you want to customise the output of the options
$el.addClass('something-special-result result');
return $el;
}
});
maybe the problem is a source of a data
You call user 1 .... server return a 1
You call user 2 .... server return a 1
You call user 3 .... server return a 2
You call user 4 .... server return a 2
You call user 5 .... server return a 3
You call user 6 .... server return a 3
curent_user = 1;
$(document).ready(function() {
http: $("#pictures_tag_input").select2({
placeholder: "Search for options",
ajax: {
url: "https://jsonplaceholder.typicode.com/users/1/todos",
dataType: "json",
global: false,
cache: false,
minimumInputLength: 2,
data: function(params) {
console.log("params",params || 1);
return {
q: params.term, // search term
_page: curent_user,
_limit: 10 // page size
};
},
processResults: function(data, params) {
curent_user += 2;
var datx = getNestedChildren(data);
console.log("data: ", data);
return {
results: datx,
pagination: {
more: true
}
};
} //end of process results
} // end of ajax
});
function getNestedChildren(list) {
var roots = [];
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (roots.length === 0) {
var obj = {
text: "User " + node.userId,
children: [{ id: node.id, text: node.title }]
};
roots.push(obj);
} else {
var obj = {
text: "User " + node.userId,
children: [{ id: node.id, text: node.title }]
};
var rootArray = $.map(roots, function(val, i) {
var vl = "User " + node.userId;
if (val.text === vl) return val;
else return undefined;
});
if (rootArray.length > 0) {
var obj1 = {
id: node.id,
text: node.title
};
rootArray[0].children.push(obj1);
} else {
roots.push(obj);
}
}
}
return roots;
}
});
so if you skip a one step
You call user 1 .... server return a 1
You call user 3 .... server return a 2
You call user 5 .... server return a 3
I just found a better solution which does not result in a (duplicated) optgroup being rendered as an empty option:
processResults: function( json, params ){
setTimeout( function() {
var $prevOptions = false;
var $prevGroup = false;
// loop
$('.select2-results__option[role="group"]').each(function(){
// vars
var $options = $(this).children('ul');
var $group = $(this).children('strong');
// compare to previous
if( $prevGroup && $prevGroup.text() === $group.text() ) {
$prevOptions.append( $options.children() );
$(this).remove();
return;
}
// update vars
$prevOptions = $options;
$prevGroup = $group;
});
}, 1 );
return json;
}
Advanced Custom Fields uses the exact same code for their WordPress plugin in order to fix this issue, ajax-load and group posts from different post-types.

Dynamic search bar - Adding element from drop down in ASP.NET MVC5

I'm programming in ASP.NET MVC5. On one of my views I need to be able to create a search bar. For this example, lets say you are searching for names. When you start typing a person's name, all of the results will be displayed in a drop down list as you type.
Here is the tricky part that I need help with. I want there to be a button for each entry in the drop down list to "Add" that person name to a table.
For example, I'm looking for the name "Debo" As I type "D-E-B", I see the name I want in the drop down list. I click "Add" and it removes the name "Debo" from the drop down list and adds it to my table. Once "Debo" has been added to the table, I need to be able to see Debo's age and gender that I wouldn't see in the drop down list.
I don't have any code examples because I'm not even sure where to start. I've researched this like crazy, but I cannot find anything. Any help or pointing me in the right direction, will be greatly appreciated,
I am using autocomplete by JQueryUI.
Please refer below code hopefully it will helps you.
JavaScript Code:
$("#member_CompanyName").autocomplete({
highlightClass: "bold-text",
search: function () {
$(this).addClass('working');
},
source: function (request, response) {
var companyDetails = new Array();
$.ajax({
url: "/ControllerName/JsonActionResult",
async: false,
data: {
"parm": request.term
},
success: function (data) {
if (data.length === 0) {
companyDetails[0] = {
label: "No Result Found",
Id: ""
};
} else {
for (var i = 0; i < data.length; i++) {
companyDetails[i] = {
label: data[i].Value,
Id: data[i].Key
};
$("#no-companyfound").css("display", "none");
}
}
}
});
response(companyDetails);
},
minLength: 2,
select: function (event, ui) {
/*Select Function works on when you selects element from Response List*/
$.ajax({
async: false,
url: "/ControllerName/JsonActionResultonClick",
data: {
"id": ui.item.Id
},
success: function (data) {
// Do your success logic here
},
error: function (xhr, ajaxOptions, thrownError) {
// Error Logic here
}
});
},
open: function () {
$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function () {
$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
}
});
Controller Code:
[HttpGet]
public JsonResult JsonActionResult(string parm) {
// Replace your special Character like "-,~" etc from your search string
var result = new List < KeyValuePair < string,
string >> ();
foreach(var item in _obj_fulldetails.GetCompanylistSearch(parm)) {
result.Add(new KeyValuePair < string, string > (item.Value.ToString(), item.Text));
}
return Json(result, JsonRequestBehavior.AllowGet);
}
You can implement "Add"
button your logic on Item select. If you still want add button you can edit response string into JS.
See my response screenshot :

Jquery Context Menu ajax fetch menu items

I have a jquery context menu on my landing page where I have hardcode menu items. Now I want to get the menu items from server. Basically the idea is to show file names in a specified directory in the context menu list and open that file when user clicks it...
This is so far I have reached..
***UPDATE***
C# code
[HttpPost]
public JsonResult GetHelpFiles()
{
List<Manuals> manuals = null;
var filesPath = Server.MapPath(#"\HelpManuals");
var standardPath = new DirectoryInfo(filesPath);
if (standardPath.GetFiles().Any())
{
manuals = standardPath.GetFiles().Select(x => new Manuals
{
Name = GetFileNamewithoutExtension(x.Name),
Path = x.Name
}).ToList();
}
return Json(manuals, JsonRequestBehavior.AllowGet);
}
private string GetFileNamewithoutExtension(string filename)
{
var extension = Path.GetExtension(filename);
return filename.Substring(0, filename.Length - extension.Length);
}
JavaScript Code
$.post("/Home/GetHelpFiles", function (data) {
$.contextMenu({
selector: '#helpIcon',
trigger: 'hover',
delay: 300,
build: function($trigger, e) {
var options = {
callback: function(key) {
window.open("/HelpManuals/" + key);
},
items: {}
};
$.each(data, function (item, index) {
console.log("display name:" + index.Name);
console.log("File Path:" + index.Path);
options.items[item.Value] = {
name: index.Name,
key: index.Path
}
});
}
});
});
Thanks to Matt. Now, the build function gets fire on hover.. but im getting illegal invocation... and when iterating through json result, index.Name and this.Name gives correct result. But item.Name doesn't give anything..
to add items to the context menu dynamically you need to make a couple changes
$.contextMenu({
selector: '#helpIcon',
trigger: 'hover',
delay: 300,
build: function($trigger, e){
var options = {
callback: function (key) {
var manual;
if (key == "adminComp") {
manual = "AdminCompanion.pdf";
} else {
manual = "TeacherCompanion.pdf";
}
window.open("/HelpManuals/" + manual);
},
items: {}
}
//how to populate from model
#foreach(var temp in Model.FileList){
<text>
options.items[temp.Value] = {
name: temp.Name,
icon: 'open'
}
</text>
}
//should be able to do an ajax call here but I believe this will be called
//every time the context is triggered which may cause performance issues
$.ajax({
url: '#Url.Action("Action", "Controller")',
type: 'get',
cache: false,
async: true,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (_result) {
if (_result.Success) {
$.each(_result, function(item, index){
options.items[item.Value] = {
name: item.Name,
icon: 'open'
}
});
}
});
return options;
}
});
so you use build and inside of that define options and put your callback in there. The items defined in there is empty and is populated in the build dynamically. We build our list off of what is passed through the model but I believe you can put the ajax call in the build like I have shown above. Hopefully this will get you on the right track at least.
I solved this problem the following way.
On a user-triggered right-click I return false in the build-function. This will prevent the context-menu from opening. Instead of opeing the context-menu I start an ajax-call to the server to get the contextMenu-entries.
When the ajax-call finishes successfully I create the items and save the items on the $trigger in a data-property.
After saving the menuItems in the data-property I open the context-menu manually.
When the build-function is executed again, I get the items from the data-property.
$.contextMenu({
build: function ($trigger, e)
{
// check if the menu-items have been saved in the previous call
if ($trigger.data("contextMenuItems") != null)
{
// get options from $trigger
var options = $trigger.data("contextMenuItems");
// clear $trigger.data("contextMenuItems"),
// so that menuitems are gotten next time user does a rightclick
// from the server again.
$trigger.data("contextMenuItems", null);
return options;
}
else
{
var options = {
callback: function (key)
{
alert(key);
},
items: {}
};
$.ajax({
url: "GetMenuItemsFromServer",
success: function (response, status, xhr)
{
// for each menu-item returned from the server
for (var i = 0; i < response.length; i++)
{
var ri = response[i];
// save the menu-item from the server in the options.items object
options.items[ri.id] = ri;
}
// save the options on the table-row;
$trigger.data("contextMenuItems", options);
// open the context-menu (reopen)
$trigger.contextMenu();
},
error: function (response, status, xhr)
{
if (xhr instanceof Error)
{
alert(xhr);
}
else
{
alert($($.parseHTML(response.responseText)).find("h2").text());
}
}
});
// This return false here is important
return false;
}
});
I have finally found a better solution after reading jquery context menu documentation, thoroughly..
C# CODE
public JsonResult GetHelpFiles()
{
List<Manuals> manuals = null;
var filesPath = Server.MapPath(#"\HelpManuals");
var standardPath = new DirectoryInfo(filesPath);
if (standardPath.GetFiles().Any())
{
manuals = standardPath.GetFiles().Select(x => new Manuals
{
Name = GetFileNamewithoutExtension(x.Name),
Path = x.Name
}).ToList();
}
return Json(manuals, JsonRequestBehavior.AllowGet);
}
HTML 5
<div id="dynamicMenu">
<menu id="html5menu" type="context" style="display: none"></menu>
</div>
JavaScript Code
$.post("/Home/GetHelpFiles", function (data) {
$.each(data, function (index, item) {
var e = '<command label="' + item.Name + '" id ="' + item.Path + '"></command>';
$("#html5menu").append(e);
});
$.contextMenu({
selector: '#helpIcon',
trigger: 'hover',
delay: 300,
items: $.contextMenu.fromMenu($('#html5menu'))
});
});
$("#dynamicMenu").on("click", "menu command", function () {
var link = $(this).attr('id');
window.open("/HelpManuals/" + link);
});
Here's my solution using deferred, important to know that this feature is supported for sub-menus only
$(function () {
$.contextMenu({
selector: '.SomeClass',
build: function ($trigger, e) {
var options = {
callback: function (key, options) {
// some call back
},
items: JSON.parse($trigger.attr('data-storage')) //this is initial static menu from HTML attribute you can use any static menu here
};
options.items['Reservations'] = {
name: $trigger.attr('data-reservations'),
icon: "checkmark",
items: loadItems($trigger) // this is AJAX loaded submenu
};
return options;
}
});
});
// Now this function loads submenu items in my case server responds with 'Reservations' object
var loadItems = function ($trigger) {
var dfd = jQuery.Deferred();
$.ajax({
type: "post",
url: "/ajax.php",
cache: false,
data: {
// request parameters are not importaint here use whatever you need to get data from your server
},
success: function (data) {
dfd.resolve(data.Reservations);
}
});
return dfd.promise();
};

Select2 limit number of tags

Is there a way to limit the number of tags a user can add to an input field using Select2?
I have:
$('#tags').select2({
containerCssClass: 'supplierTags',
placeholder: "Usual suppliers...",
minimumInputLength: 2,
multiple: true,
tokenSeparators: [",", " "],
placeholder: 'Usual suppliers...',
createSearchChoice: function(term, data) {
if ($(data).filter(function() {
return this.name.localeCompare(term) === 0;
}).length === 0) {
return {id: 0, name: term};
}
},
id: function(e) {
return e.id + ":" + e.name;
},
ajax: {
url: ROOT + 'Call',
dataType: 'json',
type: 'POST',
data: function(term, page) {
return {
call: 'Helpers->tagsHelper',
q: term
};
},
results: function(data, page) {
return {
results: data.tags
};
}
},
formatResult: formatResult,
formatSelection: formatSelection,
initSelection: function(element, callback) {
var data = [];
$(element.val().split(",")).each(function(i) {
var item = this.split(':');
data.push({
id: item[0],
name: item[1]
});
});
callback(data);
}
});
It would be great if there could be/is a simple parameter like limit: 5 and a callback to fire when the limit is reached.
Sure, with maximumSelectionLength like so:
$("#tags").select2({
maximumSelectionLength: 3
});
Maximum Selection Length
Select2 allows the developer to limit the number of items that can be
selected in a multi-select control.
http://ivaynberg.github.io/select2/
It has no native callback, but you can pass a function to formatSelectionTooBig like this:
$(function () {
$("#tags").select2({
maximumSelectionLength: 3,
formatSelectionTooBig: function (limit) {
// Callback
return 'Too many selected items';
}
});
});
http://jsfiddle.net/U98V7/
Or you could extend formatSelectionTooBig like this:
$(function () {
$.extend($.fn.select2.defaults, {
formatSelectionTooBig: function (limit) {
// Callback
return 'Too many selected items';
}
});
$("#tags").select2({
maximumSelectionLength: 3
});
});
Edit
Replaced maximumSelectionSize with the updated maximumSelectionLength. Thanks #DrewKennedy!
method 1
$("#tags").select2({
maximumSelectionLength: 3
});
method 2
<select data-maximum-selection-length="3" ></select>
list of all available options https://select2.org/configuration/options-api
The accepted answer doesn't mention that the maximumSelectionLength statement should be inside the document.ready function. So for anyone who is having the same trouble I did, here is the code that worked for me.
$(document).ready(function() {
$("#id").select2({
maximumSelectionLength: 3
});
});
$("#keywords").select2({
tags : true,
width :'100%',
tokenSeparators: [','],
maximumSelectionLength: 5,
matcher : function(term,res){
return false;
},
"language": {
'noResults': function(){
return "Type keywords separated by commas";
}
}
}).on("change",function(e){
if($(this).val().length>5){
$(this).val($(this).val().slice(0,5));
}
});
Try like this. It'll short up to 5 keywords.
This is not working for me, I am getting query function not defined for Select2, so here is another workaround.
var onlyOne=false;
$("selector").select2({
maximumSelectionSize:function(){
if(onlyOne==true)
return 1;
else
return 5;
}
});
This setting can be defined as function and it's called every time you start searching something.
Important thing is that you have something defined outside this select2 closure so you can check it (access it). In this case you could somewhere in your program change value of onlyOne and of course this returned limit can also be dynamical.
This is working for me.
$("#category_ids").select2({ maximumSelectionLength: 3 });
Send the Get Request to action method and the Map the class properties to drop down id and text property
$("#DropDownId").select2({
minimumInputLength: 3,
maximumSelectionLength: 10,
tags: [],
ajax: {
url: "#Url.Action("ActionName", "ControllerName")",
type: "get",
dataType: 'json',
delay: 250,
data: function (params) {
return {
Title: params.term // search term
};
},
processResults: function (response) {
return {
results: $.map(response, function (item) {
return {
text: item.Title,
id: item.Id
}
})
};
}
}
});
Action Method
[HttpGet]
public JsonResult ActionName(string Title)
{
ClassName obj= new ClassName ();
obj.Title = "PMPAK";
obj.Id= -1;
obj.Add(nibafInstitute);
return Json(obj, JsonRequestBehavior.AllowGet);
}
public class ClassName
{
public int Id{ get; set; }
public string Title { get; set; }
}

How to dynamically generate options for RichCombo in CKEDITOR?

There is a form on my page with textarea (CKEDITOR) and select field <select id="_photogalleries" multiple="multiple"></select>. I'd like options in RichCombo to depend on the options that are selected in select with id #_photogalleries. Is there any way to regenerate RichCombo dynamically?
Thanks in advance.
CKEDITOR.plugins.add('style_plugin', {
requires: ['richcombo'],
init: function(editor) {
var pluginName = 'style_plugin';
var config = editor.config,
lang = editor.lang.format;
editor.ui.addRichCombo('photogalleries', {
label: "Фоторепортаж",
title: "Фоторепортаж",
voiceLabel: "Фоторепортаж",
className: 'cke_format',
multiSelect: false,
icon: CKEDITOR.plugins.getPath('style_plugin') + 'photo-list-horizontal.png',
panel: {
css: [config.contentsCss, CKEDITOR.getUrl(editor.skinPath + 'editor.css')],
voiceLabel: lang.panelVoiceLabel
},
init: function () {
this.startGroup("Фоторепортаж");
var list=this;
$("#_photogalleries option:selected").each(function(index, value){
console.log(index, value);
list.add("#HORIZONTAL_GALLERY_"+ $(value).val()+"#", "(Г) " + $(value).text(), "(Г) " + $(value).text());
list.add("#VERTICAL_GALLERY_"+ $(value).val()+"#", "(В) " + $(value).text(), "(В) " + $(value).text());
});
},
onClick: function (value) {
editor.focus();
editor.fire('saveSnapshot');
editor.insertHtml(value);
editor.fire('saveSnapshot');
}
});
}
});
This works for me and you dont have to keep a global variable.
CKEDITOR.plugins.add('systemdata', {
init: function (editor) {
var fnData = editor.config.fnData;
if (!fnData || typeof (fnData) != 'function')
throw "You must provide a function to retrieve the list data.";
editor.ui.addRichCombo('systemDataCmb',
{
allowedContent: 'abbr[title]',
label: "System Data",
title: "System Data",
multiSelect: false,
init: function () {
var self = this;
var content = fnData();
$.each(content, function(index, value) {
// value, html, text
self.add(value.name, value.name, value.name)
});
}
}
Then to set the function to get the data put this somewhere where you setup the ckeditor
CKEDITOR.replaceAll(function(element, config) {
config.startupFocus = true;
config.fnData = function() {
var returnData = null;
$.ajax({
url: "/GetData",
async: false,
data: { id: 1 },
}).done(function(result) { returnData= result; });
return returnData;
};
});
It assumes you bring back a json response that has an array of items that have a value property, that can be easily changed though.
I guess I found a solution that worked for me. It was to keep a list object in a global variable and then modify it when onchange event fires in the external select.
I solved this trouble with a single line:
YOURCOMBO.createPanel(editor);
For example:
var comboTeam = editor.ui.get("team");
comboTeam.createPanel(editor);//This is important, if not, doesnt works
Now you can add items to the combo
comboTeam.add("name","name","name");
comboTeam.add("name2","name2","name2");
comboTeam.add("name3","name3","name3");

Categories

Resources