jquery define timeout when calling function - javascript

I am stuck on getting a timeout working. I already have a working code but it seems to me the wrong way to do it.
Working code but probably not the best:
/* Autosave */
// On load we hide all autosave messages.
$('.jform_params_autosave-cg').hide();
// Below is the function that handles the autosave.
$.fn.autoSave = function(){
// We remove the autosave message from it's place defined by the xml and add it to the system message container.
var autosavemessage = $('.jform_params_autosave-cg');
autosavemessage.detach();
autosavemessage.appendTo('#system-message-container');
// Now we show the message.
$('.jform_params_autosave-cg').show();
// Here we save the extension.
Joomla.submitbutton('module.apply');
}
// On change of the below elements we run the autosave.
//------------------------------------------//
// DUPLICATE AUTOSAVE FUNCTION BELOW
//------------------------------------------//
// Autosave: Theme Selection
$("#jform_params_theme_selection").change(function() {
$.fn.autoSave();
});
// Autosave: Add Content
$("a.group-add.btn.btn-mini.button.btn-success").click(function() {
setTimeout(
function()
{
$.fn.autoSave();
}, 5000);
});
The Function:
$.fn.autoSave = function(){
// We remove the autosave message from it's place defined by the xml and add it to the system message container.
var autosavemessage = $('.jform_params_autosave-cg');
autosavemessage.detach();
autosavemessage.appendTo('#system-message-container');
// Now we show the message.
$('.jform_params_autosave-cg').show();
// Here we save the extension.
Joomla.submitbutton('module.apply');
}
The Function Call
$("#jform_params_theme_selection").change(function() {
$.fn.autoSave();
});
The Function Call with Timeout
$("a.group-add.btn.btn-mini.button.btn-success").click(function() {
setTimeout(
function()
{
$.fn.autoSave();
}, 5000);
});
What do I want to achieve
Make the Timeout inside the function.
Define the timeout when calling the function.
With defining I mean calling it something like $.fn.autoSave(5000); or $.fn.autoSave().timeout(500);
I have been trying to get a working code but so far no luck. Will keep updating this post whenever I get more success or details to add.
Thanks everyone for helping.
Any link to existing SO questions will also be appreciated as I might be googling for the wrong key words.

Here it is the modified version of your function. Now it has optional timeout parameter. You can use it like
$('selector').autoSave(5000) or $('selector').autoSave()
$.fn.autoSave = function(timeout) {
function doIt() {
// We remove the autosave message from it's place defined by the xml and add it to the system message container.
var autosavemessage = $('.jform_params_autosave-cg');
autosavemessage.detach();
autosavemessage.appendTo('#system-message-container');
// Now we show the message.
$('.jform_params_autosave-cg').show();
// Here we save the extension.
Joomla.submitbutton('module.apply');
return this;
}
timeout = Number(timeout) || 0;
var f = doIt.bind(this);
if(timeout < 0) return f();
setTimeout(f, timeout);
return this;
}

Related

JQuery $.post callback firing a function that never finishes

