Kendo textbox within dropdownlist - javascript

is possible to make textbox within the dropdownlist from Kendo? When user won't find on list what he needs, there should be textbox to set manually some value.
dropdown:
#(Html.Kendo().DropDownList()
.Name("Id")
.DataTextField("StringValue")
.DataValueField("Id")
.SelectedIndex(0))
javascript:
$('#AttributeValue_Id').kendoDropDownList({
dataSource: dataSource,
dataTextField: "Text",
dataValueField: "Value",
optionLabel: '#Html.Raw(T("Product.Attribute.SelectValue"))',
dataBound: function () {
$('#AttributeValue_Id').data('kendoDropDownList').select(0);
}
});
Values in this dropdown depend on another dropdown, where we pick attribute and then this dropdown is getting new data dynamically. Somebody know any solution?

Ok I solved this issue. Solution is:
when the element on dropdown filter is not exist, I can write my string value and redirect to AddNew function. Javascript for no data template:
<script id="noDataTemplate" type="text/x-kendo-tmpl">
<div>
Didn't find the element
</div>
<br />
<button class="k-button" onclick="addNew('#: instance.element[0].id #', '#: instance.filterInput.val() #')">Add new value</button>
AddNew function is get widget element and my value. If user will confirm the script will redirect to action from controller sending needed values - productId from Model, value from parameter and attributeDefinitionId value from first dropdown:
function addNew(widgetId, value) {
var widget = $("#" + widgetId).getKendoDropDownList();
var attributeDefinition = $('#AttributeDefinition').data('kendoDropDownList').value();
var dataSource = widget.dataSource;
if (confirm("Are you sure?")) {
$.ajax({
url: '#Url.Action("AddAttributeValue", "Product")' + '?productId=#Model.Id' + '&value=' + value + '&attributeDefinition=' + attributeDefinition,
cache: false,
}).done(function () {
var grid = $("#attributesGrid").data("kendoGrid");
grid.dataSource.read();
});
dataSource.one("sync", function () {
widget.select(dataSource.view().length - 1);
});
dataSource.sync();
}
};
In controller I'm getting these values and insert them to database:
public ActionResult AddAttributeValue(int productId, string value, int attributeDefinition)
{
if (value != null)
{
try
{
var model = attributeValueRepository.Insert(new ProductAttributeValue()
{
IsCustom = true,
StringValue = value,
AttributeDefinitionId = attributeDefinition,
});
productAttributeRepository.Insert(new ProductAttribute()
{
AttributeValueId = model.Id,
ProductId = productId
});
} catch
{
AddErrorFlashMessage(T("Product.Attribute.AttributeValueError"));
return BadRequest();
}
}
return Ok();
}
Edit
Almost forgot, I set also on dropDown noDataTemplate:
$('#AttributeValue_Id').kendoDropDownList({
dataSource: dataSource,
dataTextField: "Text",
dataValueField: "Value",
optionLabel: '#Html.Raw(T("Product.Attribute.SelectValue"))',
filter: "startswith",
noDataTemplate: $("#noDataTemplate").html(),
dataBound: function () {
$('#AttributeValue_Id').data('kendoDropDownList').select(0);
}
});
Thanks everybody for the tips

Might be late for an answer but kendo dropdownlist supports contains filter for exactly this workflow.
<%= Html.Kendo().DropDownList()
.Name("DropDownList")
.Filter(FilterType.Contains);
%>
Ref: Kendo UI Dropdownlist API

Kendo already have feature within Dropdownlist in case user unable to find his choice option. He can add new element manually in dropdownlist. Please find link below
https://demos.telerik.com/kendo-ui/dropdownlist/addnewitem

Related

Dynamically populate a form field based on a previous user entry

