Knockout Validation with Bootstrap Popover

I wanted to use Twitter’s Bootstrap Popover’s to let the user know they need to enter values into each of the form’s inputs.
On top of Knockout’s Validation, I decided to create a custom Knockout binding that allows me to check if the Knockout observable is valid and either show or hide the popover with the error message.

See the image below for the final result.

Example of KO Validation with Popover

The mark up is

1
2
3
4
5
6
7
 <div class="row">
                            <div class="col-xs-6">
                                <div class="form-group" data-bind="validationElement: item.notes">
                                    <textarea id="notes" rel="validatePopover" data-position="right" class="form-control input-sm" rows="3" placeholder="Notes ..." data-bind="value: item.notes, validationPopUp: item.notes"></textarea>
                                </div>
                            </div>
                        </div>

If you would like the knockout custom binding code, please visit Github.

Setting the screen position when visiting previous page with jQuery

The scenario

This problem came while I was working on a client’s website. Take this scenario. I have a listing page (similar to a listing page from www.trademe.co.nz or www.ascent.co.nz ). They have a lot of listings. Each listing has a hyperlink going to a detail page which describes more about each listing.
If you have quite a large page of listings, the user has to scroll down the page to find the listing they want to click on. The problem is, when they click on the link and go to the details page, what happens when the click back and they end up back at the top of the page again? This can be quite annoying. It would be “nice” to get the browser to go back to the previous position on the listing page.

The Approach

We achieve this but attach a click event handler to the specific a tags that we want to record the last clicked position from the user before we redirect to the next page. This means when the user goes back to the previous page they will be taken to the exact position on the page. When the click event happens we always override what was in the cookie so that we don’t end up with several pages and positions. We don’t want a user to go to another page they have been to before and set the scroll position, it should only happen to the previous page.

Here is the code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
var COOKIE_NAME = "scroll";
 
$(document).ready(function () {
    // Check to see if the user already has the cookie set to scroll
    var scrollPosition = getCookiePosition(COOKIE_NAME);
    if (scrollPosition.length > 0) {
        // Scroll to the position of the last link clicked
        window.scrollTo(0, parseInt(scrollPosition, 10));
    }
 
    // Attach an overriding click event for each link
    // saveScrollPosition function can be called before the user is redirected.
    $("a.savel").each(function () {
        $(this).click(function () {
            saveScrollPosition($(this));
        });
    });
});
 
// Get the offset (height from top of page and the current page url) of the link element
// and save it in a cookie.
function saveScrollPosition(link) {
    var linkTop = link.offset().top;
    setCookie(COOKIE_NAME, "pos=" + linkTop + "&link=" + escape(window.location.pathname), 1);
}
 
//Trim whitespaces
function trim(str) {
   return str.replace(/^\s+|\s+$/g, '');
}
// Get cookie helper function
function getCookiePosition(name) {
    if (document.cookie.length > 0) {
        //Get the right cookie
        var cookies = document.cookie.split(";");
        for (var i = 0; i < cookies.length; i++) {
           
            if (trim(cookies[i].split("=")[0]) == COOKIE_NAME) {
                //Get the position of the & sign
                var pos = cookies[i].indexOf("&");
                if (pos > -1) {
                    //Get value
                    var scrollValue = cookies[i].split("=")[2].substring(0, cookies[i].split("=")[2].indexOf("&"));
                    var link = unescape(trim(cookies[i].split("=")[3]));
                    //if the link is the same as the current page, then assume user wants to go back to the same position
                    if (link == window.location.pathname) return scrollValue;
                }
                return "";
            }
        }
        return "";
    }
    return "";
}
 
//Method to create a new cookie
function createCookie(name, value, days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        var expires = "; expires=" + date.toGMTString();
    }
    else var expires = "";
    document.cookie = name + "=" + value + expires + "; path=/";
}
 
// Set cookie
function setCookie(name, value, expiredays) {
    //Remove all other cookies
    var cookies = document.cookie.split(";");
    for (var i = 0; i < cookies.length; i++) {
        if (trim(cookies[i].split("=")[0]) == COOKIE_NAME) {
            createCookie(trim(cookies[i].split("=")[0]), "", -1);
        }
    }
    //Set the new cookie
    createCookie(name, value, expiredays);
}

Perform ASP.NET Postback using JQuery

Came across a situation where I needed to disable the ASP.NET button using JQuery when the user clicks on the button, this is so we stop the user from clicking the button twice while the page is doing a postback.

Firstly, add the following JQuery/Javascript code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>

 function autoSubmit()
 {
 <%= ClientScript.GetPostBackEventReference(btnSaveChanges, "") %>;
 }
     $(function () {

           $("#<%= btnSaveChanges.ClientID %>").click(function () {
             $(this).attr("disabled", "true");
             autoSubmit();
           
             return false;
         });
     });
</script>

You can inject the correct generated javascript code from using the function GetPostBackEventReference between the server tags. Bind a click event to the ASP.NET server control which disables the button and call the autosubmit javascript function to perform a post back on the ASP.NET button control.

References

http://msdn.microsoft.com/en-us/library/ms153112.aspx

Max number of words in textarea using jQuery

Here is a little code snippet to set a maximum of words in a text area element.

This could be turned into a jQuery function or refactored to be better reused, but there is a sample just to get you going.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$('textarea').keyup(function () {
            var wordArray = this.value.split(/[\s\.\?]+/); //Split based on regular expression for spaces
            var maxWords = 5; //max number of words
            var total_words = wordArray.length; //current total of words
            var newString = "";
            //Roll back the textarea value with the words that it had previously before the maximum was reached
            if (total_words > maxWords+1) {
                 for (var i = 0; i < maxWords; i++) {
                    newString += wordArray[i] + " ";
                }
                this.value = newString;
            }

        });

JQuery 1.6+ attr and prop issue

I used the following code to make sure all radio buttons where unchecked and the current one was set correctly. This worked well before jQuery 1.6.

1
2
3
4
5
6
7
8
$(document).ready(function() {
SetUniqueRadioButton = function(current, id) {
jQuery("input[type=radio]").each(function() {
$(this).attr("checked", false);
});
current.checked = true;
};
});

Since jQuery 1.6, this code did not work and after doing some digging around, I found that you need to use the new method .prop() to get the code functioning correctly again.

1
2
3
4
5
6
7
8
$(document).ready(function() {
SetUniqueRadioButton = function(current, id) {
jQuery("input[type=radio]").each(function() {
$(this).prop("checked", false);
});
current.checked = true;
};
});

Before jQuery 1.6, the .attr() method sometimes took property values into account when retrieving some attributes, which could cause inconsistent behavior. As of jQuery 1.6, the .prop() method provides a way to explicitly retrieve property values, while .attr() only retrieves attributes.

References:

http://api.jquery.com/prop/