Here's the problem. I'm making a callback to the server that receives an MVC partial page. It's been working great, it calls the success function and all that. However, I'm calling a function after which iterates through specific elements:
$(".tool-fields.in div.collapse, .common-fields div.collapse").each(...)
Inside this, I'm checking for a specific attribute (custom one using data-) which is also working great; however; the iterator never finishes. No error messages are given, the program doesn't hold up. It just quits.
Here's the function with the iterator
function HideShow() {
$(".tool-fields.in div.collapse, .common-fields div.collapse").each(function () {
if (IsDataYesNoHide(this)) {
$(this).collapse("show");
}
else
$(this).collapse("hide");
});
alert("test");
}
Here's the function called in that, "IsDataYesNoHide":
function IsDataYesNoHide(element) {
var $element = $(element);
var datayesnohide = $element.attr("data-yes-no-hide");
if (datayesnohide !== undefined) {
var array = datayesnohide.split(";");
var returnAnswer = true;
for (var i in array) {
var answer = array[i].split("=")[1];
returnAnswer = returnAnswer && (answer.toLowerCase() === "true");
}
return returnAnswer;
}
else {
return false;
}
}
This is the way the attribute appears
data-yes-no-hide="pKanban_Val=true;pTwoBoxSystem_Val=true;"
EDIT: Per request, here is the jquery $.post
$.post(path + conPath + '/GrabDetails', $.param({ data: dataArr }, true), function (data) {
ToggleLoader(false); //Page load finished so the spinner should stop
if (data !== "") { //if we got anything back of if there wasn't a ghost record
$container.find(".container").first().append(data); //add the content
var $changes = $("#Changes"); //grab the changes
var $details = $("#details"); //grab the current
SplitPage($container, $details, $changes); //Just CSS changes
MoveApproveReject($changes); //Moves buttons to the left of the screen
MarkAsDifferent($changes, $details) //Adds the data- attribute and colors differences
}
else {
$(".Details .modal-content").removeClass("extra-wide"); //Normal page
$(".Details input[type=radio]").each(function () {
CheckOptionalFields(this);
});
}
HideShow(); //Hide or show fields by business logic
});
For a while, I thought the jquery collapse was breaking, but putting the simple alert('test') showed me what was happening. It just was never finishing.
Are there specific lengths of time a callback function can be called from a jquery postback? I'm loading everything in modal views which would indicate "oh maybe jquery is included twice", but I've already had that problem for other things and have made sure that it only ever includes once. As in the include is only once in the entire app and the layout is only applied to the main page.
I'm open to any possibilities.
Thanks!
~Brandon
Found the problem. I had a variable that was sometimes being set as undefined cause it to silently crash. I have no idea why there was no error message.

Wait until ajax request is completed

I have a form with several comboboxes within a window.
If I display the window and close it immediately (with a button close method), sometimes I have poor connection to the server and the request to load the data in comboboxes is interrupted.
Response is "Failed to load response data".
Sometimes, the same happens when a combobox is expanded and the store has not yet been loaded.
For these cases, in my Application.js file I have the following function which displays an error message.
Ext.util.Observable.observe(Ext.data.Connection, {
requestexception: function (connection, response, options) {
Ext.Ajax.abort(store.operation.request);
Ext.Msg.show({
title: 'Error!',
msg: 'Message...',
icon: Ext.Msg.ERROR,
buttons: Ext.Msg.OK
});
}
}
});
I'm trying to prevent the window from being closed until the requests were completed and the data was loaded into the comboboxs.
I do not want to use setTimeout().
Maybe use a mask in window and do the unmask when the request is completed ou disabled/enable de close button.
I appreciated suggestions for finding a solution to this.
EDITED:
Another possibility, probably simpler, is to iterate through all the combobox of the form and check if, in each combobox, the store.isLoading (): If yes, it displays a message to wait until the load is finished.
EDITED
If the form has only one combobox the following handler seems to solve the problem: it creates an initial mask and unmasks it after the store is loaded:
handler: function (btn) {
var win = Ext.widget('winSearch', {
animateTarget: this
}).showBy(this, 'bl');
win.getEl().mask('Loading...');
var store = Ext.getStore('storeCombo1Id');
if(store.isLoading()){
store.on('load', function() {
win.getEl().unmask();
});
}else{
win.getEl().unmask();
}
}
The problem is to iterate through several combobox: I tried the following code, without success (the stores are in a viewmodel):
handler: function (btn) {
var win = Ext.widget('winSearch', {
animateTarget: this
}).showBy(this, 'bl');
win.getEl().mask('Loading...');
// var store1 = Ext.getStore('storeCombo1Id');
// var store2 = Ext.getStore('storeCombo2Id');
// var store3 = Ext.getStore('storeCombo3Id');
// var allComboboxStores = [store1, store2, store3];
var allComboboxStores = ['storeCombo1Id', 'storeCombo2Id', 'storeCombo3Id'];
Ext.each(allComboboxStores, function(storeId) {
var store = Ext.getStore(storeId);
console.log(store); //console show 3 stores
if(store.isLoading()){
store.on('load', function() {
win.getEl().unmask();
});
}else{
win.getEl().unmask();
}
});
}
The problem with this solution is that if the store of one of the comboboxs is loaded it triggers the unmask method independently of other comboboxs still to be loaded.
How to wait until all stores are loaded?
EDITED
I have tried different types of iterations and loops and the following solution seems to work.
handler: function () {
var win = Ext.widget('mywindow', {
animateTarget: this
}).showBy(this, 'bl');
win.getEl().mask('Loading...');
var allComboboxStores = ['storeCombo1Id', 'storeCombo2Id', 'storeCombo3Id'];
var indexStores = 0;
Ext.each(allComboboxStores, function(storeId) {
var store = Ext.getStore(storeId);
if(store){
if(store.isLoading()){
indexStores++
store.on('load', function() {
indexStores--;
if (indexStores == 0){
win.getEl().unmask();
}
});
}
else if(!store.isLoading() && indexStores == 0){
win.getEl().unmask();
}
}
});
}
I appreciated suggestions to improve this solution or suggestions to do otherwise.
If jQuery is not a problem ... I suggest using Promises
Description: Return a Promise object to observe when all actions of a certain type bound to the collection, queued or not, have finished.

