JQuery $.post callback firing a function that never finishes - javascript

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.

Related

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.

Prevent calling ajax on scroll when already called

I have a plugin that tells me if an element is visible in the viewport with $('#element').visible() (set to true when visible).
Now I want to create a function that I scroll down a page and load new content with ajax. I have this so far:
window.onscroll = function() {
console.log($('#ele').visible());
if ($('#ele').visible()) {
//ajax call comes here
}
};
As soon as I see the element my log shows true:
I don't have problems implementing the ajax-request now, but shouldn't I block this function to occur only once? How could I prevent that a new element that already has been loaded to load again (prevent using ajax again)?
I thought of using a boolean-variable, but my problem is that I don't know how to implement that because if I set a variable, how would the browser know it's value? Because on every move of my mousewheel it cant remember what that variable's value was?
EDIT:
I tried the code of Ismail and it never reaches the ajax call (alert won't show).
window.onscroll = function() {
var ajaxExecuted = false;
var ele = $('#load_more').visible();
console.log(ele);
return function() {
if (ajaxExecuted) return;
if (ele) {
alert("OK");
var ajaxArray;
ajaxArray = { page: 2 }
ajaxLoadContent(ajaxArray, "load_more", "ajax_load");
ajaxExecuted = true;
}
}
};
You can use this:
window.onscroll = (function() {
var ajaxExecuted = false;
return function() {
if(ajaxExecuted) return;
if ($('#ele').visible()) {
$.ajax({...}).success(function() {
//Your code here;
ajaxExecuted = true;
});
}
}
})();
One easy solution: set a boolean to true when the element first becomes visible and set it to false when it stops being visible. Only fire the request if those states mismatch (i.e. if it's visible but the boolean is false - that means it's the first time you've seen the window. You'd then set the bool afterwards so it won't fire off anymore until it disappears and reappears again).

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);
}

Ubuntu HTML5 App: Change Tab on JS command

First Question here, too! Yay! Just moved this from AskUbuntu.
I am just about to finish a little private project for gaining some experience where i try to change the app layout so it works as a normal website (on Jimdo, so it was quite of a challenge first) without much JavaScript required but is fully functional on mobile view.
Since Jimdo serves naturally only the actual site, I had to implement an
if (activeTab.getAttribute('jimdo-target') != null)
location.href = activeTab.getAttribute('jimdo-target');
redirect into the __doSelectTab() function in tabs.js . (In js I took the values from the jimdo menu string to build the TABS menu with this link attribute)
Now everything works fine exept at page load the first tab is selected. I got it to set the .active and .inactive classes right easily, but it is not shifted to the left.
So my next idea is to let it initialize as always and then send a command to change to the current tab.
Do you have any idea how to manage this? I couldn't because of the this.thisandthat element I apparently don't really understand...
Most of you answering have the toolkit and the whole code, but I am listing the select function part of the tabs.js:
__doSelectTab: function(tabElement, forcedSelection) {
if ( ! tabElement)
return;
if (tabElement.getAttribute("data-role") !== 'tabitem')
return;
if (forcedSelection ||
(Array.prototype.slice.call(tabElement.classList)).indexOf('inactive') > -1) {
window.clearTimeout(t2);
activeTab = this._tabs.querySelector('[data-role="tabitem"].active');
offsetX = this.offsetLeft;
this._tabs.style['-webkit-transition-duration'] = '.3s';
this._tabs.style.webkitTransform = 'translate3d(-' + offsetX + 'px,0,0)';
this.__updateActiveTab(tabElement, activeTab);
if (activeTab.getAttribute('jimdo-target') != null)
location.href = activeTab.getAttribute('jimdo-target');
[].forEach.call(this._tabs.querySelectorAll('[data-role="tabitem"]:not(.active)'), function (e) {
e.classList.remove('inactive');
});
var targetPageId = tabElement.getAttribute('data-page');
this.activate(targetPageId);
this.__dispatchTabChangedEvent(targetPageId);
} else {
[].forEach.call(this._tabs.querySelectorAll('[data-role="tabitem"]:not(.active)'), function (el) {
el.classList.toggle('inactive');
});
var self = this;
t2 = window.setTimeout(function () {
var nonActiveTabs = self._tabs.querySelectorAll('[data-role="tabitem"]:not(.active)');
[].forEach.call(nonActiveTabs, function (el) {
el.classList.toggle('inactive');
});
}, 3000);
}
},
...and my app.js hasn't anything special:
var UI = new UbuntuUI();
document.addEventListener('deviceready', function() { console.log('device ready') }, true);
$(document).ready(function () {
recreate_jimdo_nav();
UI.init();
});
So meanwhile found a simple workaround, however I'd still like to know if there is another way. Eventually I noticed the __doSelectTab() function is the one that executes the click, so it does nothing but to show the other tab names when they are hidden first. so I added the global value
var jnavinitialized = false;
at the beginning of the tabs.js and run
var t = this;
setTimeout(function(){t.__doSelectTab(t._tabs.querySelector('[data-role="tabitem"].jnav-current'))}, 0);
setTimeout(function(){t.__doSelectTab(t._tabs.querySelector('[data-role="tabitem"].jnav-current'))}, 1);
setTimeout(function(){jnavinitialized = true;}, 10);
at the top of the __setupInitialTabVisibility() function. Then I changed the location.href command to
if (activeTab.getAttribute('jimdo-target') != null && jnavinitialized)
location.href = activeTab.getAttribute('jimdo-target');
And it works. But originally I searched for a way to change the tab on command, not to run the command for selecting twice. So if you know a better or cleaner way, you are welcome!

ajax search function called twice using $(window).bind( 'hashchange', function(e)

I'm working on ajax search.ajax function is called on onblur event.below is sample code.
function search_ajax(sh_val,sh_act)
{
....some search code.....
window.location.hash = sh_val+'#'+sh_act;
}
I have made one other function for restore the serch using hash value from url when click on browser back or forward button.this work well for back and forward button.
$(window).bind( 'hashchange', function(e) {
var page=location.hash.slice(1)
if (page!="" && page!="p")
{
search_ajax(page,'catsh');
}
return false;
});
but i am facing issue when i am search ajax search function is called twice. $(window).bind( 'hashchange') is also called when i am searching.is there any way to call the above function only for browser back and forward button or any other solution ?
how can i resolve this issue?
I would appreciate anykind of help..
maybe I don't understand well, but why did you bind hashchange function to window??? It doesn't make any sence. I have similar searching function in my own apps. It is not that complicated. My search function is (lets say) same as yours:
function search_ajax(sh_val,sh_act)
{
....some search code.....
window.location.hash = sh_val+'#'+sh_act;
}
The another one is performed once per page load:
(function() {
var page=location.hash.slice(1)
if (page!="" && page!="p")
{
search_ajax(page,'catsh');
}
return false;
})();
So, if you click search button, then search function is called. Hash is changed. One step into browser history is added.
Then another search, another step in history is added.
Then back button. Page loaded again, so annonymous function is performed. Hash is detected, so search is performed. And hash is changed, but becouse hash is same as before, so link is same, then no duplicite step is added into history.
You could use a semaphore:
var searching = false;
function search_ajax(sh_val, sh_act) {
searching = true;
....some search code.....
window.location.hash = sh_val + '#' + sh_act;
searching = false;
}
$(window).bind('hashchange', function (e) {
if (searching)
return false;
var page = location.hash.slice(1);
if (page != "" && page != "p") {
search_ajax(page, 'catsh');
}
return false;
});

Categories