Select2 4.0 clicking item doesn't fire select2:select - javascript

I'm using select2 4.0 and when I load data from a json file none of the created elements fire the select2:select event. I thought it would have something to do with event delegation, but the examples on the website seem to do just fine.
I've been breaking my head over this for the past hour and I just don't understand what I'm missing.
Right now I'm using this to select an item, but that obviously doesn't work:
$("body").on("click", "#select2-select-results .person-entry", function()
{
var $this = $(this);
var name = $this.data('name');
select2.find('option').val(name).text(name);
});
Binding $(...).on('select2:select'); never fires, but $(...).on('select2:open); does. So I'm not sure what's going on.
What I did notice however, is when the data has been loaded, no <option> tags are created.
This is my entire JavaScript that's handling the thing:
(function($)
{
"use strict";
var term = null;
var select2 = $("#select");
select2.select2({
allowClear: true,
ajax: {
url: "js/data.json",
dataType: "json",
delay: 250,
data: function(params)
{
// Save the terms for filtering
term = params.term;
return params;
},
processResults: function(data)
{
var people = [];
for(var i = 0; i < data.people.length; i++)
{
var person = data.people[i];
var filter = term || '';
if (person.name.toLowerCase().indexOf(filter.toLowerCase()) !== -1) {
people.push(person);
}
}
return {
results: people
};
}
},
templateResult: function(person)
{
if (person.loading) {
return person.text;
}
var personDetails = '<div class="person-information">' +
'<span class="person-name">' + person.name + '</span>' +
'<span class="person-address">' + person.address + '</span>' +
'</div>';
return '<div class="person-entry" data-name="' + person.name + '"><img src="' + person.image + '" />' + personDetails + '</div>';
},
templateSelection: function(person)
{
return person.name;
},
escapeMarkup: function(markup)
{
return markup
}
});
$("body").on("click", "#select2-select-results .person-entry", function()
{
var $this = $(this);
var name = $this.data('name');
select2.find('option').val(name).text(name);
});
})(jQuery);
Can someone tell me what I'm doing wrong here? I just don't get it.

It sounds like you are not setting the id field on your data objects. Without this field, Select2 cannot know what to set the value of your <select> to, so it doesn't allow it to be selected.
Additionally, the text field is required for searching and (by default) displaying the data in the results list.

Related

How to make ajax call works only for inputs in the same row, when using (.clone())

I’ve ajax code to append “unit menu” based on “product item” selection.
When I create a new row, and select an item from “product menu” I expected that the “unit input” of the same row must affect and append the “unit menu” belongs to the selection of the "product item" in the same row.
But I noticed that when a new row created by cloning and I select a product (all the above rows also affect, i.e after product item selection the "unit menu" of the same row and the "unit menu" of the above rows also affected)
The next code illustrate what I mean....
$(document).ready(function() {
var purchase = $('.purchase-row').last().clone();
let purchaseCount = 0;
$(document).on('click', '.add_item', function() {
var clone = purchase.clone().prop('id', 'product_' + purchaseCount);
// var clone = purchase.clone().prop('class', 'product_' + purchaseCount);
console.log('clone: ', clone);
$(this).prevAll('.purchase-row').first().after(clone.hide());
clone.slideDown('fast');
$('#product_'+ purchaseCount).find('#id_pro-product').removeClass('product').addClass('newProduct');
$('#product_'+ purchaseCount).find('#id_pro-unit').removeClass('unit').addClass('newUnit');
purchaseCount++;
console.log('PURCHASE-COUNT: ', purchaseCount);// $(this).parent().slideUp('fast');
// The next code for reinitialize select2
var $example = $(".js-programmatic-init").select2();
$example.select2();
});
$(document).on('click', '.purchase-minus', function() {
if (purchaseCount == 0) {
// Do nothing.
alert('You can not delete this row' );
} else {
$(this).closest('.purchase-row').remove();
purchaseCount--;
console.log('PURCHASE-COUNT2: ', purchaseCount);
}
});
$(document).on('click', '.purchase-broom', function() {
$(this).closest('.purchase-row').find('input').val('');
});
$(document).on('change', '.product', function(e){
var id = $(this).val();
console.log('CHANGED-PRODUCT: ', id);
$.ajax({
type: 'POST',
url: '{% url "purchases:get_product_unit" %}',
// dataType: 'json',
// async: true,
// cache: false,
data: {
'pro-product': $('.purchase-row select').closest('.product').val(), // this is right
// find('#id_pro-product')
},
success: function (data) {
console.log(
'FROM SUCCESS: ', data['unit'],
);
var values_3 = data['unit'];
// $('#id_pro-unit').text('');
// $('select').closest('.unit').find('select').text('');
$('select').closest('.unit').text('');
if (values_3.length > 0) {
for (var i = 0; i < values_3.length; i++) {
// $('#id_pro-unit').append('<option>' + values_3[i] + '</option>');
$('select').closest('.unit').append('<option>' + values_3[i] + '</option>');
}
}
},
error: function (){
console.log('ERROR with ajax request in Adding Purchase !!!');
},
});
e.preventDefault();
});
The next image indicates the main row which I want to clone
Image of the main row
The next image indicates an example for creating 2 rows from the main one.
Image of cloning rows
You can notice a bug in the cloning inputs due to using of (select2 plugin),I raised an issue in Select2 forum(but I havegot no answer till now), So I'll ask a new question here about that behavior..
My view to handle ajax
from django.http import JsonResponse
def get_product_unit(request):
data = {}
product = request.POST.get('pro-product')
if product is not None:
unit = UOM.objects.values('unit__name', 'uom_options', 'unit').filter(product_id=product)
print('purchase not purchase')
else:
unit = []
data['unit'] = [(obj['unit__name']) for obj in unit]
print(
'PRODUCT: ', product,
'UNIT: ', unit,
)
return JsonResponse(data)
My tries to fix this problem
1- In fact I tried to make a new ajax call for the new cloned row, but I realize that it can solve by the above ajax code (I don't know how).
I think if I knew to access the "class and id" of the new row itself
$(document).on('change', '.newProduct', function(e){
var id = $(this).val();
console.log('SUCCESS-CHANGE-PRODUCT-FROM-NEW-CLASS: ', id);
$.ajax({
type: 'POST',
url: '{% url "purchases:get_new_row_unit" %}',
// dataType: 'json',
// async: true,
// cache: false,
data: {
'pro-product': id,
// $('#product_'+purchaseCount).closest('.newProduct select').val(),
// find('#id_pro-product')
},
success: function (data) {
console.log(
'FROM SUCCESS-NEW-CLASS: ', data['unit'],
'PRODUCT-FROM-NEW-CLASS: ', data['product'],
);
var values_3 = data['unit'];
// $('#id_pro-unit').text('');
// $('select').closest('.newUnit').text('');
if (values_3.length > 0) {
for (var i = 0; i < values_3.length; i++) {
// $('#id_pro-unit').append('<option>' + values_3[i] + '</option>');
// $('.newUnit select').closest('#product_'+ purchaseCount).append('<option>' + values_3[i] + '</option>');
// $('select').closest('#product_'+ purchaseCount).find('.newUnit').append('<option>' + values_3[i] + '</option>');
//$('select').closest('.newUnit').append('<option>' + values_3[i] + '</option>');
$('.purchase-row #id_pro-unit').append('<option>' + values_3[i] + '</option>');
}
}
},
error: function (){
console.log('ERROR with ajax request in Adding Purchase-New Class !!!');
},
});
e.preventDefault();
});
});
My view
def get_new_row_unit(request):
data = {}
product = request.POST.get('pro-product')
data['product'] = product
if product is not None:
unit = UOM.objects.values('unit__name', 'uom_options', 'unit').filter(product_id=product)
else:
unit = []
data['unit'] = [(obj['unit__name']) for obj in unit]
print(
'PRODUCT: ', product,
'UNIT: ', unit,
)
return JsonResponse(data)
2- Also I tried to do like this Answer But I failed.
3- Also I follow instructions in this answer
But I get the "unit menu" of the main row in all new row when I select an item from the "product menu" in the new row.
My Problem in brief
When I select an item from "product" menu in the first "new cloned row" (or from any new rows)."unit menu" append to all above rows.
What I want to achieve
I want when I select an item from "product menu" only "unit menu" append to the "unit input" of the same row.
I knew that I've missed something but I failed to discover it.
Any suggestions will be appreciated.
=============================================================
My Answer To This Issue After searching and Thinking
=============================================================
Finally I fix my issue as usual (thanks to stackoverflow community).
I want to share my solution of this issue.
Really it took time to understand how it works and how to access the new row or (in other words "how to access the row inputs itself").
My Problem in brief :
When I select an item from "product" menu in the first "new cloned row" (or from any new rows)."unit menu" append to all above rows.
After searching on the web and searching here in the community questions. I found the next answers are useful and helpful.
Thanks to this answer by #martynas
Thanks to this answer by #Евгений Одинец
Thanks to this tutorial
And as I said it can be done by one ajax call.
1- In fact I tried to make a new ajax call for the new cloned row, but I realize that it can solve by the above ajax code (I don't know how).
The final code has became as follow
$(document).on('change', '.product', function(e){
var product_id = $(this).val();
let $el = $(this).closest('.purchase-row');
console.log('SUCCESS-CHANGE-PRODUCT: ', product_id,);
$.ajax({
type: 'POST',
url: '{% url "purchases:get_product_unit" %}',
data: {
'pro-product': product_id,
},
success: function (data) {
if (purchaseCount == 0) {
console.log('purchase count equal to ZERO: ');
console.log(
'FROM SUCCESS: ', data['unit'],
);
var values_3 = data['unit'];
if (values_3.length > 0) {
for (var i = 0; i < values_3.length; i++) {
$el.find('.unit').append('<option>' + values_3[i] + '</option>');
}
}
} else {
let unit = $el.find('.newUnit'); // here I can access the "unit input" of the same row of the "product input"
var values_3 = data['unit'];
unit.text('');
console.log('COUNT IS NOT EQUAL TO ZERO:', values_3);
if (values_3.length > 0) {
for (var i = 0; i < values_3.length; i++) {
unit.append('<option>' + values_3[i] + '</option>');
}
}
}
},
error: function (){
console.log('ERROR with ajax request in Adding Purchase !!!');
},
});
e.preventDefault();
});
Also I found some answers about how to copy table row to another table and these answers help me a lot.
Here is some of them
How to pass clicked/selected row data from one table to another table
Remove row from one table and add it to another with jQuery
How to read dynamically generated HTML table row's 'td' value

Handle <select> values with ajax in module class, prestashop 1.6

I'm developing a ps module which let you classify the product attachment in categories an display them in the front product page.
I'm using a draggable list with the attachment, and when you drop them to the category it turns to an option tag, each category has a select tag where to drop the attachment.
I want to save the attachments and the category where they was dropped, so I thought make an ajax call to bring the data to my module class but I'm new with ajax and cant approach it.
this is what I've made:
the js code (inside the proper .tpl):
<script>
$( ".droptrue" ).droppable({
drop: function( event, ui ) {
//add <option> tag when an attachment is dropped to category's select
$(event.target).append('<option value="' + ui.draggable.attr('id') + '" selected>'+ui.draggable.text()+'</option>');
//remove the <li> wich contained the attachment data
ui.draggable.fadeOut("slow").remove();
var val = $('#categoryAttachmentArr').val();
//var tab = val.split(',');
//for (var i=0; i < tab.length; i++)
//if (tab[i] == $(this).val())
// return false;
//create an array with the next format: 'id_category(1)'-'id_attachment(1)','id_category(2)'-'id_attachment(2)'[....]
//the comma will be the main character that will be splitted
$('#categoryAttachmentArr').val(val + ui.doppable.attr('id') + '-' + ui.draggable.attr('id') +',');
}
});
$('#submitAddProduct').click(function(e){
$.ajax({
type: 'POST',
url: baseDir + 'modules/adjuntos/classes/CategoryAttachment.php',
data: {
ajax: true,
action: \'CategoryArray\',
cat_array: $('#categoryAttachmentArray').val(),
}
dataType: 'json',
success: function(json) {
console.log($('#categoryAttachmentArray').val());
}
});
})
$( ".ui-state-default" ).draggable({
revert: "valid",
});
</script>
And my class:
class CategoryAttachment extends Objectmodel
{
//other functions
public function ajaxProcessCategoryArray()
{
$CategoryAttachmentArr = Tools::getValue('cat_array')
}
}
you can't connect directly to any class. you have to use the controller to do this.
Ajax send data to controller
Controller save data using class
Controller return result to browser (javascript)
Finaly I got the solution, maybe one of you guys will have this problem in the future.
My code in the .tpl:
$( ".ui-state-default" ).draggable();
$( ".droptrue" ).droppable({
drop: function( event, ui ) {
//add <option> tag when an attachment is dropped to category's select
$(event.target).append('<option value="' + ui.draggable.attr('id') + '" selected>'+ui.draggable.text()+'</option>');
$('#selectAttachment1').append('<option value="' + ui.draggable.attr('id') + '" selected>'+ui.draggable.text()+'</option>')
//remove the <li> wich contained the attachment data
ui.draggable.fadeOut("slow").remove();
var val = $('#categoryAttachmentArr').val();
//make a serialize() type array
$('#categoryAttachmentArr').val(val + $(this).attr('id') + "=" + ui.draggable.attr('id') +"&");
var value = $('#arrayAttachments').val();
var tab = value.split(',');
for (var i=0; i < tab.length; i++)
if (tab[i] == ui.draggable.attr('id')){
return false;
}
$('#arrayAttachments').val(value+ui.draggable.attr('id')+',');
}
});
$('#submitCategories').click(function(e){
var array = $('#categoryAttachmentArr').val()
$.ajax({
url: '../modules/adjuntos/ajax-call.php',
data: {
action: 'handlearray',
token:new Date().getTime(),
cat: array
},
method: 'POST',
success:function(data){
$('#result').html(data);
}
});
});
the ajax call goes to my ajax-call.php file:
<?php
//load ps config
require_once(dirname(__FILE__).'../../../config/config.inc.php');
require_once(dirname(__FILE__).'../../../init.php');
require_once('adjuntos.php');
//adjuntos.php is the name of my module main file
if(Tools::getIsset('token') && Tools::getIsset('action'))
{
$mp = new Adjuntos;
echo $mp->handleArray();
}
The handleArray function in my module main file:(it make a call to my custom class)
public static function handleArray()
{
$html = '';
$array = Tools::getValue('cat');
$arrayExplode = explode("&", $array);
foreach($arrayExplode as $value)
{
$finalArr = explode("=", $value);
if (!CategoryAttachment::postProcess($finalArr))
{
$html .= '<p style="color:red;>Fallo</p>"';
}
}
$html .= '<p style="color:green;>Correcto</p>"';
return $html;
}
The function in my custom class:
public static function postProcess($finalArr)
{
return Db::getInstance()->execute(
'UPDATE ps_attachment SET id_category = '.$finalArr[0].' WHERE id_attachment = '.$finalArr[1]
);
}//end
This way is working like a charm, and make the code more scalable

Dropdown value not being retained

I have a dropdown which gets its value from a model and is first populated. On click of that dropdown, I populate other values using AJAX. I am able to populate the dropdown but once I select an option from the dropdown, it gets reset to first value in the dropdown. What I want is the dropdown to populate once on click and then function like a normal dropdown. How do I put a condition for it?
This is the code for initially setting the dropdown value with the defined value 'field.Value'
ddlValue = "<option value="+field.Value+ " selected='selected'>" + field.Value+"</option>";
<td><select id='#String.Format("selValue{0}", field.Field)' class='ddlValue'>#Html.Raw(ddlValue)</select></td>
And this is the AJAX function which populates it.
$('body').on('click', '.ddlValue', function () {
var target = event.target.id;
var rowId = $('#' + target).closest("tr").prop("id");
var field = $('#' + rowId).find(".fieldvalue").html();
$.ajax({
cache: false,
url: '#Url.Action("PopulateDropdown", "AdvancedSearch")',
type: "POST",
data: { Field: field }
}).done(function (data) {
var listb = $('#' + target);
listb.empty();
$.each(data.value, function (index, value) {
listb.append($('<option>', {
value: value,
text: value
}, '<option/>'))
});
});
});
If you want the ajax population to happen only once, you need to remove the event listener after it has occurred. Something like so:
$('.ddlValue').on('click', function () {
$(this).off('click'); //This removes the event after it has happened once.
var target = event.target.id;
var rowId = $('#' + target).closest("tr").prop("id");
var field = $('#' + rowId).find(".fieldvalue").html();
$.ajax({
cache: false,
url: '#Url.Action("PopulateDropdown", "AdvancedSearch")',
type: "POST",
data: { Field: field }
}).done(function (data) {
var listb = $('#' + target);
listb.empty();
$.each(data.value, function (index, value) {
listb.append($('<option>', {
value: value,
text: value
}, '<option/>'))
});
});
});
Please note, the follow will not work:
$('body').on('click', '.ddlValue', function () {
$(this).off('click');
...
This seems like a silly way of doing this. You could do the same operation on loan without having any interaction with the user to populate the dropdown.
That being said to fix your solution simply add a global variable
$first = true
$('body').on('click', '.ddlValue', function () {
if($first) {
$first = false
var target = event.target.id;
var rowId = $('#' + target).closest("tr").prop("id");
var field = $('#' + rowId).find(".fieldvalue").html();
$.ajax({
cache: false,
url: '#Url.Action("PopulateDropdown", "AdvancedSearch")',
type: "POST",
data: { Field: field }
}).done(function (data) {
var listb = $('#' + target);
listb.empty();
$.each(data.value, function (index, value) {
listb.append($('<option>', {
value: value,
text: value
}, '<option/>'))
});
}
});
});

String Not Appended to Dynamically Created Div

I've researched this in depth on stackexchange and I don't think I am making a 'common' mistake, and the other answers have not solved this.
The problem is I am trying to append data to a DEFINITELY existing div of a certain ID. What I DO know is that the div is dynamically generated, and that is probably why it is hidden.
Despite using jquery on I cannot seem to get jquery to find the particular div.
Here is the code:
$(document).ready(function() {
function example_append_terms(data) {
var sender_id = data['sender_id'];
$.each(data, function(k, v) {
if (k != 'sender_id') {
html = '<span data-lemma="' + v['key'] + '" class="lemma">' + v['name'] + '</span>';
$('#' + sender_id + ' .lemmas').append(html);
}
});
}
function example_get_options(data) {
$.ajax({
url: '/example/',
type: 'post',
data: data,
success: function(data) {
//alert(JSON.stringify(data))
example_append_terms(data)
},
failure: function(data) {
alert('Got an error dude');
}
});
return false;
}
$(document).on('click', ".example-synset-option", function() {
var synset = $(this).data('name');
var sender_id = $(this).attr('id')
example_get_options({
'synset': synset,
'sender_id': sender_id,
});
});
});
On clicking a certain div, an action is fired to "get options" which in turn runs an ajax function. The ajax function runs the "replacer" function example_append_terms.
Having tested up to example_append_terms the .each iteration is definitely working. But when I did tested $('#' + sender_id + ' .lemmas').length I continue to get 0.
Where is this jquery newb going wrong?
I fixed it by changing stuff...
For some inexplicable reason fetching the data attribute worked better than the id..
function intellitag_append_terms(data) {
var sender_id = $('*[data-location="'+data['sender_id']+'"] .lemmas');
$.each(data, function(k, v) {
if (k != 'sender_id') {
html = $('<span data-lemma="' + v['key'] + '" class="label label-primary lemma">' + v['name'] + '</span>');
html.appendTo(sender_id)
//$('#' + sender_id).append(html);
}
});
}

How to retrieve value from a div dynamically?

Guys I have a function which uses ajax call to retrieve data dynamically based upon a value in div. Now lastNoticeID value in the function is not getting updated as its not in any loop..thus it keeps repeating the same data..
CODE :
function callMoreData() {
var lastNoticeID = $('#hiddenLastNoticeID').val();
$.ajax({
type: "GET",
url: "/api/values/getnotice?num=" + lastNoticeID,
dataType: "json",
crossDomain: true,
async: true,
cache: false,
success: function (data) {
$.each(data, function (index, value) {
BindNotice(value);
});
},
error: function (x, e) {
alert('problem while fetching records!');
}
});
}
function BindNotice(values) {
$('#divNotices').append('...some code...' +
'<input id="hiddenLastNoticeID" type="hidden" value="' + values.LastNoticeID +
'" />' + '...some code...');
}
As you can see in the code above, I am retrieving value from the above div and then passing it to webApi url... Now this is running fine and on the first scroll I get the values but then the function keeps repeating the same values over and over again i.e. var lastNoticeID is not getting updated. How do I get it to update per scroll event?
btw divNotices has the same html code as BindNotice function.
Use classes instead:
function BindNotice(values) {
$('#divNotices').append('...some code...' +
'<input class="hiddenNotice" type="hidden" value="' + values.LastNoticeID +
'" />' + '...some code...');
}
And then:
var lastNoticeID = $('.hiddenNotice').last().val();
Or, you could just store the LastNoticeID in a variable:
var lastNoticeID = 0;
function BindNotice(values) {
$('#divNotices').append('...some code...' +
'<input class="hiddenNotice" type="hidden" value="' + values.LastNoticeID +
'" />' + '...some code...');
lastNoticeID = values.LastNoticeID;
}
It would seem that you are adding more elements of the same ID. ID's are supposed to be single instance and Jquery will therefore only grab the first instance in the DOM. (Which is why $('#hiddenLastNoticeID').val(); is the same every time)

Categories