I have an application that is using Flask and wtforms and part of the functionality is to take user input for the first two fields and populate the remainder of the form fields which are of type SelectMultipleField (I'm going to refer to these as select fields) with choices from a database based on the first two fields (I'm going to refer to these as entry fields).
My issue right now is getting the select fields to dynamically populate. I found a solution here and this seems to be exactly what I need. It instantiates the select fields to all possible choices and then when it detects a JQuery "onchange" event in the entry fields, filters the select fields to choices based on the user entry for the entry fields. An example would be a user entering a specific company into the form and the select fields populating with "locations" only for that company.
However, in adapting this solution to my problem, I have not been able to get the code to run and I have researched far and wide and unable to resolve this. I'm new to both JQuery and Stack Overflow so any help would be greatly appreciated. Below is my code. Note that I am only focusing on one of the entry fields and dynamically populating just one of the select fields until I get this to work. Test_table is the entry field and test_join_key is the select field.
Here's the form with relevant fields-
class QaForm(FlaskForm):
test_table_in = StringField('Test Table', validators=[DataRequired()], id= 'test_table')
test_join_key = SelectMultipleField("Select Test Fields to Join on", choices=[], coerce=str, id = 'select_test_join_key')
Flask view to instantiate all the select fields -
#app.route('/', methods = ['GET', 'POST'])
#app.route('/home', methods = ['GET', 'POST'])
def home():
form = QaForm()
fields_query = f"""select column_name AS Fields from information_schema.columns group by 1;"""
conn.execute(fields_query)
result = conn.fetchall()
select_choices = [(column, column) for column in result]
form.test_join_key.choices = select_choices
Flask view to get choices for select fields based on user input for entry field -
#app.route('/_get_fields/<table>')
def _get_fields(table):
table = request.args.get(table, type=str)
fields_query = f"""select column_name AS Fields from information_schema.columns WHERE table_name = '{table}' group by 1;"""
conn.execute(fields_query)
result = conn.fetchall()
select_choices = [(column, column) for column in result]
return jsonify(select_choices)
JQuery to detect input in entry field and filter choices for select field (injected in HTML file)-
<script charset="utf-8" type="text/javascript">
$function() {
var dropdown = {
test_table: $('#test_table')
test_join_key: $('#select_test_join_key')
}
updateFields();
function updateFields() {
var send = {
test_table: dropdown.test_table.val()
};
dropdown.test_join_key.attr('disabled', 'disabled');
dropdown.test_join_key.empty();
$.getJSON("{{url_for('_get_fields') }}", send, function(data) {
data.forEach(function(item) {
dropdown.test_join_key.append(
$('<option>', {
value: item[0],
text: item[1]
})
);
});
dropdown.test_join_key.removeAttr('disabled');
});
}
dropdown.test_table.on('change', function() {
updateFields();
});
});
</script>
EDIT: Using #Ibsn suggestions, I was able to get the JQuery snippet to run for one form field. However, updating it to perform the same actions for multiple fields using parameters for the function again results in the code not running. I've checked to make sure my syntax is correct based on the tutorial on W3 schools as well as other Stack Overflow questions but still unable to get it to run. Here's the updated Jquery to detect input in entry fields and filter choices for select fields -
<script charset="utf-8" type="text/javascript">
$(function() {
var tables = {
test_table: $('#test_table'),
prod_table: $('#prod_table')
};
var fields = {
test_join_key: $('#select_test_join_key'),
prod_join_key: $('#select_prod_join_key'),
test_dimensions: $('#select_test_dimensions'),
prod_dimensions: $('#select_prod_dimensions'),
test_measures: $('#select_test_measures'),
prod_measures: $('#select_prod_measures')
};
updateFields(table, field);
function updateFields(table, field) {
var send = {
table: tables.table.val()
};
fields.field.attr('disabled', 'disabled');
fields.field.empty();
$.getJSON("{{url_for('_get_fields') }}", send, function(data) {
data.forEach(function(item) {
fields.field.append(
$('<option>', {
value: item[1],
text: item[0]
})
);
});
fields.field.removeAttr('disabled');
});
}
tables.test_table.on('change', function() {
updateFields(tables.test_table, fields.test_join_key);
updateFields(tables.test_table, fields.test_dimensions);
updateFields(tables.test_table, fields.test_measures);
});
tables.prod_table.on('change', function() {
updateFields(tables.prod_table, fields.prod_join_key);
updateFields(tables.prod_table, fields.prod_dimensions);
updateFields(tables.prod_table, fields.prod_measures);
});
});
There are a couple of syntax errors in your code.
$function() {} should be $(function(){}). And you're missing the comma between properties on var dropdown = {}
This is the updated version:
<script charset="utf-8" type="text/javascript">
$(function(){
var dropdown = {
test_table: $('#test_table'),
test_join_key: $('#select_test_join_key')
}
updateFields();
function updateFields() {
var send = {
test_table: dropdown.test_table.val()
};
dropdown.test_join_key.attr('disabled', 'disabled');
dropdown.test_join_key.empty();
$.getJSON("{{url_for('_get_fields') }}", send, function(data) {
data.forEach(function(item) {
dropdown.test_join_key.append(
$('<option>', {
value: item[0],
text: item[1]
})
);
});
dropdown.test_join_key.removeAttr('disabled');
});
}
dropdown.test_table.on('change', function() {
updateFields();
});
});
The OP updated the question with new requirements
If I understand correctly, you're trying to update all the test_ fields when test_table changes and all the prod_ fields when prod_table changes.
So this code should do that:
$(function () {
var tables = {
test_table: $('#test_table'),
prod_table: $('#prod_table')
};
// I'm organizing fields in two arrays, test and prod, for simplyfing iterate over each group
var fields = {
test: [$('#select_test_join_key'), $('#select_test_dimensions'), $('#select_test_measures')],
prod: [$('#select_prod_join_key'), $('#select_prod_dimensions'), $('#select_prod_measures')]
};
// This is for updating fields the first time
fields.test.forEach(item => updateFields(tables.test_table, item));
fields.prod.forEach(item => updateFields(tables.prod_table, item));
function updateFields(table, field) {
var send = {
table: table.val()
};
field.attr('disabled', 'disabled');
field.empty();
$.getJSON("{{url_for('_get_fields') }}", send, function (data) {
data.forEach(function (item) {
field.append(
$('<option>', {
value: item[0],
text: item[1]
})
);
});
field.removeAttr('disabled');
});
}
// Test fields and prod fields are two arrays now, so I can simply iterate through them
tables.test_table.on('change', function () {
fields.test.forEach(item => updateFields(tables.test_table, item));
});
tables.prod_table.on('change', function () {
fields.prod.forEach(item => updateFields(tables.prod_table, item));
});
});

