knockout-sortable binding + how to properly clone objects with observables

1,256 views
Skip to first unread message

Carlos Mendes

unread,
Nov 8, 2012, 4:31:55 PM11/8/12
to knock...@googlegroups.com
Hi,

I'm using the knockout-sortable binding for knockout but I've run into some issues that I can't figure out how to solve.

Here's a link to my jsfiddle 

1) How can I prevent users from moving items between the regions labeled as "Sortable 1" and "Sortable 2" (please check image below)

2)  How can I prevent users from dragging items from the region "Dragabble" to "Sortable 2"  (please check image below)

3) When I click on one of the dragabble items I'm able to push a new item to the form by creating a new object and pushing it to the observable array. 

But when I drag it, the function to add the new item is not used and the dragged item gets cloned.

This is an issue since the underlying observables will be the same... I need to find how to create a new object instead of cloning the existing one. 

Thanks in advance



rpn

unread,
Nov 8, 2012, 5:28:58 PM11/8/12
to knock...@googlegroups.com
Hi Carlos-
A couple of tips:
1- you can use the "connectClass" option to the sortable binding to restrict the items that can be dropped into a sortable section.  So, if you do something like sortable: { data: sortable1Items, connectClass: 'sortable1-container' }

2- same for the draggable.  Provide a connectClass that matches your sortable1 class.

3- when a draggable is dropped it will attempt to call a "clone" function on your item, if that does not exist, then it will use the actual item.  So, if you add a "clone" function to your FormField, then you can return a new FormField based on the template field's data.

Here is an updated sample with all of these changes: http://jsfiddle.net/rniemeyer/fWVDG/

If I misunderstood the questions, then let me know.  

-Ryan

Carlos Mendes

unread,
Nov 8, 2012, 6:04:36 PM11/8/12
to knock...@googlegroups.com
I tried to use a "clone" function a few times but the way I was cloning the item - with jQuery.extend() - apparently caused issues with the observable properties. I didn't consider the ko.toJS(this) approach.

Thank you so much for the  thorough and quick reply Ryan.

Carlos Mendes

unread,
Nov 8, 2012, 6:16:58 PM11/8/12
to knock...@googlegroups.com
Ryan,

apparently I'm still having issues when cloning FormFields items. 

FormItems like a Select or a Checkbox which have a FormOptions field of type observableArray aren't being cloned correctly:

I found the following approach on StackOverflow but it seems too complicated: (http://stackoverflow.com/questions/10535548/best-way-to-clone-observables)

// extends observable objects intelligently
ko.utils.extendObservable = function ( target, source ) {
    var prop, srcVal, tgtProp, srcProp,
        isObservable = false;

    for ( prop in source ) {

        if ( !source.hasOwnProperty( prop ) ) {
            continue;
        }

        if ( ko.isWriteableObservable( source[prop] ) ) {
            isObservable = true;
            srcVal = source[prop]();
        } else if ( typeof ( source[prop] ) !== 'function' ) {
            srcVal = source[prop];
        }

        if ( ko.isWriteableObservable( target[prop] ) ) {
            target[prop]( srcVal );
        } else if ( target[prop] === null || target[prop] === undefined ) {

            target[prop] = isObservable ? ko.observable( srcVal ) : srcVal;

        } else if ( typeof ( target[prop] ) !== 'function' ) {
            target[prop] = srcVal;
        }

        isObservable = false;
    }
};

rpn

unread,
Nov 8, 2012, 6:28:21 PM11/8/12
to knock...@googlegroups.com
Looks like there is a slight issue with your initialize function and how the FormOptions look.  You are mapping the form options so that they have a "val" property that you can actually bind against.  When doing the ko.toJS(this) trick, we end up passing through objects with a "val" property already and end up wrapping it again.  I made a slight tweak here to populate it with option.val if it exists or fall back to just the option.

Carlos Mendes

unread,
Nov 9, 2012, 7:04:58 AM11/9/12
to knock...@googlegroups.com
Thanks again.

I'm using the val property because knockout doesn't work well with an array of pure observables (as you mentioned on StackOverflow): Knockout binding doesn't update using array of simple observables
Reply all
Reply to author
Forward
0 new messages