JavaScript/jQuery dynamic function binding and ajax - javascript

I'm trying to build out a dynamic list of UI elements. I can hard code the UI list now, and everything works fine. I want this to be extensible however, so I'm trying to figure a way of passing id tags and corresponding functions to be called. Essentially, the callback function for my ajax call isn't being executed, though I am posting the correct data, and receiving the correct response. Here's the code:
myModule = function () {
var titleUI = Object.create(ChainUI());
var memcachedId = '<?php echo $memcachedId;?>';
return {
printChain: function(data) {
alert("printchain");
var territories = jQuery.parseJSON(data);
titleUI.makeChainTable();
territories.forEach(function(territory) {
titleUI.territoryDisplay(territory);
});
titleUI.tableDecorator($('#chainTable'));
},
loadChain: function() {
titleUI.destroyChainTable();
var url = 'traffichandler.php';
var instruction = {'instruction': 'titleChain', 'method': 'printChain', 'memcachedId': memcachedId.toString()};
$.post(url, instruction, this.printChain);
},
loadDefault: function() {
titleUI.loadUI(['Title Chain'], [this.loadChain]);
}
};
}();
The corresponding titleUI code follows:
var ChainUI = function() {
return {
loadUI: function(uiList, funcList) {
$('#uiFunctions').empty();
for(var i in uiList) {
var toDom = '<li id="'+uiList[i]+'">';
toDom += uiList[i];
toDom += '</li>';
$('#uiFunctions').html(toDom);
}
for(var i = 0; i < uiList.length; i++) {
var myFunc = funcList[i];
$('#uiFunctions').delegate($('#'+uiList[i]), "click",
function() {myFunc();}
);
}
},
}
In myModule.loadDefault, I can get this.loadChain to fire. I can't get this.printChain inside the $.post to work though. If remove all the dynamic stuff this.printChain works no problem. Don't get too hung up on the syntax, as is, the syntax is fine on my end. How can I get the ajax call back to work? Thanks!

Related

Class not changing after get request Jquery

I'm having trouble changing the class after making a jquery get request.
code:
<script>
//global variable
var table = []
var numberofaccounts = 0
$(document).ready(function() {
$('#form1').validate();
// add numbers to select ids
$(".select_changer").each(function(){
numberofaccounts++;
var new_id = "select_class"+numberofaccounts;
$(this).addClass(new_id);
});
$('#apply_btn').click(function() {
table = []
var count = 0;
var text = "";
var tracker = 0
$('#stats_table tr').each(function(){
count = 0;
text = "";
$(this).find('td').each(function(){
count++;
if (count == 4) {
text += $( ".select_class"+ tracker + " option:selected" ).val();
} else {
text += " " + $(this).text() + " ";
}
})
table.push(text);
tracker++;
});
$.post("/apply_changes", {"data": JSON.stringify(table)}, function(data) {
var res = JSON.parse(data);
if (res.data == true){
$('#updated').text("Update Successful").css('color', 'green');
$.get("/", function( data ) {
$('#stats_table').load("/ #stats_table");
numberofaccounts = 0
$(".select_changer").each(function(){
numberofaccounts++;
var new_id = "select_class"+numberofaccounts;
$(this).addClass(new_id);
});
});
} else {
$('#updated').text("Update Unsuccessful").css('color', 'red');
}
});
});
});
</script>
So when the page first loads this method changes the class on dynamically created select elements.
$(".select_changer").each(function(){
numberofaccounts++;
var new_id = "select_class"+numberofaccounts;
$(this).addClass(new_id);
});
After I make a post to flask the if the response data is true I go ahead and make a get request to grab the updated items from the db. I then refresh the table. This works great if I make one request. However on the second post nothing happens. This is because the classes that I modified at the start of the page load no longer exist. So i added the method above to also trigger after the get response (I also tried at the end of the post response). The problem is that the method doesn't seem to run again. The classes aren't there and as a result when I go to make another post request it can't find the element. How do I go about fixing this?
Things to note: The get request is necessary, the ids and classes cannot be statically assigned.
You are trying to assign classes before you even refresh your table.
$('#stats_table').load("/ #stats_table"); is called asynchronously and returns before it even completes.
You need to put you code, for assigning classes, inside the complete callback of your .load() call:
$('#stats_table').load("/ #stats_table", function() {
numberofaccounts = 0
$(".select_changer").each(function(){
numberofaccounts++;
var new_id = "select_class"+numberofaccounts;
$(this).addClass(new_id);
});
});

Controls won't work after a recursive call jquery

I am opening mvc view(s) inside a modal dialog.
I am trying to make a recursive call and the problem I am facing is : after the recursive call the view loads properly but none of the controls on the view work :
In Main.js :
$(function () {
$(document).on('click', '.ddlCart li', Mod.Carts);
}
Carts.js :
var Mod = Mod || {};
Mod.Carts = function (e) {
var ddlselectedVal = $(this).attr('id');
var selectedListinsCount = selected_Listings.length;
var SelectedMlsnums = selected_Listings.join();
var agentId = $("#AgentId").val();
var Action;
var EnvironmentURL = $("#EnvironmentURL").val();
var postData = { AgentId: agentId, Mlsnums: SelectedMlsnums, ActionTypeValue: “PreAddToCart” };
var close = function (event, ui) {
$('#dvModalDialog').dialog("close");
}
var open = function (event, ui) {
var url = EnvironmentURL + "MLSReports/Stats/SearchContacts";
$("#btncart_cancel").on("click", function () {
$('#dvModalDialog').dialog("close");
});
$("#btncart_submit").on("click", function () {
var url = EnvironmentURL + "MLSReports/Stats/Cart";
//Send the data using post and put the results in a div
$.post(url, {
AgentId: agentId, Mlsnums: SelectedMlsnums, ActionTypeValue: "AddToCart"
},
function (data) {
// Replace current data with data from the ajax call to the div.
$("#dvModalDialog").empty().append(data);
});
});
$("#lnkCreateNewcart").on("click", function () {
var url = EnvironmentURL + "MLSReports/Stats/Cart";
//Send the data using post and put the results in a div
$.post(url, {
ActionTypeValue: "preAddorEditContact"
},
function (data) {
//debugger;
// Replace current data with data from the ajax call to the div.
$("#dvModalDialog").empty().append(data);
$("#btnCancelContact").on("click", function () {
////********** replace the view (Contact) with the view (Cart).
// In the cancel event I am loading the previous page.I am having problem here. after a recursive call none of the controls work.**
// rd.open();
this.Mod.Carts();
});
});
});
};
if (ddlselectedVal == "AddtoCart") {
var rd = Mod.ReportsDialog({ title: 'Add To Cart', close: close, open: open });
rd.url = EnvironmentURL + "/MLSReports/Stats/Cart";
rd.targetElement = '#dvModalDialog'// '#dvSendEmail'
rd.formName = '#frmCart'
rd.postData = postData
rd.open();
}
};
The value of this inside of the referenced function is going to be different when this.Mod.Carts(); is used. You should use call in this scenario to bind the value of this to the proper value when calling the Carts function.
$("#btnCancelContact").on("click", function () {
Mod.Carts.call(this);
});

jQuery Find and Replace is Hanging up the browser! Data size too big?

With alot of help from #kalley we have found out that If I comment the following two lines out the LAG is gone!
var $tableContents = $table.find('tbody')
var $html = $('<tbody/>').html(data);
But how do I keep the above but cancel out the LAG ?
MORE INFO:
The code below works but the problem is that the $.GET is causing the browser to hang until the ajax request completes. I need (flow control?) or something that will solve this problem without locking/hanging up the browser until ajax completes the GET request.
The biggest LAG/Lockup/Hang is at $.get("updatetable.php", since the others only return 7 or less (number) values and this one ('updatetable.php') returns alot more (200-300kb). I would like to implement some sort of flow control here or make the script wait like 5 secs before firing the update command for tablesort and before showing the toast message so that ajax has time to GET the $.get("updatetable.php"data I just don't understand why does it lockup the browser as it is getting the data? is it trying to fire the other commands and that's whats causing the LAG?
Here are the STEPS
1.
$.get("getlastupdate.php" Will fire every 10 secs or so to check if the date and time are the same the return data looks like this: 20130812092636 the format is: YYYmmddHHmmss.
2.
if the date and time are not the same as the last GET then $.get("getlastupdate2.php" will trigger and this data will be send back and placed into a toast message and dispalyed to the user $().toastmessage('showNoticeToast', Vinfoo);
3.
before or after the above ($.get("getlastupdate2.php") another GET will fire: $.get('updatetable.php' this will GET the updated table info. and replace the old one with the new info. and then update/resort the table
4.
at the end of it all I want to $.get("ajaxcontrol.php" and this will return a 1 or 2 if the user is logged in then it will be a 2 else it's a 1 and it will destroy the session and log the user out.
<script type="text/javascript" src="tablesorter/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="tablesorter/final/jquery.tablesorter.js"></script>
<script type="text/javascript" src="tablesorter/final/jquery.tablesorter.widgets.js"></script>
<script type="text/javascript" src="tablesorter/final/toastmessage/jquery.toastmessage-min.js"></script>
<script type="text/javascript" src="tablesorter/qtip/jquery.qtip.min.js"></script>
<script type="text/javascript">
var comper;
function checkSession() {
return $.get("ajaxcontrol.php", function (DblIn) {
console.log('checking for session');
if (DblIn == 1) {
window.location = 'loggedout.php';
}
}).then(updateTable);
}
function checkComper() {
var SvInfo;
var onResponse = function (comperNow) {
if (comper === undefined) {
comper = comperNow;
} else if (comper !== comperNow) {
var Vinfoo;
comper = comperNow;
// returning this $.get will make delay done until this is done.
return $.get("getlastupdate2.php", function (primaryAddType) {
Vinfoo = primaryAddType;
$().toastmessage('showNoticeToast', Vinfoo);
}).then(checkSession);
}
};
$.get('getlastupdate.php').then(onResponse).done(function () {
tid = setTimeout(checkComper, 2000);
});
}
function updateTable() {
return $.get('updatetable.php', function (data) {
console.log('update table');
var $table = $("table.tablesorter");
var $tableContents = $table.find('tbody')
var $html = $('<tbody/>').html(data);
$tableContents.replaceWith('<tbody>' + data + '</tbody>')
//$tableContents.replaceWith($html)
$table.trigger("update", [true]);
var currentUrl = document.getElementById("frmcontent").contentWindow.location.href;
var urls = ['indexTOM.php', 'index1.php'],
frame = document.getElementById('frmcontent').contentDocument;
for (var i = 0; i < urls.length; i++) {
var url = urls[i];
if (frame.location.href.indexOf(url) !== -1) {
frame.location.reload()
}
}
$('[title!=""]').qtip({});
});
};
$(function () {
var tid = setTimeout(checkComper, 2000);
$("#append").click(function (e) {
// We will assume this is a user action
e.preventDefault();
updateTable();
});
// call the tablesorter plugin
$("table.tablesorter").tablesorter({
theme: 'blue',
// hidden filter input/selects will resize the columns, so try to minimize the change
widthFixed: true,
// initialize zebra striping and filter widgets
widgets: ["saveSort", "zebra", "filter"],
headers: {
8: {
sorter: false,
filter: false
}
},
widgetOptions: {
filter_childRows: false,
filter_columnFilters: true,
filter_cssFilter: 'tablesorter-filter',
filter_filteredRow: 'filtered',
filter_formatter: null,
filter_functions: null,
filter_hideFilters: false, // true, (see note in the options section above)
filter_ignoreCase: true,
filter_liveSearch: true,
filter_reset: 'button.reset',
filter_searchDelay: 300,
filter_serversideFiltering: false,
filter_startsWith: false,
filter_useParsedData: false
}
});
// External search
$('button.search').click(function () {
var filters = [],
col = $(this).data('filter-column'), // zero-based index
txt = $(this).data('filter-text'); // text to add to filter
filters[col] = txt;
$.tablesorter.setFilters($('table.hasFilters'), filters, true); // new v2.9
return false;
});
});
</script>
Maybe instead of using setInterval, you should consider switching to setTimeout. It will give you more control over when the time repeats:
function checkComper() {
var SvInfo;
var onResponse = function (comperNow) {
if (comper === undefined) {
comper = comperNow;
} else if (comper !== comperNow) {
var Vinfoo;
comper = comperNow;
// returning this $.get will make delay done until this is done.
return $.get("getlastupdate2.php", function (primaryAddType) {
Vinfoo = primaryAddType;
$().toastmessage('showNoticeToast', Vinfoo);
}).then(checkSession);
}
};
$.get('getlastupdate.php').then(onResponse).done(function () {
tid = setTimeout(checkComper, 10000);
});
}
var tid = setTimeout(checkComper, 10000);
Then you can keep it async: true
Here's a fiddle showing it working using echo.jsontest.com and some fudging numbers.
Since the click event callback seems to be where the issue is, try doing this and see if it removes the lag (I removed other comments to make it more brief):
function checkSession() {
return $.get("ajaxcontrol.php", function (DblIn) {
console.log('checking for session');
if (DblIn == 1) {
window.location = 'loggedout.php';
}
}).then(updateTable);
}
function updateTable() {
return $.get('updatetable.php', function (data) {
console.log('update table');
var $tableContents = $table.find('tbody')
//var $html = $('<tbody/>').html(data);
//$tableContents.replaceWith($html);
// replaceWith text seems to be much faster:
// http://jsperf.com/jquery-html-vs-replacewith/4
$tableContents.replaceWith('<tbody'> + data + '</tbody>');
//$table.trigger("update", [true]);
var currentUrl = document.getElementById("frmcontent").contentWindow.location.href;
var urls = ['indexTOM.php', 'index1.php'],
frame = document.getElementById('frmcontent').contentDocument;
for (var i = 0; i < urls.length; i++) {
var url = urls[i];
if (frame.location.href.indexOf(url) !== -1) {
frame.location.reload()
}
}
$('[title!=""]').qtip({});
});
};
$("#append").click(function (e) {
// We will assume this is a user action
e.preventDefault();
updateTable();
});
I commented out $table.trigger("update", [true]) since if you sort the table on the server before you return it, you shouldn't need to run that, which I'm almost certain is where the bottleneck is.
It is really hard untangle the mess you have but if what you want is ajax requests every 10 seconds it make sense to separate this logic from business logic over data from server.
Your code would also really benefit from using promises. Consider this example
$(document).ready(function() {
var myData = { }
, ajaxPromise = null
setInterval(callServer, 1000)
function callServer() {
ajaxPromise = updateCall()
.then(controlCall)
.done(handler)
.error(errorHandler)
}
function updateCall() {
return $.get('updateTable.php', function(data) {
myData.update = data
})
}
function controlCall( ) {
return $.get('ajaxControl.php', function(data) {
myData.control = data
})
}
function handler() {
console.dir(myData)
}
function errorHandler(err) {
console.log(err)
console.dir(myData)
}
})

$.getJSON request does not run but next line of code does

I have a $.getJSON request that does not run but the line of code right after the request does. If I remove all the code after the $.getJSON request the request will run. How do I get the request to run iterate over returned data then run code following the request.
var eventList = new Array();
$.getJSON('../index.php?/home/events', function(eventItems){
$.each(eventItems, function() {
var event = this;
var eventItem = new Array();
// format the date and append to span
eventItem[0] = formatMDYDate(formatTimeStamp(this.loc_datetime, false), 0);
// add shortdescription to div
eventItem[1] = this.shortdescription;
// check if longdescription exist
if (this.longdescription) {
// create new anchor element for "More Info" link on events
var link = $('<a></a>');
link.attr('href', '../index.php?/home/event_info');
link.addClass('popup');
link.html('More Info');
//link.bind('click', eventPopUp());
link.bind('click', function() {
var addressValue = event.id;
dialog = $('<div></div>').appendTo('body');
dialog.load('../index.php?/home/event_info',
{id: addressValue});
dialog.modal({
opacity: 80
});
return false;
});
eventItem[2] = link;
}
eventList.push(eventItem);
});
});
// removing the following lines of code will let the .getJSON request run
if (eventList.length > 0) {
write_Events(eventList);
}
I have no idea what is causing this issue, please help!
Asynchronous means that when you call it the JS runtime will not wait for it to finish before executing next line of code. Typically you need to use call backs in this case.
It's something like:
var a="start";
setTimeout(function(){
a="done";
dosomethingWithA(a);
},1000);
if(a=="done"){}//doesn't matter, a is not "done"
function dosomethingWithA(a){
// a is "done" here
}
In your case the code should look something like:
var eventList = new Array();
$.getJSON('../index.php?/home/events', function(eventItems){
$.each(eventItems, function() {
var event = this;
var eventItem = new Array();
// format the date and append to span
eventItem[0] = formatMDYDate(formatTimeStamp(this.loc_datetime, false), 0);
// add shortdescription to div
eventItem[1] = this.shortdescription;
// check if longdescription exist
if (this.longdescription) {
// create new anchor element for "More Info" link on events
var link = $('<a></a>');
link.attr('href', '../index.php?/home/event_info');
link.addClass('popup');
link.html('More Info');
//link.bind('click', eventPopUp());
link.bind('click', function() {
var addressValue = event.id;
dialog = $('<div></div>').appendTo('body');
dialog.load('../index.php?/home/event_info',
{id: addressValue});
dialog.modal({
opacity: 80
});
return false;
});
eventItem[2] = link;
}
eventList.push(eventItem);
});
processEventList();
});
function processEventList(){
// removing the following lines of code will let the .getJSON request run
if (eventList.length > 0) {
write_Events(eventList);
}
}
try
var eventList = new Array();
$.getJSON('../index.php?/home/events', function (eventItems) {
$.each(eventItems, function () {
//....
eventList.push(eventItem);
});
// removing the following lines of code will let the .getJSON request run
if (eventList.length > 0) {
write_Events(eventList);
}
});
Alternatively, you can use PubSub with jquery technique
var eventList = new Array();
$.getJSON('../index.php?/home/events', function (eventItems) {
$.each(eventItems, function () {
//....
eventList.push(eventItem);
});
//publisher
$(document).trigger('testEvent', eventList);
});
//subscriber
$(document).bind("testEvent", function (e, eventList) {
if (eventList.length > 0) {
write_Events(eventList);
}
});
For more detials http://www.codeproject.com/Articles/292151/PubSub-with-JQuery-Events
happy coding.. :)
$.getJSON is an asynchronous call. The callback will not execute until after the current function has executed completely. The code after the call will always run BEFORE the getJSON callback runs.
Its possible the write_Events function is throwing an error and stopping execution, which is why the callback is never running. Or it is actually running but you're not seeing evidence of it for whatever reason called by the extra code.
javascript code never wait for the response from the server and we need to stop the processing of javascript until we get the response from the server.
we can do this by using jquery.Deferred
You can also visit this tutorial.

Tried to register widget with id==valores0 but that id is already registered

i get this error, and i don't know how can be solved. I read this link before.
EDIT:1
index.php
<script type="text/javascript">
$(document).ready(function() {
$("#customForm").submit(function() {
var formdata = $("#customForm").serializeArray();
$.ajax({
url: "sent.php",
type: "post",
dataType: "json",
data: formdata,
success: function(data) {
switch (data.livre) {
case 'tags':
$("#msgbox2").fadeTo(200, 0.1, function() {
$(this).html('Empty tags').fadeTo(900, 1);
});
break;
default:
$("#msgbox2").fadeTo(200, 0.1, function() {
$(this).html('Update').fadeTo(900, 1, function() {
$('#conteudo').load('dojo/test_Slider.php');
});
});
break;
}
}
});
return false;
});
});
</script>
test_slider.php
<script type="text/javascript">
var slider = [];
for (i = 0; i < 5; i++) {
slider[i] = (
function(i) {
return function() {
var node = dojo.byId("input"+[i]);
var n = dojo.byId("valores"+[i]);
var rulesNode = document.createElement('div'+[i]);
node.appendChild(rulesNode);
var sliderRules = new dijit.form.HorizontalRule({
count:11,
style:{height:"4px"}
},rulesNode);
var labels = new dijit.form.HorizontalRuleLabels({
style:{height:"1em",fontSize:"75%"},
},n);
var theSlider = new dijit.form.HorizontalSlider({
value:5,
onChange: function(){
console.log(arguments);
},
name:"input"+[i],
onChange:function(val){ dojo.byId('value'+[i]).value = dojo.number.format(1/val,{places:4})},
style:{height:"165px"},
minimum:1,
maximum:9,
}
},node);
theSlider.startup();
sliderRules.startup();
}
})(i);
dojo.addOnLoad(slider[i]);
}
</script>
Problem: First click in submit btn all works well, 5 sliders are imported. Second click, an update is supposed, but i get this message:
Tried to register widget with id==valores0 but that id is already registered
[Demo video]2
Just to add on to #missingo's answer and #Kevin's comment. You could walk through the existing dijits by looking in the registry:
var i = i || 0; // Cache this at the end of your loop
dijit.registry.map(function (widget) {
if (+widget.id.replace(/^[^\d]+/, '') < i) {
widget.destroyRecursive();
}
});
/*
Your loop fixed as described in missingno's answer.
*/
You fell in the age-old trap of making function closures inside a for loop. By the time addOnLoad fires and the sliders are created, i will be equal to 2 and both sliders will try to use the same DOM nodes (something that is not allowed).
You need to make sure that you give a fresh copy of i for everyone. The following is a quick fix:
for(i=0; i<2; i++){
(function(i){
slider[i] = ...
//everything inside here remains the same
//except that they now use their own i from the wrapper function
//instead of sharing the i from outside.
}(i));
}
Dijit stores all active widgets in the dijit.registry, and uses id's as unique qualifiers. You can't create dijits with same id.
Need to clean dojo.registry before create a new slider dijits. Add this code before declare dijit on test_slider.php
dijit.registry["input"+ [i]].destroyRecursive();
can you assign any number ID like ID generated by 10 digit random number or something with datetime combination so id will never be same.

Categories