0

I have an unordered list (generated by jinja2 under Flask) which the user can re-order interactively, using mouse or keyboard. Each list item has a data-dbid attribute (the database key) and a data-seq attribute (defining the place of the item in the list).

The data-seq attribute is initially set by jinja2 and then updated by the jquery code that enables the re-ordering to reflect any user changes to the sequence.

Once the user has finished re-ordering the list I want to do a simple post of json to the server of data-dbid and data-seq key/value pairs so the sequence changes can be persisted to the db.

For a 3-row list the resultant json should therefore look something like:

[
  { "dbid": 123, "seq": "1" },
  { "dbid": 456, "seq": "2" },
  { "dbid": 789, "seq": "3" }
]

I am struggling to create the json, without iterating the list and building it.

I was expecting to be able to use JSON.stringify, with the class of the list items as the selector and specifying the keys of the required attributes, but this doesn't work (I get an empty string).

HTML/Jinja2 code snippet:

<ul class="ais-table" id="ais-types">
    {% for ListType in ListTypes %}
    {% set itemId = (loop.index|string) %}
    {% set itemDbId = (ListType.id|string) %}
    {% set itemSeq = (ListType.sequence|string) %}
        <li class="ais-row" id="{{itemId}}" data-dbid="{{itemDbId}}" data-seq="{{itemSeq}}">
            <div class="ais-row-name">
                {{ ListType.name }}
            </div>
        </li>
    {% endfor %}
</ul>

The JQuery code:

$(document).ready(function(){
    $('#btnSave').bind('click', function() {
        var listData = $(".ais-row");
        var jsonData = JSON.stringify(listData, ["dbid", "seq"]);
        alert(jsonData); // Test purposes only

        // AJAX code here

    });
});

If I use the JSON.stringify code above then the result is an empty string. I'm not sure whether, for data-* attributes, I should be specifying "dbid", "data-dbid" or even "dataDbid" in the replacer array, but I've tried all 3 and none work.

If I take out the replacer array:

        var jsonData = JSON.stringify(listData);

... then I get all the attributes, including "dbid" and "seq" (which proves they are at least being being found). I've also tried writing a replacer function but that also did not work (key value doesn't seem to be passed and I end up with all attributes in the json):

    let replacer = function (key, value) {
        alert(key);   // Displays "undefined"
        if((key == "dbid") | (key == "seq")) {
            return value;
        } else {
            return undefined;
        }
    }

1 Answer 1

1

If I take out the replacer array then I get all the attributes, including "dbid" and "seq"

Strangely I just see a stringified jQuery object without any attributes when I tried it in a JSFiddle. Not sure if you wanted to avoid "iterating the list and building it" completely, but here's an approach using jQuery's .map() method:

$(function() {
    const li = $(".ais-row");
    const payload = $.map(li, function(el, i) {
        el = $(el);

        return {
            dbid : el.attr("data-dbid"),
            seq  : el.attr("data-seq")
        }
    });

    console.log(JSON.stringify(payload));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
    <li class="ais-row" data-dbid="123" data-seq="1"></li>
    <li class="ais-row" data-dbid="456" data-seq="2"></li>
    <li class="ais-row" data-dbid="789" data-seq="3"></li>
</ul>

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

3 Comments

You possibly didn’t get the attributes as the jinja2 code to populate them wouldn’t have been executed in the fiddle. Yes, if necessary I’ll do something similar to your solution but there must be a reason why stringify isn’t working for me.
I've accepted this as the answer but note that it only works where data-dbid and data-seq are not being changed after initial load (as the attribute values are immutable). In my case I am changing data-seq as the sort order is changed by the user. Returning el.data().seq instead of el.attr("data-seq") makes it work for me.
"Returning el.data().seq instead of el.attr("data-seq") makes it work for me" - I assume that's because you're setting the values via .data("seq", 1) rather than .attr("data-seq", 1)? They're not strictly the same thing, just FYI.

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.