How to marked checkbox in function jquery

I have a listbox in view.
This Listbox use template
Listbox
<div id="UsersLoad" style="width: 50%">
#Html.EditorFor(i => i.Users, "UsersForEdit")
</div>
Template UserForEdit (Part of the code)
#model string[]
#{
if (this.Model != null && this.Model.Length > 0)
{
foreach(var item in this.Model)
{
listValues.Add(new SelectListItem { Selected = true, Value = item, Text = item });
}
}
else
{
listValues = new List<SelectListItem>();
}
}
<div class="field-#size #css">
<h3>#Html.LabelFor(model => model):</h3>
#Html.ListBoxFor(model => model, listValues, new { id = id })
</div>
In another view div "Users" is called.
function LoadUsersCheckBox() {
$("#UsersLoad").load('#Url.Action("LoadUsers", "User")' + '?idUser=' + idUser);
}
LoadUsers Controller
public JsonResult LoadUsers(int? idUser)
{
var users = Service.GetSystemUsers(idUser);
var model = users.Select(x => new
{
Value = x,
Description = x
});
return this.Json(model, JsonRequestBehavior.AllowGet);
}
The controller method returns what I want.
But instead of it select the items in the listbox it overwrites the listbox with only the text of found users.
How to mark the items in the listbox on the function LoadUsersCheckBox?
Sorry for my bad English
The jQuery load() method "loads data from the server and places the returned HTML into the matched element." Note the words "the returned HTML". See http://api.jquery.com/load/
To select existing items, you should try get() instead (http://api.jquery.com/jQuery.get/). In the success callback handler, you will need to parse the returned data to an array. Then use an iterator to go over the items in the listbox, and if they exist in the parsed array, mark them as selected. Something like:
$.get("action url", function(data) {
var users = $.parseJSON(data);
$("#UsersLoad option").each(function() {
var opt = $(this),
value = opt.attr("value");
opt.removeAttr("selected");
if (users.indexOf(value) > -1) {
opt.attr("selected", "selected");
}
});
});

How to set search results to pre-selected in select2?

Alright, so I'm trying to use select2's tagging and AJAX functionality in conjunction for my categories selection.
Currently, the user can search for categories to add to their post. One nice thing I noticed is that, select2 won't let you select the same selection twice (it's grayed and nothing happens when you click on it).
Here's my challenge... let's say a user is editing a post and already has categories selected. These categories appear below the select2 search. For example, let's say the user has the category "Life" selected. This will appear below already checked off.
The problem arises though, when the user searches for "Life". They'll be able to select it and add it again. I could just parse the previous selections and negate the selection, but I'd really like to use the built in functionality of select2 for the sake of consistency.
So how do I set incoming AJAX results to be already selected so that they can't be selected again?
Here's a fiddle. Notice how "Experiences" is grayed out when you search for it, but "life" is not even though it's already selected.
http://jsfiddle.net/odLnznct/1/
function formatStuff(stuff) {
if (stuff.loading) return 'Searching...';
markup = "<p>" + stuff.text + "</p>";
return markup;
}
function formatRepoSelection(stuff) {
return stuff.cat_name || $('.js-select').val();
}
function catAdd() {
var addCat = div = clo = label = labelText = null;
cat = $('.js-select').select2('data');
addCat = cat[0].text;
div = $('#categories-cat_name div.checkbox:first');
clo = div.clone();
$('input[type="checkbox"]', clo).val(addCat);
label = $('label', clo);
labelText = label[0].childNodes[label[0].childNodes.length - 1];
labelText.textContent = addCat;
$(div).before(clo);
}
$('.js-select').select2({
tags: true,
ajax: {
url: 'https://api.myjson.com/bins/58uwe',
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term
};
},
processResults: function (data, page) {
var select2Data = $.map(data, function (obj) {
obj.id = obj.cat_id;
obj.text = obj.cat_name;
return obj;
});
return {
results: select2Data
};
},
cache: true
},
escapeMarkup: function (markup) {
return markup;
},
minimumInputLength: 1,
templateResult: formatStuff,
templateSelection: formatRepoSelection
});
$('.js-select').on('select2:select', function () {
catAdd();
});
You can try this.
Since your results could be multiple, you need to set your select element's multiple true to enable it and just add selected option as default value.
You can do it either javascript or html.
<div id='select-test'>
<select class="js-select" style="width:90%;" multiple=true>
<option value="Life" selected=true>Life</option>
<option value="Joy" selected=true>Joy</option>
</select>
</div>

