Refactor a huge form with a Javascript Framework - javascript

I have a huge form divided into sections. It has about eight sections and it will simply be unwieldy to put this giant form on one page. No one would ever slog through it.
I also decided that dividing it into pages will also not be ideal because if someone is section 6 and realizes he needs to change something on section 2.
I created a client side solution using Jquery. So You just click tabs representing sections of the form. So you hide a previous section section when you click on a new section and handle all the logic of saving server side making sure someone can switch back and forth while validating data on each section. Behind the scenes its still one huge form. A lot of Jquery is used to make it work properly. It is tightly coupled to the DOM and no one can understand the code unless I explain.
Also when making changes you have to make sure there are no lingering events which cause something unexpected to affect another section of the code.
Its quickly becoming a monster. I think this is an ideal problem a Javascript framework would solve but I have no idea where to start. How would it fit in the context of Javascript MVC especially all the DOM manipulation and event driven approach I use. any ideas or suggestions are welcome.

I would consider using AngularJS
This is a real war story - I was struggling with the exact same issue you are. Huge unwieldy form, needed it to be refactored into re-usable components(since one portion of the form included a pricing page).
Getting started is pretty easy, I'd suggest to look at the tutorial before you see my solution.
Here's how I solved my issue -
Have one controller for your form.
Use UI-router for making sub-routes of your form (e.g. /signup/profile, /signup/address etc); all of them being controlled by your main controller. Store them in separate HTML files as templates being rendered on a view (yay!)
Also, you don't need a major commitment to use angular, you can just use it for this purpose in your app.
Hope this helps.

Frameworks that handle data binding and embedded control statements sound like they would be ideal for an issue like this, like Knockout.js or Angular.js.
For example, with knockout, you could have a segment like:
<div data-bind="if: someCondition">
Only show this section of the form if the condition is met
....
</div>

Related

Effeciency, hidden HTML or JavaScript DOM appending?

I am working on a simple Cordova app with about 4 page types and I am trying to think through which is the better way to handle the inner HTML templates.
Hidden HTML hard coded into the HTML files that is hidden and populated/revealed by my JS.
Using a JS template system and appending and removing from the DOM.
I feel that appending all that to the DOM for a page is inefficient when I could just update the sections that change. But perhaps an append is lightweight enough where I shouldn't worry about it.
There are a number of ways you can do it. In terms of load on the browser. That is hard to say. From your question it is hard to know what is in these pages, what are you displaying, is it live data, static html etc.
When you first plot out an app, if you are from the old class of building multiple page websites, it can be a little concerning as to how well your app/page will run with all those pages crammed in to one, and all that data plus code.
The answer is, amazingly well. If done properly in modern browsers, and for example Ipads the app will run to near native performance.
The options you have are
Map all the pages into one HTML document. Hide each page content using css display:none, flip them into view using css animation, fading or just display:block.
Use a javascript routing library to map urls to blocks of code that deal with each page, this makes mapping out your app much easier, and means that buttons can just link to your pages, like a real website. see http://projects.jga.me/routie/
Building all the page templates into one page can make it hard to code, as the page becomes enormous, consider breaking the inner content of each page into separate files, you can then give each page holder a url and use a small xhr request to load the page on-the fly, once loaded you can cache it into memory or even local-storage, depending on whether you remove it when it is closed or keep it hidden.
In my experience you can put an enormous number or nodes into one page and have very little speed drop, bear in mind if you use something like jquery and do a lot of $(".page > .page1 > .items li") your going to have a slow app.
Tips
Use element ID's everywhere document.getElementById(..) is 100's of times faster in a loop that $(...)
cache elements when you find them, if you need them later store them in a memory cache.
keep for loop inner code to a minimum.
use a decent click touch libary like http://hammerjs.github.io/ and delegate all the events of the body tag or at least on each page.
If you need to touch the server, load data, think dom first, device second server later. A good app is a responsive app, that responds to the user instantly.
I know this has been posted a while ago, but for the sake of the users I am going to add my answer.
I completely agree with MartinWebb but my answer will shed some light on the results of his options. I am currently working on a similar project. Please note that this answer pertains to cordova (previously called phonegap) specifically. My app has about 5 pages with +-20 different components (input's, div's, h1's, p's, etc.). This is what i tried and the result of each:
jQuery was my first option, mainly because it is easy to use and reduces the amount of code required to accomplish a said goal. Result: First time I tried this approach I though I would spice it up with animations and transformations. The result of this was a very unresponsive app. I removed the animation and transformation, however due to the nature of my application I required multiple dynamically added components and jQuery just wasn't up for the task.
Css display:none and visible:hidden was my next option. I used javascript's dom to display certain div's. Result: This works if your not planning on switching many div shortly after one another eg. a simple menu. It quickly became apparent that this wasn't going to work. Also this does not eliminate my need for the dom. Remember document.getElementById('menu').style.display = "none"; is still part of the dom. This as a solution, for me, is poor. There is a reason that var menu= document.createElement('div'); is part of the language. Which brings me to my last option.
Building a page 90% on javascript's dom was my last option. Logically I could not see how 600 lines of code cold trump one .innerHTML or .style.display = "block"; but it did. Result: It was by far the most responsive of all the solutions.
I'm not saying that all webpages should be coded with dom appending, but as I stated previously, for a cordova app of a few pages (<6), with a few components a javascript dom appending approach would be best. It takes longer to code, but you will be rewarded with control and efficiency. I would suggest coding the backbone of your app in html and populating and controlling with javascript's dom.
Best of luck.
The first option, <div>s with display:none; would be more efficient by a small margin, but you can get the best of both worlds by compiling your JavaScript and templates together into a single file using something like browserify or require.js.

