3

I've an ng-repeat in my angular template which needs to be sortable. I'm using jQuery-ui's Sortable to implement it.

The JS:

$scope.data = [{"key":123,"val":"a"},
{"key":124,"val":"b"},
{"key":125,"val":"c"}];

$(".sortable").sortable();

The template:

<div class="sortable"> 
    <div ng-repeat="sub in data" >
        {{sub.key}}
    </div>
</div>

This works perfectly fine, and I can drag and drop the elements. However, when a ng-repeat is nested within another, it doesn't work; I'm unable to drag anything. On using Chrome inspector, I see that the class 'ui-sortable' is not added to any element at all.

The JS:

$scope.subJson = [{"name":"MS1","slides":[{"title":"Title1"},{"title":"Title2"}]},{"name":"MS2","slides":[{"title":"Title3"},{"title":"Title4"}]}];

$(".sortable").sortable();

The template:

<div> 
    <div ng-repeat="sub in subJson" >
        {{sub.name}}
        <div class="sortable">
            <div ng-repeat="slide in sub.slides" >
                {{slide.title}}
            </div>
        </div>
    </div>
</div>

Why does this happen? Is there a solution?

2 Answers 2

2

Maybe this problem lies in the execution time of $('.sortable').sortable(). Sortable finds elements with classname sortable immediately after the controller is set up.

At that time the ng-repeat has not been initiated, so the $('.sortable') finds no element. In the js fiddle below, the output in console shows this problem. http://jsfiddle.net/Q5FWt/439/

A quick dirty fix is put $('.sortable').sortable() in a setTimeout. However, manipulating dom element is never an angular way! A desirable way to achieve this is to construct a directive, or use a angular-ui plugin like this, https://github.com/angular-ui/ui-sortable

Sign up to request clarification or add additional context in comments.

3 Comments

Never thought of it in that way. thanks! doesn't setTimeout need a time in milliseconds value though?
The company I work for doesn't allow angular-ui yet. I use this controller for a directive in my code. Do you mean to say the sortable itself is to be handled as a separate directive?
If you're using controller for directive then manipulating dom is fine :) (At least for me). Putting sortable in this directive's link will be also fine, I think
1

Sortable needs to reload the object to control.

Put the $(".sortable").sortable(); inside a function and then call that function in the item row of the list.

For example:

function init() {
    $(".sortable").sortable();
}

then in your html:

<div> 
<div ng-repeat="sub in subJson" >
    {{sub.name}}
    <div class="sortable">
        <div ng-repeat="slide in sub.slides" >
            <div class="layer-draggable" 
              ng-mousedown="init()">
                {{slide.title}}
          </div>
        </div>
    </div>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.