I have a page that requests most of it's content via Ajax. The returned html consists of 2 tables, which I render on the page.
The code I am currently using:
$.post(myUrl, $('form').serialize(), function (data)
{
var $data = $(data);
$('#HeaderIndholdPanel').html($data.find('#GridView1'));
$('#SvarIndholdPanel').html($data.find('#Table1'));
}, 'html');
It does not get any easier, but does it get faster?
The second table is almost 4 MB, so that explains, why it's slow - both tables must be rendered from one request, can't be split.
However I want to optimize it.
I know that Jquery parses the html for scripts and other things. And when the table is replaced it cleans the events assigned to the elements.
Is there any way I can avoid that? It's not neseccary in my case.
I know that my html doesn't have any scripts and I don't assign any avents to it.
Should I return JSON instead and pass that to the native 'innerhtml' method?
Or do you have any better ideas?
I have found that $('#id').replaceWith(data) works much better/faster than $('#id').html(data).
This is because $('#id').html(data) takes the time to trace the object before replacing. When you command a simple replace it seems to ignore any existing value(s) and completes a straight swap.
I found this out when trying to swap out a select list that had thousands or options and using an ajax response to filter it. While watching the code I literally watched it deleted each select option one by one and then re-add it one by one.
Using .replaceWith(data), did a split/quick/1-for-1 replace.
$('#HeaderIndholdPanel').replaceWith($data.find('#GridView1'));
$('#SvarIndholdPanel').replaceWith($data.find('#Table1'));
Related
Code 1:
$("#page").replaceWith(html_string)
Code 2:
$("#page .title").text("Hello")
I am starting to use Mustache.js, jQuery.tmpl, and Coffeekup and am starting to wonder what best practices are in terms of re-rendering html elements.
Say I have a list of items, like here, and I want to just change the titles/tags/images with JSON via a templating framework. Should I:
Replace the whole list itself with a new html string?
Replace each list item with a new html string?
Replace just the text/attributes in every single element with the json values?
I know the last case will require traversing the dom a lot more, but I'm not sure if that's more of a performance hit than replacing the whole html tree. How does this work?
I tend to think that you shouldn't destroy DOM elements just to recreate them immediately.
The last case doesn't really add any DOM traversal, but it does modify the DOM several times instead of just once.
If you're concerned about performance you can always use the detach()[docs] method to remove the elements from the page, do your manipulation on its content, then append them.
// reference the container
var ul = $('#myul');
// select and detach the children
var lis = ul.children().detach();
// do your manipulation
lis.each(function() {
// update the text
});
// reinsert them
ul.append(lis);
The .detach() will keep the elements and all their handlers/data intact while you manipulate them.
A jQuerytmpl template is a compiled javascript function, which should be even faster then rendering html strings.
Imagine the browser. It reads first all the html and parses it then. With a jquery template you go one step further and provide the browser the already parsed object.
Compiled templates like jQuery.tmpl are the fastest way i think, faster than any html, if coded good.
Waiting for critics SO! :)
no different
for Code 1:
$("#page").replaceWith(html_string)
Code 2:
$("#page .title").text("Hello")
Via ajax method, I need to fetch an html which is a real mess, half of the elemnts are opened but not closed.
Now I need to find elements which contains time string as in such format: "19:00-20:00" which means it should have something such as "HH:MM-HH:MM".
How can I fetch these rows that contains such time-time elements ?
an example for ajax call source can be found here: http://www.tatlisestv.com/YayinAkisi.asp?Day=3
I am interested with start-end time and the nearest right element that holds the program name for that hour interval.
Regards
$(strong).filter(function() {
return /(\d{2}:\d{2}-?){2}/.test($(this).text());
});
should work (not tested)
I am using an html <select> (not the server control) on my asp.net webform, which I bound using asp.net ajax via a webservice call. In my webservice I basically do this:
Private Function GetStores() As String
dim stores as DataTable = GetStores()
dim html as new StringBuilder
for each row as DataRow in stores.Rows
html.append("<option>")
html.append(row("store"))
html.append("</option>")
next
return html.tostring()
End Function
From my js, I would then simply use:
$get("myddl").innerHTML = "<select>" + result + "</select>";
The reason why I do this is because the server is faster in creating the required HTML. If I were to fill the ddl from the client-side by just returning the dataTable, then I think it will take a bit longer, depending on the rows.
Also please note that I do this only once when the page is loaded.
What do you think about this? Is this bad? If yes, why?
I think it is bad because I have seen many issues from various browsers arise when you just set the innerHTML of an element.
If you try to create elements by just putting the html markup for them into some controls innerHTML, the html DOM does not always get updated. This can cause your values to not get passed back on form submits, or even make it impossible to refer to the elements using javascript.
You should instead have you WebService return JSON or XML data with just the info you need, (just the store name.) And then use javascript to dynamically create and add the options to the dropdown.
Something like this would work well:
// do your AJAX call and pass back the responseText to this function (For a JSON response)
function FillDDL(text)
{
eval("var data="+text);
var ddl=document.getElementById('ddlID');
for( var i=0; i<data.items.count; i++ )
{
var option = document.createElement("option");
option.text=data.items[i];
option.value=data.items[i]; //IE wont automatically copy the text to the value
ddl.options.add(option,0); //FF will error if you dont tell it where to add the option
}
}
And if you aren't familar with JSON, this is the format to use with the code above:
{items:['name','name2','name3']}
Just return a string like the above from your WebService and you should be all set.
Your server-side method doesn't seem to filter that list of options, so if you are just displaying a select list, why not render it with the initial page, rather than making a subsequent request.
As far as performance in concerned, sending back the data in JSON format is less verbose, so less kilobytes. If we're talking 50 items in the drop down list, you will hardly notice the overhead of creating this using JavaScript vs doing it on the server.
Also, there is a known bug in some versions of Internet Explorer that mean you need to replace the entire select rather than simply updating the options - just in case you run into it!
I recently wrote some javascript code that filled a drop down list based on some XML, pretty simple stuff. The problem was I had to write similar code to do almost the same thing on a different page.
Because the code was almost identical I named most of the functions the same, thinking that they would never be included in the same page. However, naming conflicts arose because both javascript files were eventually included in the same HTML page.
When I had to go back and change the names I simply added first_ or second_ to the method's names. This was a pain and it doesn't seem very elegant to me. I was wondering if there is a better way to resolve name conflicts in javascript?
Try the JavaScript module pattern (or namespaces) used in various libraries.
Try to be DRY (don't repeat yourself) so you can avoid name collisions. If the code is almost the same you better avoid code duplication by creating a function which can handle both cases. The function can take two parameters: which dropdown to populate and with what data. This helps maintainability as well.
update: I assume that you take the XML from an AJAX request. In this case you can create on-the-fly anonymous functions with the appropriate parameters for callback inside a loop.
I would look at how I could merge the two pieces of code (functions?) into a single function. If you need to populate a list box, then pass the list box id into the function, so you are not hard-coded to operate on one single control only...
I did this on my rocket business's web site where I sold rocket motors with different delay values, but in essence, they were the same product, just a different delay value.
Perhaps this might try and explain what I'm trying to say... I use this if an image file happens to be missing, it will display a "no image" image in place of the real image.
function goBlank(image)
{
if(image) {
var imgobj = document[image];
imgobj.src="/images/blank.png";
}
}
In this case, you call it with:
<img src="/images/aerotech.png" name="header" onError="goBlank('header');">
If you need more example with things like list boxes used, let me know. Perhaps even post some sample code of yours.
Another option (if possible) is to carefully tie the code to the element itself.
e.g.
<input type="text" name="foo" id="foo" value="World" onchange="this.stuff('Hello ' + this.value);"/>
<script>
document.getElementById('foo').stuff = function(msg){
//do whatever you want here...
alert('You passed me: ' + msg);
};
</script>
Sorry I couldn't be more descriptive with the title, I will elaborate fully below:
I have a web application that I want to implement some AJAX functionality into. Currently, it is running ASP.NET 3.5 with VB.NET codebehind. My current "problem" is I want to dynamically be able to populate a DIV when a user clicks an item on a list. The list item currently contains a HttpUtility.UrlEncode() (ASP.NET) string of the content that should appear in the DIV.
Example:
<li onclick="setFAQ('The+maximum+number+of+digits+a+patient+account+number+can+contain+is+ten+(10).');">
What is the maximum number of digits a patient account number can contain?</li>
I can decode the string partially with the JavaScript function unescape() but it does not fully decode the string. I would much rather pass the JavaScript function the faq ID then somehow pull the information from the database where it originates.
I am 99% sure it is impossible to call an ASP function from within a JavaScript function, so I am kind of stumped. I am kind of new to AJAX/ASP.NET so this is a learning experience for me.
First of all, if you're pulling the questions from the db on page load you most likely have all the answers too, so just keep going with your current approach by jamming the answers into the page as your code sample is doing. Unless your FAQ list has thousands and thousands of questions, doing it the "AJAX way" by hitting the db on each click of the list item doesn't give you much here IMO. If it does have that many questions then a straight list is the wrong way to go anyway.
Secondly, two things to keep in mind re your approach:
you're placing html inside an html attribute
the attribute is specifying a javascript function to call
So you need to make sure your "answer" escapes both html and is valid js. By valid js I mean it can't have new lines and must escape quotes properly. For example, the following html - although valid html - won't fire the onclick and you'd just get a js syntax error:
<li onclick="setFAQ('This line's
multi line and has a single quote in it!')"
To account for these I would say HttpUtility.HtmlAttributeEncode in tandem with System.Web.Script.Serialization.JavaScriptSerializer is more appropriate to the markup you've shown.
JavaScriptSerializer json = new JavaScriptSerializer();
string answerString = "This line's\nmulti line and has a single quote in it!";
string onClickJS = String.Format("setFAQ({0})", json.Serialize(answerString));
string onClickAttr = HttpUtility.HtmlAttributeEncode(onClickJs);
Even better, use .NET's ListItem object and lose HtmlAttributeEncode altogether:
ListItem faqItem = new ListItem(questionString);
faqItem.Attributes.Add("onclick", String.Format("setFAQ({0})", json.Serialize(answerString)));
The html portion is escaped automatically for you, plus it's a lot cleaner.
As for your javascript, you don't have to decode anything in setFAQ(). Just take its argument and put it in into you "answer" div:
function setFAQ(answer) {
document.getElementById('answer').innerHTML = answer
}
I think just using HttpUtility.HtmlEncode may solve your problem. I'm not sure I follow completely though : \