kontent-ai / delivery-sdk-js

Kontent Delivery SDK for Javascript
https://kontent.ai
MIT License
50 stars 34 forks source link

Ensure order of LinkedItems and LinkedItemCodenames matches RichTextElement value order #355

Closed benmorana closed 2 years ago

benmorana commented 2 years ago

Motivation

When using rich text elements to add content to a page, you might sometimes use components to give the content editors a "page-builder" like experience. In those instances, one of the ways you might render those blocks on the front-end is by looping through the linkedItems property of your rich text element, to render out an array of props that can be passed to your preferred UI framework components (e.g. React, Vue, ect...). This is particularly useful in cases where you are dealing with nested components. For example, if you wanted to render a card group component with nested card components (screenshot of Kontent setup below), you could render the CardGroup using an html-parser to replace the object of the CardGroup with your preferred component (like a React component) and then pass an array of cards as a prop by mapping over the CardGroup's rich text element linkedItems.

image

However, as it currently stands in the Kontent Delivery API, it looks like the order of the codenames in a rich text element's modular_content and value props aren't guaranteed to always be the same. We have found a few cases where that order changes from one request to another, which leads to an inconsistent user experience on the site. See example below:

image

Proposed solution

To ensure this edge case is handled regardless of the order in which the Delivery API returns the data, it would be great if the getMappedRichTextElement function (https://github.com/kontent-ai/delivery-sdk-js/blob/6817a1cb0b4695bc1c8d749be8d0e2200044c0ba/lib/mappers/element.mapper.ts#L147) could sort the linkedItems and linkedItemsCodenames based on the order in which they appear inside the richTextHtml variable. We've implemented a similar utility function in other projects that does this using regex, but would be great to see this implemented as part of this library, if possible/appropriate.

What this could potentially look like:

    const matchedLinkedItemCodenames = richTextHtml.matchAll(/<object[^>]+data-codename=\"(?<codenames>[a-z0-9_]*)\".*?>/g);
    const orderedLinkedItemCodenames = [...matchedLinkedItemCodenames].map(([match, codename]) => codename);

    return {
       images: images,
       linkedItemCodenames: rawElement.modular_content.sort(function (a, b) {
            return orderedLinkedItemCodenames.indexOf(a) - orderedLinkedItemCodenames.indexOf(b);
        }),
       linkedItems: richTextLinkedItems.sort(function (a, b) {
            return orderedLinkedItemCodenames.indexOf(a.system.codename) - orderedLinkedItemCodenames.indexOf(b.system.codename);
        }),
       links: links,
       name: rawElement.name,
       type: ElementType.RichText,
       value: richTextHtml
    };

Additional context

Happy to put up a PR for this, but first wanted to check if this was something that we would consider adding to this SDK :)

Enngage commented 2 years ago

Hi @benmorana,

Sorry for a bit late response, been a busy time recently :)

Ideally, this is something that our Delivery API should handle, but it's hard to say if (or when) this would get implemented and it might be good to cover this in the SDK in the meantime.

I like your idea and if you have the time, it would be great if you could make a PR for this :) Extending the mapRichTextElement function you mentioned is also probably the best place for it!

Enngage commented 2 years ago

Hey @benmorana,

any chance you could prepare the PR for this in upcoming days? :) It turns out we need to have this functionality ourselves internally! ;) If not, I will take this and implement next week based on your suggestions.

benmorana commented 2 years ago

Hey @Enngage, Funny you should ask, I was just finalising the PR for it on Wednesday (yesterday was a public holiday for us). Take a look (https://github.com/kontent-ai/delivery-sdk-js/pull/356) and let me know what you think :)

Enngage commented 2 years ago

Awesome @benmorana, it looks good! I've merged it and released under 12.2.0 :)

Thank you!

benmorana commented 2 years ago

Legend! Thanks @Enngage!