I have the below code, the first HTML snippet is loaded on the initial page load, then when the span with id flag is clicked the javascript will load the second HTML snippet into a hidden div on the webpage.
Now this hidden div has a select drop down box which when changed the javascript should make another AJAX call but $("#overlay #innerWrapper #country").on('change', function() { is never called.
I'm sure it's an event delegation issue but can't seem to see where I'm going wrong!?
Javascript
$("#topBar").on("click", "#flag", function(e) {
e.preventDefault();
var data = {};
$("#overlay").css("display", "inline");
// Country Change
$("#overlay #innerWrapper #country").on('change', function() {
var country = $(this).val();
ajaxCall(country);
});
ajaxCall(data);
e.stopPropagation();
});
Loaded on page load (snippet 1)
<div id="topBar">
<span id="flag" class="flag-icon"></span>
</div>
Loaded via a AJAX query (snippet 2)
<div id="innerWrapper">
<div id="title">Select Country</div>
<span id="flag" class="flag-icon"></span>
<select id="country" name="country">
<option value="fr" selected="selected"> France</option>
<option value="de"> Germany</option>
</select>
</div>
Update 1:
$("#innerWrapper").on('change', '#country', function() {
alert('1');
var country = $(this).val();
ajaxCall(country);
});
$("#topBar").on("click", "#flag", function(e) {
e.preventDefault();
var data = {};
$("#overlay").css("display", "inline");
ajaxCall(data);
e.stopPropagation();
});
function ajaxCall(element, callId, dataIn)
{
var limit;
var data;
if ($(element).data("limit")) {
limit = $(element).data("limit");
data = {id: callId, limit: limit, data: dataIn};
}
data = {id: callId, data: dataIn, element: element};
$.ajax(
{
type: "POST",
url: "ajax.php",
data: data,
beforeSend: function ()
{
if (element != 'ignore') {
$(element).append( "<div class=\"loading\"></div>");
}
},
success: function (data)
{
if (element != 'ignore') {
$(element).html(data);
} else {
location.reload(true);
}
},
complete: function ()
{
if (element != 'ignore') {
$(element).siblings(".loading").remove();
}
},
error: function (jqXHR)
{
$(element).html(jqXHR.status + " - " + jqXHR.statusText);
}
});
}
Related
I'm working on a ASP .Net Core project where for the first time I'm using Select2.
I have one page where I'm passing the ID's that I need by ViewModel like this:
Controller:
public async Task<IActionResult> MyPage()
{
var model = new MyViewModel()
{
selectedUSerId = 1,
selectedEmployeeId =1
};
return View(model);
}
View:
#model MyViewModel
<select class="form-select" id="User" name="User" data-url="#Url.Action("MyUserAction","MyUserController")" data-placeholder="#Localizer["SelectUser"].Value">
<option></option>
</select>
<select class="form-select" id="Employee" name="Employee" data-url="#Url.Action("MyEmployee","MyEmployeeController")" data-placeholder="#Localizer["SelectUser"].Value">
<option></option>
</select>
#section Scripts{
<script type="text/javascript">
var userId = "#Model.selectedUSerId";
var emplyeeId = "#Model.selectedEmployeeId";
$(document).ready(function () {
$('select').each(function () {
InitSelect2(this.id);
});
if(userId){
$('#User').val(userId).trigger('change');
}
if(emplyeeId){
$('#User').val(emplyeeId).trigger('change');
}
});
function InitSelect2(selector, selectedId = 0) {
var url = $("#" + selector).data('url');
var placeholder = $("#" + selector).data('placeholder');
const type = "POST";
const dataType = "json";
if (!url) {
console.error("Selector: " + selector + " Unspecified URL");
return;
}
if (placeholder === "") {
console.error("Selector: " + selector + " Unspecified Placeholder");
return;
}
try {
$("#" + selector).select2({
theme: "bootstrap-5",
width: $(this).data('width') ? $(this).data('width') : $(this).hasClass('w-100') ? '100%' : 'style',
placeholder: placeholder,
allowClear: true,
minimumInputLength: 3,
ajax: {
url: url,
type: type,
dataType: dataType,
delay: 250,
data: function (params) {
var query = {
id: selectedId,
searchFullName: params.term,
}
return query;
},
processResults: function (data) {
console.log(data)
return {
results: data.results
};
},
}
})
} catch (ex) {
console.error(ex);
}
}
</script>
}
So far it works perfectly.
But when I try to do:
$('#User').val(userId).trigger('change'); or
$('#Employee').val(emplyeeId ).trigger('change');
nothing happened.
I think its gonna work only when I retrieve the data the first time when I click the drop donw list, instead of doing it every time when it is clicked.
In that way I will have the <option>s and I can use the jQuery to select the <option> by Id.
I don't like to follow this approach, becouse the data should be load and setted dynamically. Theres no another way to do it?
If you want to do something only when first time the selected value is changed,you can try to use a js variable,change the value of it when first time the selected value is changed.Here is a sample,only when first time the selected value is changed,alert(1) will be called.
var UserCount = 0;
var EmplyeeCount = 0;
$('#User').change(function() {
if (UserCount == 0) {
UserCount++;
alert(1);
}
});
$('#Employee').change(function() {
if (EmplyeeCount == 0) {
EmplyeeCount++;
alert(1);
}
});
I have a radio button list (rblCategories) and when selected value is changed I create a checkbox list using ajax and populate it. I need to update my datatable when any checkbox is checked/unchecked but I can't get it to respond to to change in state.
This is what i have and what I have tried (I removed all unnecessary stuff like styling, etc.)
<div class="row">
<div class="col-sm-2">
<label for="ddlYear">Select Year</label>
<asp:DropDownList runat="server" ID="ddlYear" ClientIDMode="Static">
</asp:DropDownList>
</div>
<div class="col-sm-4">
<label for="rblCategories">Categories</label>
<asp:RadioButtonList runat="server"
ID="rblCategories"
ClientIDMode="Static"
DataTextField="Name"
DataValueField="TypeID"
AppendDataBoundItems="true">
</asp:RadioButtonList>
</div>
<div class="col-sm-6" id="divSubCategory">
</div>
</div>
//Using the selected values of ddlYear and rblCategories, populate table
function bindDataTable() {
var year = $('#ddlYear').val();
var selCategoryID = $('#rblCategories input:checked').val()
var url = "";
var params = "";
// -1 refers to "All" categories
if ('-1' == selCategoryID) {
url = "../services/exp.asmx/GetExpenseByYear";
params = JSON.stringify({ "Year": year });
}
else {
url = "../services/exp.asmx/GetExpenseByYearByCategory";
params = JSON.stringify({ "Year": year, "CategoryID": selCategoryID });
}
populteTable(url, params, tblExpenses);
}
//for testing
function bindDataTable(subCategories) {debugger
}
// create and populate sub-category checkbox list based on selected category
function updateSubTypes(typeID) {
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: '<%=ResolveUrl("~/services/exp.asmx/GetExpenseSubTypeItems") %>',
cache: false,
data: "{ 'TypeID': '" + typeID + "' }",
success: AjaxSucceeded,
error: AjaxFailed
});
}
function AjaxFailed(result) {
alert('Failed to load checkbox list');
}
function AjaxSucceeded(result) {
BindCheckBoxList(result);
}
function BindCheckBoxList(result) {
$('#divSubCategory').empty();
var items = JSON.parse(result.d);
if (items.length > 0)
CreateCheckBoxList(items);
}
function CreateCheckBoxList(checkboxlistItems) {
var lbl = $('<label></label>').text('Sub-Categories');
$('#divSubCategory').append(lbl);
var table = $('<table></table>').attr({ id: 'cblSubCategory', class: 'form-control' });
var row = table.append($('<tr></tr>'));
var counter = 0;
$(checkboxlistItems).each(function (i) {
row.append($('<td></td>').append($('<input>').attr({
type: 'checkbox', name: 'chklistitem', value: this.ExpenseSubTypeID, id: 'chklistitem' + counter
})).append(
$('<label>').attr({
for: 'chklistitem' + counter++
}).text(this.Name)));
});
$('#divSubCategory').append(table);
}
$(document).ready(function () {
$('#rblCategories input').change(function () {
var selCategoryID = $(this).val();
if (selCategoryID != null) {
updateSubTypes(selCategoryID)
}
bindDataTable();
});
// This never gets hit; I tried chklistitem instead of cblSubCategory too
$('#cblSubCategory input').change(function () {debugger
var selCategoryID = $('#rblCategories input:checked').val()
var names = $('.parent input:checked').map(function () {
return this.name;
}).get();
bindDataTable(names);
});
})
$('#cblSubCategory input').change(function () {
TO
$('#cblSubCategory').on('change','input', function () {
Use jQuerys .on() method when loading elements dynamically, which will look for any new elements added to the DOM that match that selector. Otherwise jQuery will only parse the DOM once on initial execution.
$(document).ready(function () {
$('#rblCategories').on('change','input', (function () {
var selCategoryID = $(this).val();
if (selCategoryID != null) {
updateSubTypes(selCategoryID)
}
bindDataTable();
});
// This never gets hit; I tried chklistitem instead of cblSubCategory too
$('#cblSubCategory').on('change','input', function () {debugger
var selCategoryID = $('#rblCategories input:checked').val()
var names = $('.parent input:checked').map(function () {
return this.name;
}).get();
bindDataTable(names);
});
})
The following changes fixed the issue; However, I marked cantucket's reply as answer cause he put me in the right direction.
I added an attr line to "createCheckBoxList" function; right after I append the resulting table to div:
function createCheckBoxList(checkboxlistItems) {
var lbl = $('<label></label>').text('Sub-Categories');
$('#divSubCategory').append(lbl);
var table = $('<table></table>').attr({ id: 'cblSubCategory', class: 'form-control' });
var row = table.append($('<tr></tr>'));
var counter = 0;
$(checkboxlistItems).each(function (i) {
row.append($('<td></td>').append($('<input>').attr({
type: 'checkbox', name: 'cblSubCategory', value: this.ExpenseSubTypeID, id: 'cblSubCategory' + counter
})).append(
$('<label>').attr({
for: 'cblSubCategory' + counter++
}).text(this.Name)));
});
$('#divSubCategory').append(table);
// added this line
$('#divSubCategory').attr({ onclick: "onSubCatChange()" });
}
I added "onSubCatChange()" function:
function onSubCatChange() {
// Both following methods work to get list o checked items
var names = [];
$('#cblSubCategory input:checked').each(function() {
names.push(this.value);
});
var names2 = $('#cblSubCategory input:checked').map(function () {
return this.value;
}).get();
bindDataTable(names);
}
And I removed the checkbox list's on change handler in document.ready() function.
i made a function that sends data (ajax) to the database and depending on the response from the server i need to alert a message but it seems like whenvever i change the select option i get the alert message for each change(if i change the select four times when i click i get the alert four times ) , but if i remove my ajax function and replace it simply by an alert i get it once not repeating itself here is my JS
$('.select_ids').change(function () {
var id = $(this).val();
var form = $('#form_widget_ids_' + id);
var container = form.parent('.ewb_forms');
var box = container.parent('.edit_widget_box');
container.children('.selected').fadeOut(300, function () {
$(this).removeClass('selected');
form.fadeIn(300, function () {
$(this).addClass('selected');
});
});
Widget.updateSSOUrl(box);
$.ajax({
type: "POST",
url: window.location + "",
data: {'id': id}
}).done(function (msg) {
$(".red").on('click', function (evt) {
if ('done' == msg) {
evt.preventDefault();
alert('NOP');
}
})
});
});
the event that you are binding i think is wrong. For newly append items is better in your case to use
$(document).on('click', ".red", function (evt) {
})
And it must be moved outside the ajax success because now you are triggering it every time
----- Edited ---
If you want just to alert the output of the ajax you dont need the onClick event
$('.select_ids').change(function () {
var id = $(this).val();
var form = $('#form_widget_ids_' + id);
var container = form.parent('.ewb_forms');
var box = container.parent('.edit_widget_box');
container.children('.selected').fadeOut(300, function () {
$(this).removeClass('selected');
form.fadeIn(300, function () {
$(this).addClass('selected');
});
});
Widget.updateSSOUrl(box);
$.ajax({
type: "POST",
url: window.location + "",
data: {'id': id}
}).done(function (msg) {
if (msg === 'done') {
evt.preventDefault();
alert('NOP');
}
});
});
If you want to show the latest result on a button click you can store the msg on a global variable and on click of a div show that like
var globalMsg = "";
$('.select_ids').change(function () {
var id = $(this).val();
var form = $('#form_widget_ids_' + id);
var container = form.parent('.ewb_forms');
var box = container.parent('.edit_widget_box');
container.children('.selected').fadeOut(300, function () {
$(this).removeClass('selected');
form.fadeIn(300, function () {
$(this).addClass('selected');
});
});
Widget.updateSSOUrl(box);
$.ajax({
type: "POST",
url: window.location + "",
data: {'id': id}
}).done(function (msg) {
globalMsg = msg
});
});
$(".div").click(function() { alert(globalMSG); });
I have "load more" button, and if I click it fast enough it load the same content twice, and I want to prevent it.
This is how I call to the load more with ajax:
<script type="text/javascript">
function loadmore() {
var val = document.getElementById("result_no").value;
var userval = document.getElementById("user_id").value;
$.ajax({
type: 'post',
url: 'fetch.php',
data: {
getresult: val,
getuserid: userval
},
context: this,
success: function(response) {
var content = document.getElementById("result_para");
content.innerHTML = content.innerHTML + response;
document.getElementById("result_no").value = Number(val) + 10;
}
});
}
</script>
<div id="content">
<div id="result_para">
</div>
</div>
<input type="hidden" id="user_id" value="<?php echo $userid;?>">
<input type="hidden" id="result_no" value="15">
<input type="button" id="load" onclick="loadmore()" value="Load More Results">
You could set a loading variable to true at the start of loadmore, and set it back to false in the ajax callback. loading should be declared outside of loadmore though (see what a closure is).
var loading = false;
function loadmore()
{
if (loading) {
return ;
}
loading = true;
var val = document.getElementById("result_no").value;
var userval = document.getElementById("user_id").value;
$.ajax({
type: 'post',
url: 'fetch.php',
data: {
getresult:val,
getuserid:userval
},
context: this,
success: function (response) {
loading = false;
var content = document.getElementById("result_para");
content.innerHTML = content.innerHTML+response;
document.getElementById("result_no").value = Number(val)+10;
},
error: function () {
loading = false;
}
});
}
Instead of using that variable, you could also programmatically disable/enable the button, but that means that your button will flicker if the request is fast.
You can prevent from this by disable the button after first click, so change this lines:
success: function (response) {
var content = document.getElementById("result_para");
content.innerHTML = content.innerHTML+response;
document.getElementById("result_no").value = Number(val)+10;
}
With this lines:
success: function (response) {
document.getElementById("load").disabled = true;
var content = document.getElementById("result_para");
content.innerHTML = content.innerHTML+response;
document.getElementById("result_no").value = Number(val)+10;
document.getElementById("load").disabled = false;
}
you could disable the button when the "load more" button is clicked then then use the javascript function setTimeout to remove the disabled attribute from the button after a period of time. This would mean that the button would not be able to be clicked after the first click and even if the ajax request returned an error the button would still be able to be clicked.
$('#load').click(function {
// disable the button
$(this).prop('disabled', true);
// after three seconds enable the button again
var timeout = setTimeout(function() { $(this).prop('disabled', false); }, 3000);
});
i have a situation where im apending html to load more posts(pagination), and each post has a reply link, the appened html is not functioning properly:
the jquery post:
$(function () {
//More Button
$('.more').live("click", function () {
var ID = $(this).attr("id");
if (ID) {
$("#more" + ID).html('<img src="moreajax.gif" />');
$.ajax({
type: "POST",
url: "ajax_more.php",
data: "lastmsg=" + ID,
cache: false,
success: function (html) {
$("ul.statuses").append(html);
$("#more" + ID).remove();
}
});
} else {
$(".morebox").html('The End');
}
return false;
});
});
html file:
return <<<ENDOFRETURN
<li>
<img class="avatar" src="images/$picture" width="48" height="48" alt="avatar" />
<div class="tweetTxt">
<strong>$username</strong> $auto
<div class="date">$rel</div>
<a class ="reply" href="home.php?replyto=#$username&status_id=$id&reply_name=$username"> reply </a>
</div>
<div class="clear"></div>
</li>
ENDOFRETURN;
the reply link jquery:
function insertParamIntoField(anchor, param, field) {
var query = anchor.search.substring(1, anchor.search.length).split('&');
for (var i = 0, kv; i < query.length; i++) {
kv = query[i].split('=', 2);
if (kv[0] == param) {
field.val(kv[1]);
return;
}
}
}
$(function () {
$("a.reply").click(function (e) {
insertParamIntoField(this, "status_id", $("#status_id"));
insertParamIntoField(this, "reply_name", $("#reply_name"));
insertParamIntoField(this, "replyto", $("#inputField"));
$("#inputField").focus()
$("#inputField").val($("#inputField").val() + ' ');
e.preventDefault();
return false; // prevent default action
});
});
I'm taking a shot in the dark but it sounds like you haven't used a .live() event on the reply buttons. Any new buttons being appended to the document will not have the click event that you specified for them attached.
So in short make sure any buttons that are loaded dynamically and need to fire off an event are using a 'live' event binding.
Change your click handler to use .live() like this to make it work on links added later as well.:
$(function () {
$("a.reply").live("click", function (e) {
insertParamIntoField(this, "status_id", $("#status_id"));
insertParamIntoField(this, "reply_name", $("#reply_name"));
insertParamIntoField(this, "replyto", $("#inputField"));
$("#inputField").val(function(i, v) { return v + ' '; }).focus();
return false;
});
});