Bootstrap Multiselect update option list on flow

I use bootstrap multi-select and I want to update options on flow with ajax
To populate on init my multiselect I do
<select name="model" class="multiselect" multiple="multiple">
<? foreach ($sel_models as $mod) { ?>
<option value="<?= $mod ?>" <?= ($mod == $params['model']) ? 'selected' : '' ?>><?= $mod ?></option>
<? } ?>
</select>
then on event I would like to update my option list with the following ajax
I was trying to use the rebuild method but won't fire the drop-down after creation
$.ajax({
type: 'post',
url: "helper/ajax_search.php",
data: {models: decodeURIComponent(brands)},
dataType: 'json',
success: function(data) {
$('select.multiselect').empty();
$('select.multiselect').append(
$('<option></option>')
.text('alle')
.val('alle')
);
$.each(data, function(index, html) {
$('select.multiselect').append(
$('<option></option>')
.text(html.name)
.val(html.name)
);
});
$('.multiselect').multiselect('rebuild')
},
error: function(error) {
console.log("Error:");
console.log(error);
}
});
With firebug I can see that the list is generated but on select won't show up
In the doc I can read :
.multiselect('setOptions', options)
Used to change configuration after initializing the multiselect. This may be useful in combination with .multiselect('rebuild').
Maybe you can't change your widget data by your initial way. In a correct way you should use setOptions method.
Else : With your way, maybe should you think about destroy your widget .multiselect('destroy') and create it again after.
Update after comment :
In the doc : ( you've linked )
Provides data for building the select's options the following way:
var data = [
{label: "ACNP", value: "ACNP"},
{label: "test", value: "test"}
];
$("#multiselect").multiselect('dataprovider', data);
So :
When you get data from your ajax call, you have to create an array of objects ( it's the options in the select you want to have ) with the format like
var data =
[
{label: 'option1Label', value: 'option1Value'},
{label: 'option2Label', value: 'option2Value'},
...
]
When your objects array is created, then you just have to call the method
$("#multiselect").multiselect('dataprovider', data);
Where data is your array of objects.
I hope I'm clear :/
As an alternative to multiselect('dataprovider', data) you can build the list with jquery append exactly the way you did in your question. The only change you need to make is to delay the rebuild until after the ajax request is complete.
var buildDrivers = $.getJSON('resources/orders/drivers.json', function(data) {
$.each(data, function(i, driver) {
$('#toolbar select[name="drivers"]').append('<option>'+driver+'</option>');
});
});
buildDrivers.complete(function() {
$('.multiselect').multiselect('rebuild');
});
see http://api.jquery.com/jquery.getjson/ for documentation
I've been added the functionality of updating options after filtering and getting them from the server side. This solution relays on the concept of injecting new options, destroying the select and initializing it again.
I took into account:
Considering the existing selected options, which must stay.
Removing duplicate options (might be as a conflict from which that already selected and the new that came from the server).
Keeping the options tray open after the update.
Reassign the previous text in the search text box & focusing it.
Just add the 'updateOptions' as a function after the 'refresh' function along with the two helper functions as follows:
updateOptions: function (options) {
var select = this.$select;
options += this.getSelectedOptionsString();
var selectedIds = select.val(),
btnGroup = select.next('.btn-group'),
searchInput = btnGroup.find('.multiselect-search'),
inputVal = searchInput.val();
options = this.removeOptionsDuplications(options);
if (!options) {
options = '<option disabled></option>';
}
// 1) Replacing the options with new & already selected options
select.html(options);
// 2) Destroyng the select
select.multiselect('destroy');
// 3) Reselecting the previously selected values
if (selectedIds) {
select.val(selectedIds);
}
// 4) Initialize the select again after destroying it
select.multiselect(this.options);
btnGroup = select.next('.btn-group');
searchInput = btnGroup.find('.multiselect-search');
// 5) Keep the tray options open
btnGroup.addClass('open');
// 6) Setting the search input again & focusing it
searchInput.val(inputVal);
searchInput.focus();
},
getSelectedOptionsString: function () { // Helper
var result = '',
select = this.$select,
options = select.find('option:selected');
if (options && options.length) {
$.each(options, function (index, value) {
if (value) {
result += value.outerHTML;
}
});
}
return result;
},
removeOptionsDuplications: function (options) { // Helper
var result = '',
ids = new Object();
if (options && options.length) {
options = $(options);
$.each(options, function (index, value) {
var option = $(value),
optionId = option.attr('value');
if (optionId) {
if (!ids[optionId]) {
result += option[0].outerHTML;
ids[optionId] = true;
}
}
});
}
return result;
},
Demo:
State:
"Option 1"
$('#select').multiselect('updateOptions', '<option value="2">Option 2</option>');
State:
"Option 2"
"Option 1"
I think this is an easier way to add options on the fly (using ajax or any other listener) to an existing Bootstrap MultiSelect.
Following is a simplified example to add options:
function addOptionToMultiSelect(multiselectSelector, value, selected) {
var data = [];
$(multiselectSelector + ' option').each(function(){
var value = $(this)[0].value;
var selected = $(this)[0].selected;
data.push({label: value, value: value, selected: selected});
});
// Add the new item
data.push({label: value, value: value, selected: selected});
$(multiselectSelector).multiselect('dataprovider', data);
}
For simplicity, I have assumed both the label and value are the same in an option. Note that the already selected options are taken care of by reading the selected attribute from the existing options. You can make it more sophisticated by tracking the disabled and other attributes.
Sample:
addOptionToMultiSelect('#multiselect-example', 'new-option', true);

MVC UIHint/Parital view with JQuery multiselect, dynamic creation issue

I've been using this tutorial to create a screen where a user can add additional input fields on a given screen
Instead of using all textboxes Iv'e created a UIHint/Partial view that'll render a multi-select JQuery widget (I'm using this component)
ViewModel for each row item
public class Micros
{
[UIHint("JsonComboBox")]
[AdditionalMetadata("id", "Lab_T_ID")]
[AdditionalMetadata("description", "Description")]
[AdditionalMetadata("action", "LabTestOptions")]
[AdditionalMetadata("controller", "Micro")]
[AdditionalMetadata("noneSelectedText", "Test")]
[AdditionalMetadata("comboboxWidth", "200")]
[DisplayName("Test")]
public Nullable<int> Lab_T_ID { get; set; }
[UIHint("JsonComboBox")]
[AdditionalMetadata("id", "Lab_SD_ID")]
[AdditionalMetadata("description", "Description")]
[AdditionalMetadata("action", "LabSampleDetailOptions")]
[AdditionalMetadata("controller", "Micro")]
[AdditionalMetadata("noneSelectedText", "Sample Details")]
[AdditionalMetadata("comboboxWidth", "300")]
[DisplayName("Sample Details")]
public Nullable<int> Lab_SD_ID { get; set; }
[DisplayName("Result")]
public string Result { get; set; }
}
Partial View/UIHint
#model int?
#{
var values = ViewData.ModelMetadata.AdditionalValues;
}
<select id="#values["id"]" multiple="multiple" style="width:#values["comboboxWidth"]px" > </select>
<script type="text/javascript">
$.getJSON('#Url.Action((string)values["action"], (string)values["controller"])',
null,
function (j) {
var options = '';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].#values["id"] + '">' + j[i].#values["description"] + '</option>';
}
$('##values["id"]').html(options);
$('##values["id"] option:first').attr('selected', 'selected');
});
setTimeout(function () {
$("##values["id"]").multiselect({
multiple: false,
header: "Select an option",
noneSelectedText: '#values["noneSelectedText"]',
selectedList: 1
});
}, 300);
</script>
The components render fine on the initial page load, but when add the items, they get added... but it seems that the javascript doesn't execute/get added..
Any ideas? Still debugging this issue, will post the fix as soon as I find it, but I'm hoping someone can point me in the right direction
Update
So far I've discovered that (We'll it looks like), the UIHint/Partials don't get rendered at all when the user clicks to add another item. (Otherwise the select will be populated with items, and the JQuery widget will be applied)
I would recommend you to remove all javascript from your partial. Javascript shouldn't be mixed with markup. So your editor template should contain only markup:
#model int?
#{
var values = ViewData.ModelMetadata.AdditionalValues;
}
<span>
<select multiple="multiple" style="width:#values["comboboxWidth"]px" data-url="#Url.Action((string)values["action"], (string)values["controller"])" data-noneselectedtext="#values["noneSelectedText"]" data-value="#values["id"]" data-text="#values["description"]"></select>
</span>
and then in a separate javascript file you will have a function which will be used when the Add another... button is clicked as shown in Steven Sanderson's article:
$('#addItem').click(function() {
$.ajax({
url: this.href,
cache: false,
success: function(html) {
// Here's the place to attach any plugins to the given row:
var select = $('select', html);
$.getJSON(select.data('url'), function(options) {
$.each(options, function() {
select.append(
$('<option/>', {
value: this[select.data('value')],
text: this[select.data('text')]
})
);
});
select.multiselect({
multiple: false,
header: 'Select an option',
noneSelectedText: select.data('noneselectedtext'),
selectedList: 1
});
$('#editorRows').append(select);
});
}
});
return false;
});

Categories