Behat select2 ajax closes the search box - ajax

I want to test with Behat a select2 dropbox that makes an ajax call in order to get the results.
The problem is that immediately after I populate the search box of select2 the dropdown closes immediately so the search is not happening.
If the select is already populated (a normal dropdown with predefined values) everything is ok because all the data is there and it takes it right away.
I'm using Behat Page object for my project so here is my method:
select2FieldPopulate
public function select2FieldPopulate($field, $value)
{
$select2Field = $this->find('css', '.'.$field);
//check if select2Field exists
if (!$select2Field) {
throw new \Exception(sprintf("Field %s was not found", $field));
}
$select2Field->click();
$select2Input = $this->find('css', '.select2-drop.select2-drop-active .select2-search input.select2-input');
if (!$select2Input) {
throw new \Exception(sprintf("Field %s was not found", "select2-input"));
}
$select2Input->setValue($value);
}
js
function buildSelect2Element(selector, placeholder, url) {
var element = $(selector).select2({
placeholder: placeholder,
minimumInputLength: 3,
ajax: {
url: url,
dataType: 'json',
data: function (term) {
return {
q: term
}
},
results: function (data) {
//workarround to fix select2
var results = [];
$.each(data, function (index, item) {
results.push({
id: item.id,
text: item.name
});
});
return {
results
}
}
}
});
return element;
}
On $select2Input->setValue() the search box gets populated with the value but the search does not happen because the dropdown closes right away.
So the question is: Is there a way to force the box to stay open until the results are displayed (the ajax call is finished)?

