Support for lists with more than 20 items

Sep 2, 2009 at 4:34 AM

Hi,

I us your library for my cascading drop down and it's just great !

I added support for lists with more than 20 items and created two lists and two site columns on the root site and it works on all the subsites where I use these columns !

Thank you !

 

Coordinator
Sep 2, 2009 at 4:44 AM

Kirikou:

I'm glad you found our library useful!  Did you add support for 20+ items to the library itself or did you do something else?

M.

Sep 2, 2009 at 5:26 AM

I modified the library so that it supports 20+ items. I wrote this piece of code during the day. There must be a cleaner way to achieve this:

This:
		// Find the child column's select (dropdown)
		var childSelect = $().find("select:[Title='" + opt.childColumn + "']");
		// Find the parent column's select (dropdown)
		var parentSelect = $().find("select[Title='" + opt.parentColumn + "']");
		// Bind to the parent column's onchange event
		parentSelect.bind("change", function(){

Became this:

        var childHasMoreThanTwenty = false;

        // Find the child column's select (dropdown)
        var childSelect = $().find("select:[Title='" + opt.childColumn + "']");
        
        if (childSelect.html() == null) {
            childSelect = $().find("input:[Title='" + opt.childColumn + "']");
            childSelect.attr("readonly", "readonly");
            childHasMoreThanTwenty = true;
        }
        // Find the parent column's select (dropdown)
        var parentSelect = $().find("select[Title='" + opt.parentColumn + "']");
        
        if (parentSelect.html() == null) {
            parentSelect = $().find("input:[Title='" + opt.parentColumn + "']");
            parentSelect.attr("readonly", "readonly");
            // Bind to the parent column's onchange event
            parentSelect.bind("focus", function() {
                var realSelect = parentSelect.parent().find("#_Select");
                handleEvent(realSelect, childSelect, childHasMoreThanTwenty, opt);
                realSelect.trigger("change");
            });
            // Trigger the onchange event for the parent column to set the valid values
            parentSelect.parent().find("img").click();
            parentSelect.blur();
        }
        else {
            handleEvent(parentSelect, childSelect, childHasMoreThanTwenty, opt);
            parentSelect.trigger("change");
        }
 
And the handleEvent function:
 
function handleEvent(ctr, childCtr, hasMoreThanTwenty, opt) {
    var parentSelectedValue;
    var displayedOnce = false;

    ctr.bind("change", function() {
        // Get the current child column selection, if there is one
        if (hasMoreThanTwenty)
            var childSelectSelected = childCtr.attr("value");
        else
            var childSelectSelected = childCtr.find("option:selected").val();

        parentSelectedValue = ctr.find("option:selected").text();

        // When the parent column's selected option changes, get the matching items from the relationship list
        $().SPServices({
            operation: "GetListItems",
            // Force async so that we have the right values for the child column onchange trigger
            async: false,
            listName: opt.relationshipList,
            // Filter based on the currently selected parent column's value
            CAMLQuery: "<Query><Where><Eq><FieldRef Name='" + opt.parentColumn + "'/><Value Type='Text'>" + parentSelectedValue + "</Value></Eq></Where></Query>",
            completefunc: function(xData, Status) {
                // Add an explanatory prompt
                if (!hasMoreThanTwenty)
                    childCtr.attr({ length: 0 }).append("<option value='0'>Choose " + opt.childColumn + "...</option>");

                // Add an option for each child item
                var hasSelection = false;
                var hasItems = false;
                var choices = "(None)|0";
                $(xData.responseXML).find("z\\:row").each(function() {
                    hasItems = true;
                    if (!hasMoreThanTwenty) {
                        var selected = ($(this).attr("ows_ID") == childSelectSelected) ? " selected='selected'" : "";
                        childCtr.append("<option" + selected + " value='" + $(this).attr("ows_ID") + "'>" + $(this).attr("ows_Title") + "</option>");
                    }
                    else {
                        if ($(this).attr("ows_Title") == childSelectSelected) {
                            childCtr.attr("value", childSelectSelected);
                            hasSelection = true;
                        }
                        if (!hasSelection) {
                            childCtr.attr("value", "");
                        }
                        choices = choices + "|" + $(this).attr("ows_Title") + "|" + $(this).attr("ows_ID");
                    }
                });
                childCtr.attr("choices", choices);

                if (!hasItems && hasMoreThanTwenty) {
                    childCtr.attr("value", "");
                    childCtr.attr("choices", choices);
                }
            }
        });

        // Trigger the child column's onchange event
        if (!hasMoreThanTwenty)
            childCtr.trigger("change");
        else if (displayedOnce) {
            ctr.blur();
            childCtr.parent().find("img").click();
            childCtr.blur();
        }

        if (ctr.css("display") != "none")
            displayedOnce = true;
    });
}
 
In my masterpage I added this:
 
	<SharePoint:ScriptLink language="javascript" name="jquery/jquery-1.3.2.js" Defer="false" runat="server"/>
	<SharePoint:ScriptLink language="javascript" name="jquery/jquery.SPServices-0.2.7.modified.js" Defer="false" runat="server"/>
	<script type="text/javascript">
		$(document).ready(function(){
						$().SPServices.SPCascadeDropdowns({
						relationshipList: "{EEC7BB0B-6B3C-4702-B208-BD4A0D310903}",
						relationshipListParentColumn: "Countries",
						relationshipListChildColumn: "Title",
						parentColumn: "Countries",
						childColumn: "Towns"
						});
		});
 
	</script>
 
My js files are in the 12\Template\Layouts\1033 folder
I used the guid of the list to have access to it everywhere in the site collection (http://msdn.microsoft.com/en-us/library/lists.lists.getlistitems.aspx)

<!---->

 

I did this in a test environment and don't intend to deploy it yet. If you find a cleaner way to do this just let me know ! 
Coordinator
Sep 2, 2009 at 1:45 PM

Kirikou:

We've been working on enhancing the function in the same way, but probably have been testing more boundary conditions (combinations of parent/child less than 20, 20+, etc.).  I'm sure that we''l be able to incorporate some of your ideas, so thanks a lot for sharing the code.  We'll be sure to give credit in the documentation if we reuse anything.

By the way, another approach instead of ussing the GUID is to specify the WebURL/ListName combination, but we hadn't implemented that as an option.  We'll get that into the next release.

M.

Coordinator
Sep 2, 2009 at 9:40 PM

Kirikou:

Now that I've dug through your code in detail, it's excellent stuff!  We're going to use quite a bit of it, as your approach, especially handling the _Select is tighter than ours was.  Hope that's OK with you.  The relationshipWebURL will also be included in v.0.2.8 as well as full implementation of relationshipListParentColumn and relationshipListChildColumn.

If you have time to try it out, I'd love to get your feedback.

M.

Sep 3, 2009 at 3:47 AM

Hi sympmarc,

I'm glad to know that my code helped you !

I'll try the new version ASAP and will give you some feedback.

K.

Sep 3, 2009 at 8:53 PM

Not having any luck when column names contain spaces.  Tried this change . . .

if ($(this).attr("ows_" + opt.relationshipListChildColumn.replace(/ /g,"_x0020_") == childSelectSelected) childCtr.attr("value", childSelectSelected);
choices = choices + "|" + $(this).attr("ows_" + opt.relationshipListChildColumn.replace(/ /g,"_x0020_")) + "|" + $(this).attr("ows_ID");
in the XML parse routine but to no avail.  I need to test it on a simpler form since my initial test is on a list with several renamed columns (Title being one, a lookup column I created under site columns) so I may be fighting two issues.  This list also uses a custom content type.
Toby
Coordinator
Sep 3, 2009 at 9:10 PM

The way I've got it set up now, you need to use the 'internal' name for the column:

relationshipListParentColumn: "Region_x0020_Name"

This worked in my testing.  I guess I should update the documentation, at least.

M.

Sep 3, 2009 at 9:44 PM

That's it!  I didn't try that because I figured the select or input .find would fail since the form doesn't have the _x0020_ in it's title attribute.  Not quite sure how that works but it doesn't matter.  Great job!  (You too, Kirikou!)

Coordinator
Sep 3, 2009 at 9:47 PM

Toby:

I updated the docs.  If you have a sec to take a look to let me know if it seems clearer now, I'd appreciate it.

M.

Sep 3, 2009 at 9:53 PM

Yup. That makes it clear. If I would have just paused a second and thought about the difference in the syntax definition I would have figured it out. Sorry about that. Maybe it will help others that speed read through the docs.

Toby