Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Tuesday, January 8, 2019

Find This Not That in jQuery

Today at work, I came across a jQuery find statement that was selecting a bunch of different elements but I needed to excluded a single class from the selection. Of course, I hit Google and Stack Overflow for an answer but nothing was quite exactly what I needed. I found the solution and also learned something else about jQuery in the process. So here is what I came up with.

The solution was to chain a filter call to the find statement using the not selector.

Here is a contrived example on CodePen. In this example, I am selecting all buttons except for the btn-danger and btn-warning classes:
var myButtons = $('#main')
     .find('button')
     .filter(':not(".btn-danger,.btn-warning")');

Something I noticed in the console is that there is an object created called prevObject. This object contains the matched elements before the filter is applied which could be useful.

Thursday, August 27, 2015

Using jQuery and ColdFusion to Retrieve and Save a List of Files

The Issue: We are required to scan our Web sites at work to insure that they meet Section 508 guidelines for accessibility.

The Problem: The scanner that we are required to use does not recognize spider traps. Since the site I have to scan contains over 4 million records and thus over 4 million URLs, the scanner will take hours to complete a scan and then report the same issue 4 million times.

The Fix (First Iteration): When the site was smaller, I would just save an example of each page to a directory on the Web server, then scan that directory for issues. The problem with this approach was that 1) it required me to manually save these HTML files and 2) would require me to remember each file that needed to be checked.

The Fix (Second Iteration): I decided a better approach would be to create a list of all URLs that needed to be scanned. Then write a server-side script to retrieve each one of those pages using wget and save them to the server. But I ran into a problem. Authentication on this site is a single sign-on (SSO) application that works by redirecting the user to a log in page on a different server, then redirect back after the user has successfully logged in. Maybe that could be handled in the server side script, but I don't want to figure out the code to do that.

The Fix (Final Iteration): It then occurred to me that a better solution would be to retrieve these files through AJAX. I would require authentication for my main page and then the AJAX calls would include my credentials. Of course client-side JavaScript can't save files to the server, but I found a way around that. Here's an overview of the solution:

Diagram illustrating an overview of the process