I managed to make it work under select2 v4.x.
I added to the js the option to select on close like this:
js
function buildSelect2Element(selector, placeholder, url) {
var element = $(selector).select2({
theme: "classic",
placeholder: placeholder,
minimumInputLength: 3,
selectOnClose: true, //HERE
Then in my tests i used the evaluateScript method:
select2FieldPopulate method
$this->getDriver()->evaluateScript("$('#your_select2_element').select2('open')");
$this->getDriver()->evaluateScript("$('.select2-search__field').val('". $value ."').keyup();");
$this->getDriver()->evaluateScript("$('#your_select2_element').select2('close')");

Related

jquery autocomplete is now working properly

I am working on jquery autocomplete in mvc platform. Now, my question is that in some textbox data autocomplete is working properly while in some textbox data autocomplete is not working properly.
For more clear, lets see the image of autocomplete task
now as per the image when I write the R word, I am getting the suggestion list of related R word.
now as per the second image I have written the whole word but still suggestion is not display.
Here is my code,
View
<input type="text" id="CustomerName" name="CustomerName" required data-provide="typeahead" class="typeahead search-query form-control autocomplete"
placeholder="Customer Name" />
<script>
$(document).ready(function () {
$.ajax({
url: "/ServiceJob/CustomerSerchAutoComplete",
method: "GET",
dataType: "json",
minLength: 2,
multiple: true,
success: function (data) {
/*initiate the autocomplete function on the "myInput" element, and pass along the countries array as possible autocomplete values:*/
//autocomplete(document.getElementById("CustomerName"), data.data);
$('#CustomerName').autocomplete({ source: data.data, minLength: 2, multiple: true });
}
});
});
</script>
Controller
[HttpGet]
public IActionResult CustomerSerchAutoComplete()
{
var customers = _Db.Ledger.Where(x => x.LedgerTypeId == (int)LedgerType.Customer).ToList();
var result = (from n in customers
select new
{
kk = n.Name.ToUpper()
}).ToList();
return Json(new { data = result });
}
As you are getting
Uncaught TypeError: Cannot read property 'substr' of undefined
For this error you should check that data is not null.
success: function (data) {
if(data != null)
{
autocomplete(document.getElementById("CustomerName"), data.data);
}
}

Select2 4.0.0 can't select results

I'm trying to use the newest version of Select2 to query my site's API and return a multiple-select. It's fetching the right data and it's even formatting the dropdown properly, combining two keys in the returned objects as "(A-123) John Johnson", but the dropdown's not responding to mouseover or clicks.
I'm using the select2.full.min.js and select2.min.css files. For the purposes of the project, I'm including them in the directory and accessing them through Bundles in cshtml, instead of accessing them via a CDN.
HTML:
<div>
<select class="user-list" multiple="multiple" style="width: 100%">
</select>
</div>
At the moment, it's looking like this, which is how I want it:
Not sure if this is relevant, but when I browse the generated source code while searching, the input looks fine, but the dropdown's code is greyed out as though it were hidden.
Per other suggestions I've found on here and elsewhere, I've tried a few different solutions. I eventually found out how templateResult and templateSelection are supposed to work (not particularly thanks to the documentation), and tried returning the ID as well, but I still can't seem to actually select anything, or even get a response when I hover over the options.
Here's what I wound up with, including some debugging to make sure the returned object is valid.
JS:
// Setup autocomplete/select for User filter
$(".user-list").select2({
ajax: {
url: "[api url]",
type: "GET",
dataType: "json",
data: function (params) {
return {
search: params.term, // search term
page: params.page
};
},
processResults: function (data) {
console.log(JSON.stringify(data));
return {
results: data
};
},
},
escapeMarkup: function (markup) { return markup; },
id: function (data) { return data.Id.toString(); },
minimumInputLength: 1,
templateResult: function (data, page) {
return "(" + data.User + ") " + data.Name;
},
templateSelection: function (data, page) {
return "(" + data.User + ") " + data.Name;
}
})
The ID is a GUID, and there are two other fields, which I'll call Name and User.
Data Sample:
[
{
"Id":"a1a1a1a1-a1a1-a1a1-a1a1-a1a1a1a1a1a1",
"Name":"John Johnson",
"User":"A-123"
},
{
"Id":"b2b2b2b2-b2b2-b2b2-b2b2-b2b2b2b2b2b2",
"Name":"Tom Thompson",
"User":"B-456"
}
]
I hate to add to the pile of questions that seem to be about this, but most results I've found have been for the older version with significantly different options, and they just haven't worked for me yet.
The way select2 operates is that it uses the "id" values of each data object and puts those into the original Select element as the selected option(s). This is case-sensitive.
By default, it displays the dropdown options and the selected element by whatever the "text" value is of the data object. This does not allow for custom formatting.
If (like me) you want to return different data options, you still need to return a field as "id", or re-map a field to "id" in an object returned in the processResults option under ajax. Then use the templateResult and templateSelection settings with your other returned data to display what you want.
If you return and parse everything correctly except for the id, you may wind up with an otherwise functional list, but be unable to select any options.
The requirements for the dropdown changed a bit with my project, but here's where I wound up. It works fine the multiple="multiple" attribute added to to make it a multi-select, too.
<select class="select2" style="width:100%; height: 100%;">
<option></option>
</select>
$(".select2").select2({
ajax: {
url: "[api url]",
method: "get",
data: function (params) {
return {
search: params.term
};
},
processResults: function (data) {
return {
results: data
};
},
cache: true
},
placeholder: "Enter a User ID or Name",
templateResult: function(data) {
return "(" + data.user + ") " + data.name;
},
templateSelection: function(data) {
return "(" + data.user + ") " + data.name;
}
}).ready(function () {
$(".select2-selection__placeholder").text("Enter a User ID or Name")
})
It's possible part of my initial issue was all the attempts at implementing fixes for older versions of Select2, which had a completely different set of options/settings available.
Additionally, a bit of a side-note, the "placeholder" attribute doesn't currently work with custom templating. It tries to force the placeholder text into the Result format, which shows "(undefined) undefined" with this code. To fix it requires an empty option and to replace the text on select2.ready.
I had the same problem. Solution:
added this part :
_.each(data.ResultObject, function (item) { item.id = item.K_CONTACT; });
(used underscore)
for my init
$(".js-data-example-ajax").select2({
ajax: {
url: "api/MyApi/MyApi",
method: "POST",
dataType: 'json',
delay: 250,
data: function (params) {
return {
SearchPart: params.term, // search term
page: params.page
};
},
processResults: function (data, params) {
params.page = params.page || 1;
_.each(data.ResultObject, function (item) { item.id = item.K_CONTACT; });
return {
results: data.ResultObject,
pagination: {
more: (params.page * 30) < data.total_count
}
};
},
cache: true
},
multiple: true,
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
minimumInputLength: 3,
tags: true,
templateResult: self.Select2FormatData, // omitted for brevity, see the source of this page
templateSelection: self.Select2FormatDataSelection // omitted for brevity, see the source of this page
});

Multiple Ajax PUTs in Laravel 4 Giving Errors

I am updating my Model through a resource controller via jQuery Ajax Put. No problems at all the first time. This works fine:
$(".addNest").click(function() {
var nid = msg; //once the LI is added, we grab the return value which is the nest ID
var name = $('.nestIn').val();
if(name == '') {
$("textarea").css("border", "1px solid red");
}else {
$.ajax({
type: 'PUT', // we update the default value
url: 'nests/' + nid,
data: {
'name': name
},
success: function(msg) {
alert(msg)
window.location.replace('nests/' + nid ); //redirect to the show view
}
});
}
});
Later in a separate code block, I try to call the PUT again like this:
$(".nestEdit").click(function() {
$(".nestEdit").hide();
var name = $('.nestName').data("name");
var nid = $('.nestName').data("id");
$(".nestName").html("<textarea class='updateNest'>"+ name +"</textarea> <span><a href='#' class='btn btn-mini nestUpdate'><i class='icon-plus'></i> Update</a></span>");
$(".nestUpdate").click(function() {
var updatedName = $('.updateNest').val();
$.ajax({
type: 'PUT', // we update the default value
url: 'nests/' + nid,
data: {
'name': updatedName
},
success: function(msg) {
alert(msg) // showing the error here
location.reload( ); //refresh the show view
}
});
});
The 'updatedName' values and the 'nid' values are passing fine when I 'alert' them. When I view the return for the first PUT it comes back fine. However, when I view the return for the second PUT I get this:
{"error":{"type":"Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException","message":"","file":"\/Applications\/MAMP\/htdocs\/n4\/bootstrap\/compiled.php","line":8643}}
Anyone have some insights here? As you can tell, I am trying to do an inline edit. I have tried to wrap everything into a function but still not helping...
Laravel does not use PUT and DELETE natively since it is not supported in all browsers, you need to send a POST request with '_method' set to either put or delete.
$.ajax({
type: 'POST',
url: 'nests/' + nid,
data: {
'name': updatedName,
'_method': update
},
success: function(msg) {
alert(msg) // showing the error here
location.reload( ); //refresh the show view
}
EDIT: Ajax request do support PUT AND DELETE.
In your JavaScript code, for the inline editing, you are not making proper use of $.
If you click on .nestEdit, it's inner function should not be calling it by name, provided you have multiple objects of the same class on that page. This is why you get the error. Instead of sending the nest ID, it's sending an array object, which your Laravel Router will not pick up, because it is more than likely not defined.
Simply put, you should not be doing this:
$(".nestEdit").click(function() {
$(".nestEdit").hide();
...
You should be making a call to this:
$(".nestEdit").click(function() {
$(this).hide();
...
So, for every .nestEdit within the inner function, you need to call for this instead.

jQuery autocomplete not displaying data returned from Ajax call

Below an Ajax call wrapped inside a jQuery autocomplete source function. checking the return value in Fiddler and also in Chrome's Network console, I can see that the data is being returned to the view and in the correct format.
However, the normal list of items that occur when the user starts typing do not appear. You can type as fast/slow for as little/long as you want and nothing will appear.
I've set a breakpoint in the controller method (this is an ASP MVC site) just to make sure that part of the program was functioning properly, and it fires every time.
I'm only a few weeks new to jQuery so any help would be greatly appreciated. Thanks!
$(function () {
$('#DRMCompanyId').autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("compSearch", "AgentTransmission")',
type: 'GET',
dataType: 'json',
data: request,
success: function (data) {
alert(data);
response($.map(function (value, key) {
alert(value);
return {
label: value,
value: key
};
}));
}
});
},
minLength: 1
});
});
EDIT
I added a couple alerts to the code. The alert(data) will fire but the alert(value) will not.
Here is a copy of the returned json from the Chrome's debugging console
And here is the controller method that returns the key/value pair in the form of a Dictionary object.
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
nsmgr.AddNamespace("d", "http://schemas.microsoft.com/ado/2007/08/dataservices");
Dictionary<string, string> companies = new Dictionary<string, string>();
foreach (XmlNode childNode in parentNode)
{
if (!String.IsNullOrWhiteSpace(childNode["content"].InnerText))
{
try
{
string name = childNode["title"].InnerText;
string id = childNode["content"].InnerText.Substring(0, 6);
companies.Add(id, name);
}
catch (Exception ex)
{
}
}
}
return Json(companies, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
results = ex.InnerException.ToString();
}
return Json(results, JsonRequestBehavior.AllowGet);
The $.map function expects an array/object to enumerate on, as first argument. ref jQuery.map.
try changing
$.map(function (value, key) {
to
$.map(data, function (value, key) {
Regards.
The jQuery documentation: http://api.jquery.com/jQuery.map/ says that the $.map function expects two parameters; the first being an array. I think that you need to use the $.each method instead.
I also believe that in this context, response is a callback function that you are supposed to invoke with the data from AJAX as the parameter, as in response(data).
Shooting from the hip here, I think that your success handler should look about like this:
success: function (data) {
var x, array = [];
for(x in data) {
array.push({
label: data[x].value,
value: data[x].key
};
}
response(data);
}

Auto complete (Jquery) focus doesn't bind Spring Propety

I am working on Auto complete (jquery) using Spring MVC. I have done everything, data is displaying properly in auto complete but properties doesn't display onfocus event. Whenever i call "ui.item.username" in onfocus method, it always display me null value.
$( "#city" ).autocomplete({
minLength: 0,
source: function( request, response ) {
$.ajax({
url: "person.ajax",
dataType: "json",
data: {
maxRows: 6,
startsWith: request.term
},
success: function( data ) {
response( $.map( data.zipcodes, function( item) {
return {
label: item.realName + item.realName,
value: item.username
}
}));
}
});
},
it works fine till here but when i call property in onfocus methods (in following method), it displays me null
in focus event (jquery)
focus: function(event, ui) {
alert($( event.target ).val(ui.item.ealName)); // it displays me null value at this point
},
select: function( event, ui ) {
}
Any Suggestion?
The result object you're building in the success function of your AJAX request is used across all methods/event handlers of the autocomplete widget. If you want to access a property later, you'll have to include that property when you're building the data source you're passing to the response function:
success: function( data ) {
response( $.map( data.zipcodes, function( item) {
return {
label: item.realName + item.realName,
value: item.username,
realName: item.realName // include realName
}
}));
}
(From the comments):
Also the alert function does return null, so if you'd like to alert just the value, use:
alert(ui.item.realName)
instead.
I have implemented auto complete drop down using spring mvc. Now my question is when any user select/choose any value from auto complete drop down, then How can i sure that the selected value is correct or not? in other words i want to ensure that whether user selected the correct value from auto complete or not. Because user can type random string in input text box and submit it(Technically, i also make sure when user select any value from drop down, then submit will be visible to the user, and if user type incorrect data, the button shouldn't be activate).
Here is a code
<script>
$(function() {
$( "input[name='creditCheck']" ).autocomplete({
minLength: 2,
source:function( request, response ) {
$.ajax({
url: "creditCheck.ajax",
dataType: "json",
data: {
maxRows: 6,
startsWith: request.term
},
success: function( data ) {
response( $.map( data.creditCheckData, function( item) {
return {
creditName: item.creditName,
}
}));
}
});
},
The above code words fine, it get the list from server and displays the auto complete data.In following code i am just toggling the button.But i also make sure when user select any value from drop down, then submit will be visible to the user, and if user type incorrect data, the button shouldn't be activate.
$('input[name="creditCheck"]').bind("change keyup", function () {
if ($(this).val()!="") {
$(this).nextAll("button[name='add']:first").removeAttr('disabled');
} else {
$(this).nextAll("button[name='add']:first").attr('disabled', 'disabled');
}
});

Resources