Improve ASPX page performance with Telerik grids

My question is related to the improving performance of the aspx page. So after reading this Post, please comment whether it is even possible to improve the performance of this page.
Here is the scenario.
I am working on one asp.net web application with following tools
.Net 3.5
Typed Dataset(10 tables)
IE 8 Compatibility View-IE7 Standards(App does not work on FF,Chrome or any other browser)
Telerik RadControls. (Grid(s), Numeric Textboxe(s), Dropdowns with autocomplete)
App Fabric Cache.
Jquery and other page specific javascripts.
ASPX Page contains
8 Grids (out of which 6 are telerik grids and 2 are html tables)
All telerik grids have EditFormTemplates defined.
Lot of controls(I dont event know how many controls are really used, so I am not much keen into cleaning up the aspx page, as this might require lot of dev/qa efforts, which unfortunately is not an option right now.)
Lot of javascript inside the RadScriptBlock.(We also have javascrtip that fiddles around the width and other UI of the grids)
ViewState is enabled for all grids and controls on the page.
The operations on these grids are - Insert, Update, Delete, Copy, Remove all.
All these operations are done throguh parital postbacks.
There are not many database hits as most of the data is cached in appfabric.
Now this might sound weired, but there are thousands of lines of code in this single page. Approx 30k lines in code behind, 5k lines in jS and around 4k lines (html/js combined)in the aspx page.
There is complex logic in the code behind which runs on page load as well as every partial post back, and most of the grids are rebind(ed) on almost every postback.
Things we did to improve performance(which did not help much).
Note: Rewriting the entire page again was not an option so all the enhancements had to go in this page.
Minified all javascripts, CSS
Added all scripts in Radscript mangaers Script collection(I dont know if this would help in any case, but was told to do so.)
Moved all the javascript written on aspx to js files from RadScriptBlock
Refactored lot of code and minimized the use of appfabric(push,get).
RadCompression is already implemented.
All Grids use server-paging (5 records per page).
Page has hardly any static contents.
Page Caching, Fragment caching is not possible looking at the usage of this page
I dont know if this surprises anyone, but the partial postback operations on this page takes around 4-6 seconds(Request+Response+Render). I think that is pretty fas, looking at the code that is running in the background. But the client doesn't feel like that.
The expectation is that any operation on the page should not take more than 1-1.5 seconds.
Questions
Is it possible to get this performance boost looking at the infrastructure used in this page
If at all it is possible what are the things that I am missing and that could make the page perform better.
I have seen that the ItemCreated and ItemDatabound of each grid is called lot many more times than the RowCount. I know this is called for each Item i.e Header, Footer, and Items, but if I have a row count of 5 why are these methods called more than 10 times?
I have seen in the code that the developers have used Rebind() method like crazy(May be this is the reason for #3). Can any one tell me what is the correct way and location to call Rebind? I know that Telerik grids calls rebind implicity on inserts, but in what scenario do we need to call rebind explicitly?
I am trying to review the entire code base and trying to find out the bottlenecks.
I would really appreciate if anyone gives me any kind of advise which I am ready to try out on the code.
Let me know if any more information is needed.
Thank You.
EDIT
Further to the analysis, I have checked the viewstate of the entire page and it is around 33kb. Also, when I removed the AjaxSettings from the page the page loads pretty fast in 2/3 seconds. So I feel the Ajaxification of the page is creating some problem in rendering the page.
I also logged the server process timings and it takes around 1/2 seconds based on which grid is in action.
After lots of analysis, and digging through different layers, we found out there were couple of stored procedures that were the culprit. Uncessary calls were also identified to procedures, which was slowing down the page quite a bit. Fixing that gave us good performance boost. Also we had to make some tweaks in the grid rendering events.
Not sure if this answer helps someone in the future, but I hope at least it would give some pointers. Dynatrace came real handy in this excercise.
I have examples where Telerik's data access was not configured correctly which lead to hundreds of individual SQL queries to populuate a control instead of executing a single query that pulled in all the data at once.
Instead of repeating all the steps that we've taken to analyze and fix it I hope its ok if I simply post the link to the blog post I wrote about this: Link

Simple way to degrade Organic Tabs gracefully to work in IE9 high security (aka no js)?

I know, I should have built this in a progressive enhancement way instead of trying to gracefully degrade. But I didn't. So now I need a way to make this work, preferably without altering the structure too much.
What I need is, if they don't have javascript enabled, then it will reload the page and add a hash tag. Based on that hash tag I wish to load different data into a spot.
I am using Drupal and this is dynamic content and there are hundreds of pages. I can change the markup easily across all of them from the template... it's just a very basic implementation of Organic tabs, but with variables in place of the tab titles and bodies.
Based on my research, I would think this has to be done manually (with separate pages that "look" like tabs), but I know that is not the case as I have seen this functionality here: http://observers.gohernandez.com/election/results/2005/kabul With the quicktabs module.
Thanks very much in advance.
I found, after sifting through literally hundreds of tabs plugins, this one that actually degrades gracefully: http://blog.ginader.de/archives/2009/02/07/jQuery-Accessible-Tabs-How-to-make-tabs-REALLY-accessible.php

Custom View Engine to solve the Javascript/PartialView Issue?

I have seen many questions raised around PartialViews and Javascript: the problem is a PartialView that requires Javascript, e.g. a view that renders a jqGrid:
The partial View needs a <div id="myGrid"></div>
and then some script:
<script>
$(document).ready(function(){
$('#myGrid').jqGrid( { // config params go here
});
}
</script>
The issue is how to include the PartialView without littering the page with inline tags and multiple $(document).ready tags.
We would also like to club the results from multiple RenderPartial calls into a single document.Ready() call.
And lastly we have the issue of the Javascript library files such as JQuery and JQGrid.js which should ideally be included at the bottom of the page (right before the $.ready block) and ideally only included when the appropriate PartialViews are used on the page.
In scouring the WWW it does not appear that anyone has solved this issue. A potential way might be to implement a custom View Engine. I was wondering if anyone had any alternative suggestions I may have missed?
This is a good question and it is something my team struggled with when JQuery was first released. One colleague wrote a page base class that combined all of the document ready calls into one, but it was a complete waste of time and our client's money.
There is no need to combine the $(document).ready() calls into one as they will all be called, one after the other in the order that they appear on the page. this is due to the multi-cast delegate nature of the method and it won't have a significant affect on performance. You might find your page slightly more maintainable, but maintainability is seldom an issue with jQuery as it has such concise syntax.
Could you expand on the reasons for wanting to combine them? I find a lot of developers are perfectionists and want their markup to be absolutely perfect. Rather, I find that when it is good enough for the client, when it performs adequately and displays properly, then my time is better spent delivering the next requirement. I have wasted a lot of time in the past formatting HTML that no-one will ever look at.
Any script that you want to appear at the bottom of the page should go inside the ClientScriptManager.RegisterStartupScript Method as it renders at the bottom of the page.
http://msdn.microsoft.com/en-us/library/z9h4dk8y.aspx
Edit Just noticed that your question was specific to ASP.NET MVC. My answer is more of an ASP.NET answer but in terms of the rendered html, most of my comments are still relevant. Multiple document.ready functions are not a problem.
The standard jQuery approach is to write a single script that will add behaviour to multiple elements. So, add a class to the divs that you want to contain a grid and call a function on each one:
<script language="text/javascript">
$(document).ready(function(){
$('.myGridClass').each(function(){
$(this).jqGrid( {
// config params can be determined from
//attributes added to the div element
var url = $(this).attr("data-url");
});
});
}
</script>
You only need to add this script once on your page and in your partial views you just have:
<div class="myGridClass" data-url="http://whatever-url-to-be-used"></div>
Notice the data-url attribute. This is HTML5 syntax, which will fail HTML 4 validation. It will still work in HTML 4 browsers. It only matters if you have to run your pages through html validators. And I can see you already know about HTML5
Not pretty but as regards your last point can you not send the appropriate tags as a ViewData dictionary in the action that returns the partial?

Why Stackoverflow binds user actions dynamically with javascript?

Checking the HTML source of a question I see for instance:
<a id="comments-link-xxxxx" class="comments-link">add comment</a><noscript> JavaScript is needed to access comments.</noscript>
And then in the javascript source:
// Setup our click events..
$().ready(function() {
$("a[id^='comments-link-']").click(function() { comments.show($(this).attr("id").substr("comments-link-".length)); });
});
It seems that all the user click events are binded this way.
The downsides of this approach are obvious for people browsing the site with no javascript but, what are the advantages of adding events dynamically whith javascript over declaring them directly?
You don't have to type the same string over and over again in the HTML (which if nothing else would increase the number of typos to debug)
You can hand over the HTML/CSS to a designer who need not have any javascript skills
You have programmatic control over what callbacks are called and when
It's more elegant because it fits the conceptual separation between layout and behaviour
It's easier to modify and refactor
On the last point, imagine if you wanted to add a "show comments" icon somewhere else in the template. It'd be very easy to bind the same callback to the icon.
Attaching events via the events API instead of in the mark-up is the core of unobtrusive javascript. You are welcome to read this wikipedia article for a complete overview of why unobtrusive javascripting is important.
The same way that you separate styles from mark-up you want to separate scripts from mark-up, including events.
I see this as one of the fundamental principals of good software development:
The separation of presentation and logic.
HTML/CSS is a presentation language essentially. Javascript is for creating logic. It is a good practice to separate any logic from your presentation if possible.
This way you can have a light-weight page where you can handle all your actions via javascript. Instead of having to use loads of different urls and actions embedded into the page, just write one javascript function that finds the link, and hooks it up, no matter where on the page you dump that 'comment' link.
This saves loads of repeating html :)
The only advantage I see is a reduction of the page size, and thus a lower bandwith need.
Edit: As I'm being downvoted, let met explain a more my answer.
My point is that, using a link as an empty anchor is just a bad practice, nothing else! Of course separation of JavaScript logic from HTML is great. Of course it's easier to refactor and debug. But here, it's against the main principle of unobtrusive JavaScript: Gracefull degradation!
A good solution would be to have to possible call of the comments: one through a REAL link that will point to a simple page showing the comment and another which returns only the comments (in a JSON notation or similar format) with the purpose of being called through AJAX to be injected directly in the main page.
Doing so, the method using the AJAX method should also take care of cancelling the other call, to avoid that the user is redirected to the simple page. That would be Unobtrusive JavaScript. Here it's just JavaScript put on a misused anchor tag.

Categories

Resources