CRM 2011 Open a new window after save

Essentially what I need is to run some JavaScript after a record has been saved. This will pick up a guid from a field which has been populated by a plugin. My code looks like;
Xrm.Page.data.entity.save();
var newguid = Xrm.Page.getAttribute("new_copyguid").getValue();
Xrm.Utility.openEntityForm("new_myentity", newguid);
The problem is the code runs past the call to save() and continues executing before a plugin has populated the "new_copyguid" field. Is there a way to wait for the plugin to complete before continuing with the javascript? I have tried AddOnSave() without success. Any javascript callback seems to execute before the plugin finishes as well. The plugin is set to run synchronously.
I am performing this javascript from a button on the form. The button sets a field value and then saves the record, triggering the plugin. The button is a "Copy Entity" button which creates a clone. I need to open this new record in the browser.
I have read that this does not work either, as it happens before the save;
Xrm.Page.data.refresh(save).then(successCallback, errorCallback);
Any pointers would be great!
I think you'll have to run your logic in the OnLoad section. The save should force a refresh and your onload logic will run again. You'll need to do some check to see if the modified on date is within a certain time frame.
Other option is you perform the update manually through a rest call or Soap call, then you can read the value from the plugin in another call.
You can just wait for some seconds by putting this code.
function YourFunction()
{
Xrm.Page.data.entity.save();
OpenForm();
}
Its a new function.
function OpenForm()
{
setTimeout(function () {
var newguid = Xrm.Page.getAttribute("new_copyguid").getValue();
Xrm.Utility.openEntityForm("new_myentity", newguid);
}, 3000);
}
Try this:
function onPageLoad() {
var formType = Xrm.Page.ui.getFormType();
if (formType == 0 || formType == 1) { // 0 = Undefined, 1 = Create
// If form is in Create Mode then
if (Xrm.Page.data != null && Xrm.Page.data.entity != null) {
Xrm.Page.data.entity.addOnSave(onSaveDoThis);
}
}
}
function onSaveDoThis() {
setTimeout(onFormSaveSuccess, 300);
}
function onFormSaveSuccess() {
var newguid = Xrm.Page.getAttribute("new_copyguid").getValue();
if (newguid == "") {
onSaveDoThis();
} else {
// Don't need to trigger the function onSaveDoThis anymore
Xrm.Page.data.entity.removeOnSave(onSaveDoThis);
Xrm.Utility.openEntityForm("new_myentity", newguid);
}
}
Try this:
function OpenForm()
{
setTimeout(function () {
var newguid = Xrm.Page.getAttribute("new_copyguid").getValue();
Xrm.Utility.openEntityForm("new_myentity", newguid);
}, 3000);
}

Scraping Trophy Data from The Official Playstation Website