My main ColdFusion page contains a list of relative URLs to test. Then it loops through those to generate AJAX requests. JavaScript then returns HTML data. I pass the file name and encoded HTML back to ColdFusion through a second AJAX call. Then that ColdFusion page saves the HTML to my specified data. Here's a snippet of the code:
<cfset variables.count = 0>
<cfloop array="#variables.pagesToCheck#" index="variables.url">
    <cfset variables.count = variables.count + 1>
    <script>
    $(function() {
        $("#current-file").text('Processing <cfoutput>#variables.url#</cfoutput>');
        $.ajax({
            url: '<cfoutput>#variables.url#</cfoutput>',
            async: false,
            dataType: 'html',
            error: function (jqXHR, textStatus, errorThrown) {
                $("#pbar").progressbar({value:<cfoutput>#variables.count#</cfoutput>});
                $('#file-list').append('<li style="font-weight: bold; color: red">Could not retrieve <cfoutput>#variables.url#</cfoutput>.  Error: ' + errorThrown + '</li>');
            },
            success: function (data, textStatus, jqXHR) {
                $.ajax({
                    async: false,
                    type: 'POST',
                    url: 'save_html.cfm',
                    dataType: 'json',
                    data: {
                        source: escape('<cfoutput>#variables.url#</cfoutput>'),
                        html: escape(data)
                    },
                    error: function (jqXHR, textStatus, errorThrown) {
                        $("#pbar").progressbar({value:<cfoutput>#variables.count#</cfoutput>});
                        $('#file-list').append('<li>Could not process #variables.url#  Error: ' + errorThrown + '</li>');
                    },
                    success: function (data, textStatus, jqXHR) {
                        $("#pbar").progressbar({value:<cfoutput>#variables.count#</cfoutput>});
                        $('#file-list').append('<li>' + data.source + ' - ' + data.success + '</li>');
                    }
                });
            }
        });
    });
    </script>
</cfloop>
And then here is the source of the save_html.cfm page:
<cfset variables.file_name = ReReplace(form.source, "[^\w\_]", "-", "ALL")>
{
    "source": "<cfoutput>#form.source#</cfoutput>",
    "success":
<cftry>
    <cffile action="write" file="#application.webroot#/508/#variables.file_name#.html" output="#URLDecode(form.html)#">
        "Saved"
    <cfcatch type="any">
        "Failed to save"
    </cfcatch>
</cftry>
}
Now when I'm ready for 508 testing, I just run my page to create all of my HTML pages then set my scanner to my /508 directory.

Friday, June 26, 2015

Resizable HTML Table Columns Using jQuery UI

I went round and round this afternoon trying to find something to resize my table columns. It seemed like it should be easy but unfortunately it was not. All of the plug-ins I found seemed promising until I actually tried to implement them in my code. I finally realized that most of them worked...as long as my table was smaller than my viewport. I had tried to use the jQuery UI resizable function but to no avail. Finally, I figured out a way to do it.

The trick was to add a blank div within my <th> tag. Then upon resizing the column header, it would actually resize the div within.

Here's the code on Codepen.

Edit: I'm positive this code could be refactored to look/work better. This is just my first go at it.

Thursday, December 11, 2014

Making Lists into To-Do Lists with jQuery

I have a folder containing several procedures that are in written with HTML lists. I wanted a way to quickly modify them so that I could check off each line item as I went through the procedure. And as I checked off the line items, I wanted it to strike through the text to make it clearer that that step had been done.

The first thing I did was define a CSS class:

.strikethrough {
    text-decoration: line-through;
}

Then I added this JavaScript to my header file:

function strikethrough(element) {
    var $checkbox = $(element);
    if ($checkbox.prop("checked")) {
        $checkbox.parent().addClass("strikethrough");
    }
    else {
       $checkbox.parent().removeClass("strikethrough");
    }
}
$(function() {
    var checkboxCode = "<input type='checkbox' onclick='strikethrough(this)' style='margin-right: 10px' title='Mark this item done' />";
    $("li").each(function() {
        $(this).html(checkboxCode + $(this).html());
    });
});
Here is a demo on CodePen along with the source.

Friday, September 19, 2014

Show "loading" icon for long running AJAX calls only.

If an AJAX call is slow, then I want to present a "loading" overlay to let the user know the process is still working. However, on short calls, it is distracting to the user to flash the "loading" overlay and then immediately remove it. This code allows me to specify a time (in milliseconds) for how long to wait before showing the spinning wheel.
http://codepen.io/clarmond/pen/mvalt

Thursday, April 18, 2013

Catching and Logging JavaScript Errors

As browser-based applications become more JavaScript centric, it becomes harder to debug user issues. For years I have been logging and handling server side errors, but only recently have I started logging JavaScript errors. And it turns out the solution was very simple.

First, the JavaScript code. Near the top of my main JavaScript file that I include on every page of my application, I put this code that I found online and modified for my own use. I should note here that I am using jQuery (and you should to).
window.onerror = function(m,u,l){
    $.post(
        basePath + "/js_error.cfm", 
        {
            msg: m,
            url: u,
            line: l,
            window: window.location.href
        }
    );
    return true;
}
All this code is doing is catching untrapped errors and posting them to a page on the server. Now for the server-side code:



    


#errorReport#
The ColdFusion script write the error to a log file and then emails me the report.

For now this will blindly send me error reports in the background. But in the future I would like to pop up a form to the user to get more information such as asking what they were trying to do when they got the error. I built a prototype using the jQuery UI dialog module. However, I need to work out some more UX questions like:
- How often do I ask for input especially if it's an error they are getting on every page?
- Should I pilot this dialog to select users first?
- Would a live chat with tech support be an option (using web sockets)?

Friday, April 6, 2012

jQuery Newbie Mistake

I just made a jQuery newbie mistake but the worst part about it was that the code still worked in all browsers...except IE7. So I didn't even know that I had done it wrong until one of the developers discovered it.

Here is what I tried to do:

$("blah").each(function(index) {
this.id = newID;
this.name = newID;
});
Here is what I should have done:

$("blah").each(function(index) {
$(this).attr("id", newID);
$(this).attr("name", newID);
});
Once I changed my code to the latter, it starting working correctly in IE7.

Monday, March 5, 2012

My Essential Firefox Plug-Ins

The more I do Web development, the more I wonder how I ever built any applications without Firefox and its many plug-ins. Here are my essentials:

Firebug
I'm sure I'm not taking advantage of all the great features of this plug-in. As I do more and more jQuery development, the JavaScript console has become a necessity. Also great for debugging AJAX. The inspector is great for working CSS issues.

MeasureIt
Simply drag out a rectangle out the screen and you can instantly get the dimensions of any object on the screen.

ColorZilla
Found a color on the screen that you need? Use the dropper to find it, then right-click the picker to copy the color code in various formats (hex, rgb, hsl).

Live HTTP headers
This plug-in will show you all of the HTTP headers during a page load. I once used this tool to figure out that the reason a particular page was broken was because a key element being included was blocked by the company firewall.

Web Developer
Drop down menu includes: Disable, Cookies, CSS, Forms, Images, Information, Outline, Resize, Tools, and more. Let's you do all sorts of manipulation for debugging Web development.

What about you? What are your "must haves"?

Friday, February 17, 2012

Only Writing One Set of Form Validation Code

Form validation is an important part of Web development. It provides the user feedback when they make a mistake or omit information. And it protects the integrity of the application data.

In the past I have written 2 sets of form validation: 1 client-side and 1 server-side. Server side form validation is essential. Client-side validation wasn't always necessary in the past, but provided a better user experience. However, as more and more dynamic client-side content is being generated, it is becoming more essential and users are not as tolerant of "press the back button to correct your errors".

So instead of writing 2 sets of validation code (one in JavaScript and one in ColdFusion), I now levy the power of AJAX to only write one set of form validation code.

The way it works is to submit the form data to the server first via AJAX. The server side code then generates any and all error messages based on the form data. If there are errors, it sends the error messages back to the browser as JSON array. If there are no errors, then it submits the form to the client.

So what if the user has JavaScript disabled (does anybody do that anymore?) or somehow JavaScript is bypassed? The same error messages are then presented back to the user regardless. Here's some sample code to make more sense of it.

First our HTML form:

Next we add the JavaScript to handle the AJAX check and form submission:

And finally the client-side code:
 
Blogger Templates