How do I add draggable List Items from the result

2019-06-08 16:12发布

问题:

I want to be able to add my own items to a draggable list from an array of products returned from an .ajax call, based on the shopping cart example at http://jqueryui.com/demos/droppable/#shopping-cart.

I've tried a number of variations of appending, etc. to get them into the list, all of which get them to "appear", but are not draggable. I've been googling this for a couple of days, and am not finding a clear explanation of how to accomplish it. I keep finding answers about .live, but that is apparently a deprecated solution.

Here's the basic code I'm trying to make work. I've left out the half dozen attempts I've made in hopes that someone will give me the most "correct" way of doing it, rather than try to improve upon a bunch of my experiments. If it matters, this code is to be executed when opening a modal dialog form.

    $.ajax({
        type: "POST",
        url: "GetMyProducts.php",
        data: dataString,
        dataType: "json",
        success: function(data) {
            // data returned is:
            // {"product_id": 10004, "product_name": "DVD"}, 
            // {"product_id": 10040, "product_name": "CD"}, 
            // {"product_id": 10059, "product_name": "Blue-Ray"}
            $.each(data, function(i,item) {
                // WHAT do I do here to append my data as a draggable List Item?
            });
        }
    });

    <div id="products">
        <h1 class="ui-widget-header">Products</h1>    
        <div id="catalog">
            <h3>My Products</h3>
            <div>
                <ul>
                    <li>iPhone</li>
                    <li>iPod</li>
                    <li>iPad</li>
                </ul>
            </div>
        </div>
    </div>

Firebug of the LI items - the last two don't have all the "magic"

回答1:

Looks like you're going to have to use $(selector).draggable( "destroy" ); ( and possibly droppable and possibly sortable ) and re-initialize. Docs say that "destroy" will return to original state though. Let us all know if you find another way.

I am working on a similar situation now, and will update this post with the solution I find.



回答2:

After reading Greg's response to your question that clued my coworker into what the problem was. The thing that clued us in was the reinitialize comment.

In my limited understanding I will explain as I understand and maybe someone else can elaborate.

Because the AJAX call is ASYNCHRONOUS, the page will continue to load while the AJAX is still working in the background. As Greg pointed out it is a timing issue, the page has finished loading, but the AJAX is not finished loading the data and populating the un-ordered list. So trying to apply the draggable method to the list items before the items are appended to the un-order list will not work at all. We need to apply the draggable method after the AJAX has completed.

The fix is to use the COMPLETE option of the ajax method to apply the draggable method to the list items after they have been loaded into the un-ordered list element. Or, once the AJAX call is 100% complete, then make the list items that have been added to the un-ordered list element draggable.

So to use your code as an example...

$.ajax({
    type: "POST",
    url: "GetMyProducts.php",
    data: dataString,
    dataType: "json",
    success: function(data) {
        // data returned is:
        // {"product_id": 10004, "product_name": "DVD"}, 
        // {"product_id": 10040, "product_name": "CD"}, 
        // {"product_id": 10059, "product_name": "Blue-Ray"}
        $.each(data, function(i,item) {
            //IN HERE IS WHERE YOU POPULATE THE UNORDERED LIST WITH THE LIST ITEMS
        });
    },
    complete: function() {
        $('ul li').draggable();
    }
});

<div id="products">
    <h1 class="ui-widget-header">Products</h1>    
    <div id="catalog">
        <h3>My Products</h3>
        <div>
            <ul>
                <li>iPhone</li>
                <li>iPod</li>
                <li>iPad</li>
            </ul>
        </div>
    </div>
</div>

Hope this makes sense, and it helps someone else out in the future.



回答3:

Other Greg P, let's see what we can do here! Probably an artifact of trying to shorten the code, but first of all you need to make sure that your data being returned is all wrapped up as an array; otherwise you won't be able to iterate over it with an index. It's just your data as it shows in your comments, except wrapped in square braces:

[
  {
    "product_id": 10004,
    "product_name": "DVD"},
  {
    "product_id": 10040,
    "product_name": "CD"},
  {
    "product_id": 10059,
    "product_name": "Blue-Ray"}
]

Next, although you are returning a product ID, your base markup doesn't seem to use it (with the 3 iDevices). I'm going to assume you want to see the name, and then I'm going to store the id into an arbitrary data attribute (data-productId)).

Since these are going to be list items, you could get fancy and make the nodes then populate them with values, but if you concatenate an <li> string and then append, you're going to get the same result, so that's what I'll do. You might prefer to build then populate.

var $productList = $('#catalog ul');
$.each(data, function(i, item) {
    var listItem = '<li data-productId="' + item.product_id + '">' + item.product_name + '</li>';
    $productList.append(listItem);
});​

Example of the basics: http://jsfiddle.net/sQtkB/

This is what adds them to the list. As for making them draggable, this is the role of jQuery UI. If you have already initialized the list as draggable, I believe the listener is the list node itself, so you can add to it and its members should still trigger events. If not, you may have to also re-initialize the draggable list.



回答4:

After looping through and appending the new list items to the current list, the following call may work to ensure they have the draggable features as well.

$.each(data, function(i,item) {
   // Create new list items as Greg show's in his post
}

$("#catalog li").draggable();

or

$("#catalog li").not(".ui-draggable").draggable()