Im trying to use PhantomJS to scrape the trophy data from http://my.playstation.com/logged-in/trophies/public-trophies/
The page requires you enter a valid username and then click 'go' and the page will load the data. Ive gotten this to work somewhat, but it never loads the trophy data into the div. Im hoping im missing something ajax related thats causing this?
var fullpagehtml = page.evaluate(function()
{
document.getElementById("trophiesId").value = "<<valid user id>>";
//checkPTrophies(); btn click calls this function
$('#btn_publictrophy').click().delay( 6000 );
console.log("\nWaiting for trophy list to load...");
var trophylist = document.getElementById("trophyTrophyList").innerHtml; // all the data i want ends up inside this div
var counter = 0; //delay andset timeout wont work here so this is the best i coukld think of
while (trophylist == null)
{
//presumably the ajax query should kick in on the page and populate this div, but it doesnt.
trophylist = document.getElementById("trophyTrophyList").innerHtml;
counter ++;
if(counter == 1000000)
{
console.log($('#trophyTrophyList').html());
counter = 0;
}
}
return document.all[0].outerHTML;
});
The delay( 6000 ) does absolutely nothing as the documentation says:
The .delay() method is best for delaying between queued jQuery effects. Because it is limited—it doesn't, for example, offer a way to cancel the delay—.delay() is not a replacement for JavaScript's native setTimeout function, which may be more appropriate for certain use cases.
To wait you have to do this outside of the page context (busy waiting doesn't work in JavaScript because it is single threaded):
page.evaluate(function() {
document.getElementById("trophiesId").value = "<<valid user id>>";
//checkPTrophies(); btn click calls this function
$('#btn_publictrophy').click();
});
console.log("\nWaiting for trophy list to load...");
setTimeout(function(){
var fullpagehtml = page.evaluate(function() {
var trophylist = document.getElementById("trophyTrophyList").innerHTML;
return trophylist;
});
}, 20000);
You also might want to use waitFor to wait until #trophyTrophyList is populated instead of using setTimeout:
waitFor(function(){
return page.evaluate(function(){
var e = document.getElementById("trophyTrophyList");
return e && e.innerHTML;
});
}, function(){
// TODO: get trophies
});
This won't get you far, because just because #trophyTrophyList is loaded, doesn't mean that the descendent elements are already in the DOM. You have to find some selector which signalizes that the page is sufficiently loaded for example by waiting until a .trophy-image exists in the page. It works for me with a 20 second timeout of the waitFor function.
waitFor(function(){
return page.evaluate(function(){
var e = document.querySelector("#trophyTrophyList .trophy-image");
return e;
});
}, function(){
setTimeout(function(){
var trophiesDiv = page.evaluate(function(){
return document.getElementById("trophyTrophyList").innerHTML;
});
console.log(trophiesDiv);
}, 1000); // wait a little longer
}, 20000);
Don't forget that you need page.evaluate to actually access the DOM. Btw, it is innerHTML not innerHtml.

function is looped according to setinterval but with different parameters

i have a simple question, there is a function with parameter emp_id that opens up a form for a chat with different attributes, i want it to be refreshed automatically each 10 sec, now it works a bit wrongly, since there is a parameter emp_id that is can be changed, and once i change it, the chat with messages and form are refreshed double time or triple times :) depend on how many times u change the emp_id, i hope i was clear )) anyway here is the javascript function:
function load_chat(emp_id) {
var url = "#request.self#?fuseaction=objects2.popup_list_chatform"
url = url + "&employee_id=" + emp_id;
document.getElementById('form_div').style.display = 'block'; AjaxPageLoad(url,'form_div',1,'Yükleniyor');
setInterval( function() {
load_chat(emp_id);
},10000);
}
there a list of names, once i click on one of them, this form is opened by this function, but if i click another user, i mean if i change the emp_id, it refreshes, the previous and present form. how do i change it so that it will refresh only the last emp_id, but not all of id's which i've changed
thank you all for the help, i really appreciate it!
This would nicely encapsulate what you're doing. The timer id (tid) is kept inside the closure, so when you call load_chat it will stop the interval if there was one running.
Once the new url is set up, it will start the interval timer again.
var ChatModule = (function() {
var tid,
url;
function refresh()
{
AjaxPageLoad(url, 'form_div', 1, 'Yükleniyor');
}
return {
load_chat: function(emp_id) {
if (tid) {
clearInterval(tid);
}
// setup url
url = "#request.self#?fuseaction=objects2.popup_list_chatform"
url = url + "&employee_id=" + emp_id;
document.getElementById('form_div').style.display = 'block';
// load ajax
refresh();
// set timer
tid = setInterval(refresh, 10000);
}
}
}());
ChatModule.load_chat(123);
Use setTimeout instead. Each time your function is executed, it will set up the next execution (you could also make it conditional):
function load_chat(emp_id) {
... // do something
if (condition_still_met)
setTimeout(function() {
load_chat(emp_id); // with same id
}, 10000);
}
load_chat("x"); // to start
Or you will have to use setInterval outside the load_chat function. You can clear the interval when necessary.
function get_chat_loader(emp_id) {
return function() {
... // do something
};
}
var id = setInterval(get_chat_loader("x"), 10000); // start
// then, somewhen later:
clearInterval(id);

Categories