I am trying to optimize the combobox code because I have some latency in my project due to the fact that I create four input boxes in a row. I have some improvement using appendChild() instead of insertAfter() in this jFiddle. But I get strange behavior when I click in the dropdown arrow on the right of each input field.
Question: Why is that happening? or What exactly is happening? Can someone point out how to solve this issue?
Update#1: My explanation and question implie that I have already tried the original code and as is slow I want to optimize it!
Update#2: After a short profiling with Chrome Developer Tools I think I may have resolved this issue. Although the original question is still on.
I took three tests:
Using insertAfter(). Picture#1 Picture#2
Using insertAfter() and removing $.Widget.prototype.destroy.call(this); in _destroy() function. Picture#3
Using appendChild() and removing $.Widget.prototype.destroy.call(this); in _destroy() function. Picture#4
Comments on tests:
It seems that some event triggering is happening. Due to $.Widget.prototype.destroy.call(this); call from _destroy() function, I have multiple $.widget._destroy() calls which leads to ~25% of usage. See Picture#2. Behavior of comboboxes as excepted.
It seems that removing $.Widget.prototype.destroy.call(this); from the code removes this event triggering. I don't see latency issues anymore. Behavior as excepted.
It seems that removing $.Widget.prototype.destroy.call(this); from the code removes this event triggering. I don't see latency issues anymore. Behavior not as excepted. Same behavior as stated in the explanation above.
Related
I've encountered an annoying issue while working on YUI.
I have a main area and a navigation block. The elements in the main area can be activated with a direct click or by clicking an element in the navigation block that triggers the appropriate element in the main area.
As it turns out, triggering a click event programmatically in YUI isn't as simple as I thought it might be. Looking at the documentation I found pleanty of information on how to attach and delegate events but not how to call one.
I found this question, but it deals with creating a new custom event and not calling an existing one.
All other similar questions are answered with using .simulate(), but this is actually not the best option for compatability reasons and it's also not recommended by YAHOO itself for client-side use http://yuilibrary.com/yui/docs/event/simulate.html#faking. EDIT: After re-reading the section I realized the warning is irrelevant for the subject of this question.
I found a solution by calling the click() command in the node's DOM element, but this is really a last resort and I would like to know if there's a more "clean" way to do it through YUI.
Here is an example of what I'm doing now: http://jsfiddle.net/3fso2dg8/
In the example, the second button is triggering the click event of the first button by using the DOM element
Y.one('#clickme')._node.click();
CONCLUSIONS
After more fiddling with the code I came to realize simulate() is the preferred option in most cases, but not all.
The YUI vesrion I'm required to work with (3.14) has a known issue on simulating a click event in IE9 and above. Since - for other technical reasons - I cannot upgrade to whatever version this issue was fixed and I need to keep a multi-platform compatibility, my original solution is still the best option. Anyone else that uses YUI components that don't respond well on IE, maybe you stumbled upon the same issue so this is one way to solve it.
After looking for exactly the same functionality I just used simulate in user-facing code - where It would just mimic clicking with no return method etc. (simple submit button or choose fil trigger).
When I would needed "complex" functionality I would just add a class or new ID and add new delegate or "on" method in my code - following the: "If a function needs to respond to user action or be called programmatically, it should be written accordingly and called directly in the latter case." prinsipp.
So to summarize - I use simulate for very simple effects with no callbacks or other "advanced" stuff and (sadly) duplicate other delegate/on elements where simulating would be tricky...
Had also looked into your method (._node.click();) and I can't see no obvious difference comparing to simulate()...
I am trying to do all dom manipulations off screen and then make it visible. Which works, except now I have the situation where I am trying to do it with a form which I want to focus on the first input text upon rendering it on the browser.
Something like: myForm.prependTo(myDiv).show().find('input:first').focus();
Problem is that the focus is being called before the form has finished rendering which is causing the lovely error 'Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus'
How do other web developers handle the similiar situation of manipulating elements off screen and then making it visible? I wish jQuery had something like myForm.prependTo(myDiv, function() { /* on render code here */ })
I know one way of doing it is setting a timeout and when it fires I put focus on the input, but I feel like that's not really the cleanest way to do things. I know the iframe has an onload event, so I'm curious if people usually draw their elements in some hidden iframe and listen for its load event to know when the element has finished rendering? If so could you point me to an example of doing this?
myForm.prependTo(myDiv).show(function(e){
$(this).find('input:first').focus();
});
I know I'm 7 years late, but I had a similar problem, which I solved by putting the stuff I needed to happen after the render in a ready handler.
I had a restore function that worked, but there was zero or near zero visual feedback that the element had been restored.
I tried emptying the element first. It still worked, but still had zero visual feedback.
$("#someSelector").empty();
restore();
Then I discovered ready() happens after the rendering; so I changed it to something like....
$("#someSelector").empty().ready(function() {
restore();
});
Now the restore() doesn't happen until after the empty() action RENDERS. This means my element APPEARS to empty out and then refill (it always did, but now the user can see it happen).
I found this solution somehow a few days ago for a different problem with some vague search that I can't remember. Then I needed it again but couldn't exactly remember what I did. Now my searches included the word "jquery" and "render" and lead me here.
I ended up going thru my code to find out what I did, and I thought it might be a good idea to post it here in case other people stumble on this post and actually need to execute something AFTER rendering happens.
Cheers.
I have taken a look around Stack Overflow on the topic of onblur but so far have not been able to locate an approach to solve what I want to do.
What I have is a simple two column tables with an unknown number of rows. Rows are created at render time based on the number of boxes being shipped. Each column has the following name and id for the input box:
For column 1: shipItems[ rowNum ].barcode
For column 2: shipItems[ rowNum ].trackingcode
Pretty straight forward. What I want to do is validate the trackingcode and if in error alert the user and re-focus the cursor on the column/row that caused the problem. Users will be using a scanner to scan in the information.
Every things works except that I can not get the cursor to go back to the column/input that caused the issue in the onBlur event.
My understanding is that when the onBlur event fires the element is losing focus and thus the focus is being transferred to the new/next element.
I have tried to playing around with the onfocus event, onkeypress events but still have not been successful.
I am open to any ideal to get this done, I have spend way to much time on it as it is. JQuery is not out of the questions or just plan old Javascript.
UPDATE
Here is a link to the script on jsFiddle:
After reviewing your code, best I can tell you are experiencing an unusual bug in jQuery. I have seen some quirky things happen when using focus() (like having to use setTimeout). But, in your case the $(this) is somehow not resolving correctly when calling focus().
At first I thought it was because the id is not following HTML-4 standards, but correcting the id did not help. $(this) still failed to focus, despite the fact it correctly refers to the <input> element. Then I tried identifying the id with jQuery as a string $("'#" + thisId + "'")...still did not work. But, a hard coded id did work...
So, here's how I modified your code and worked around the problem to get it to focus
if( null === $text.match(/\b(1Z ?[0-9A-Z]{3} ?[0-9A-Z]{3} ?[0-9A-Z]{2} ?[0-9A-Z]{4} ?[0-9A-Z]{3} ?[0-9A-Z]|[\dT]\d\d\d ?\d\d\d\d ?\d\d\d)\b/))
{
alert("No Match");
//$(this).focus();//don't use jquery $this
var thisId = $(this).attr('id');//get the id
//use the setTimeout workaround for firefox
setTimeout(function() {
document.getElementById(thisId).focus();//use javascript to set focus
},0);
$(this).css('background-color','Red');
}
Feel free to look at the fiddle (linked above). This approach does correct the focus problem.
I figured out the issue. It turns out that IE and FireFox have very different behavior when it comes to onBlur.
I was calling focus() during the execution of the blur(). since the blur has not completed it either ignored the focus command or executes and then completes the blur.
Some browsers the focus command can cause a blur to be triggered thus creating an infinite loop with the cursor bouncing between the two fields.
Using a timeout will cause the focus to trigger outside of the blur call back function.
Under IE I can make use of onBlur and have no issues, under FF the focus never got called event with a timeout, so it needs an onChange.
I have updated my script - it runs fine on IE - http://jsfiddle.net/boyd4715/3wbtQ/34/
I'm working on a web app in ASP.NET 2.0 that involves several GridView elements. When users click one of the rows in a grid, that row needs to show its selection by changing color. Each row has attributes set to identify its record type and unique ID:
<tr data-elementType='myType' data-myID='12' onclick='selectionFunction();'></tr>
I accomplish the selection through a javascript onclick handler on each row that calls a function that:
Removes the selected class from the previously selected row
Adds the selected class to the new selected row
Updates the value of a hidden field with the new selected unique ID so server-side code can know which element to perform an action on when a button is clicked (view, delete, etc).
One of these grids now has just over 700 records in it. In Firefox 3.6, the selection operation on this grid is horribly slow (about two seconds); in other browsers (even IE 7 and 8) it's not a problem. I put console.log statements at the start and end of the selection function, and in Firebug they show up very fast at the end of the delay, suggesting that it's not the selection function that is slowing things down. I used the profiler in Firebug and it says that "createCallback", which is defined in one of the "ScriptResource" script files generated by ASP.NET, is taking the huge majority of the time. What is createCallback and why does it seem to be so slow in Firefox 3.6? Is it a bug in FF, or is it a problem I can solve?
UPDATE: I am, of course, using jQuery to add/remove classes from the rows. I've been working with jQuery 1.5.2 and jQueryUI 1.8.11, but I updated to the latest (1.6.2 and 1.8.14 currently) to no avail. I tried putting a breakpoint in createCallback to see where it's getting called, and when it breaks there it's several frames down in the call stack from my call to removeClass. Here is what the stack looks like in Firebug:
createCallback() - in ScriptResource.axd?......
wherever possible trim: trim ? function(text=" ") - in jQuery
removeClass(value="selectedRow") - in jQuery
removeClass(classNames="selectedRow", speed=undefined, easing=undefined, callback=undefined) - in jQueryUI
selectionFunction() - in my .aspx page
onclick
I don't understand why jQuery is triggering an ASP.NET generated function like this.
UPDATE 2: some more investigation has provided some more detail. It seems that this "createCallback" function is getting called A LOT when I use addClass/removeClass, and it's happening in both Firefox 3.6 and Firefox 5. I found the same function in Chrome and put a breakpoint on it, and it's not getting called at all, so this seems to be a Firefox thing. I put a breakpoint on the function/line in question and selected a row, and the breakpoint got it 57 times. Only the first two involved me calling removeClass and addClass; the rest had createCallback several times in the callstack, and sometimes BeginRequestEventArgs too. I've noticed it getting called also when I mouseover other jQueryUI stuff on the page (tabs), when jQuery uses addClass and removeClass. But why is it getting called so many times when I do work on tr elements?
I'm changing the title and tags to reflect the real issue.
UPDATE 3: createCallback is getting called about the same number of times whenever I select a row in any of the grids, even if it only has 6 rows in it. But in that case it's not a performance problem, and the profiler shows it only taking about 30% of the execution time, while it's at least 80% when I profile selection on the larger table. So createCallback seems to perform worse when it's used in the context of more stuff visible on the page. But it still seems like jQuery shouldn't cause a call to createCallback, especially since I couldn't fine any references at all to it in Firebug's script search. And it appears to only get called in Firefox!
Note also that all of these grids are on the same page, but only one is visible at once, because I'm using jQueryUI tabs.
UPDATE 4: I managed to get something similar up on jsFiddle as requested. See here. In Firebug, find createCallback and set a breakpoint (just below my click handler in the script, where it begins with Function.__typeName = "Function"; Function.__class = true; Function.createCallback = function (b, a) and reload the page. I get a lot of calls to it.
I have very little knowledge of ASP however it sounds like your problem is purely client side.
Declaring on "onclick" event for each row is not the most sensible way to handle the rows being clicked. Especially when you get into the quantity of rows you're talking about (~700+).
A better way would be to add a click event handler to the table and figure out what is clicked when it happens. I have written an application where a similar size table is being handled and we're not seeing anything like the lag you're experiencing upon click. there may well be other factors causing your click events to slow down however I would still suggest something along the following lines is worth implementing in any case:
$(function(){
var rowSelectedClass = 'rowSelectedClass';
$('#myTableID').click(function(e){
if(e.target.nodeName === 'TD'){
var $tr = $(e.target).parent();
$('tr.' + rowSelectedClass).removeClass(rowSelectedClass);
$tr.addClass(rowSelectedClass);
// ....
// Do whatever else you want to do when the row is clicked
// ....
}
});
}
A good article to take a look at which advocates this method (and a few other handy jQuery tips) can be found here: http://www.artzstudio.com/2009/04/jquery-performance-rules/#leverage-event-delegation
Also worth noting that if your table has rows added dynamically after the page is loaded then consider using .live() instead of .click().
UPDATE # July 28th 2011 9AM
Having taken a look at the source more closely, I think the supposed calls to "createCallback" are a red herring. The line within your original jsFiddle source which contains the "createCallback" function is actually a really long string (~90,000 characters) of javascript. I think the fact that "createCallback" is the first function within that string is misleading Firebug's profiler. When you profile your original page's load, there are 2261 calls and as you said, there appear to be lots to "createCallback"
I've "beautified" (hate that phrase) this long JS string via http://jsbeautifier.org/ to make it readable and re-added it to a jsFiddle page. You can see it here: http://fiddle.jshell.net/KvpmE/1/show/. Now when you profile this page's load you'll see a similar number of calls (2267 - not sure what happened to the other 6!) but importantly not a single one to "createCallback".
I still can't offer any solution though because essentially I've been unable to re-create your original issue which was that there was a 2 second lag in Firefox 3.6 when clicking a row.
Is this still the problem you're having?
Could you try and see whether you can re-create the problem within the updated jsFiddle page?
Also try and add the de-minified JS to your page to see if it helps you track down the actual functions being called when the row is clicked and therefore where the lag is taking place.
Mr. Jefferson,
It really sounds to me like you're actually performing a postback without knowing it. Have you set a breakpoint on the server side yet to see if something is inadvertently firing your update panel? It really sounds like some kind of postback is happening that is requiring a reload of dependant scripts.
I say this because 1) the problem you're having makes absolutely no sense - you're 100% on the money with JQuery and the ASP.NET Client Framework not even knowing they're neighbors in this case, and 2) the BeginRequestEventArgs instantiation sounds like the PageRequestManager thinks it should be doing something in response to your triggers... You could also try breaking out Fiddler and just doing a quick sanity check to make sure some update panel of yours isn't firing. There should be no HTTP traffic during the ops you're describing.
Sorry if this is an absolutely useless post for you, but with all of the work you've gone through to troubleshoot the client side it can't hurt to set a server side breakpoint just to do a quick sanity check / occam's razor...
Good luck - happy coding.
B
Function.createCallback is used a lot internally by Ajax Toolkit and maybe its being called within your code unintentionally too http://msdn.microsoft.com/en-us/library/dd409287.aspx.
Since this is browser dependent, I would check code paths that are executed based on a specific browser.
Another clue to look for is if you're having any Ajaxtoolkit components for the grid or its individual rows as that would explain the increase in number of calls with the increase in rows.
There is also Type.createCallback function (http://msdn.microsoft.com/en-us/library/bb397568.aspx) so if you have any Type related code or methods, I would check those.
Using jQuery, the following is not working in FF, but it is in IE
$(this).focus().select();
I looked around for this and found that you could use a timeout to get around this, but that is not something I want to do if I can avoid it. Does anyone know another way to do this and have it work in FF?
Metropolis
I've run into this before as well. I believe that the setTimeout() solution is the only way this will work in Firefox. The issue has to do with order of events processing, if I remember correctly: IE immediately changes control focus when the focus() method is invoked, but Firefox handles it by adding a focus event to the event queue, which doesn't resolve until after the current event processing has completed. The setTimeout() trick works because it adds the remainder of your code to another event to the event queue after the focus change event, causing it to resolve before your code continues processing.
Please try this code
setTimeout(function()
{
$(Selecter).focus();
}, 0);
i used
$('input').focus().select();
on
<input type="text" value="Some text" />
and it worked in firefox. maybe I dont understand what your problem exactly is.
A solution to this that I just found is to use the below code.
[elementHere].setSelectionRange(0, [elementHere].value.length);
According to the Mozilla Developer Network documentation, this selects the text but does not focus it. At least for me, this prevented issues with selecting text inside a focus event handler, since selecting the text does not cause the element containing it to be focused again.