Question T15455
Visible to All Users

How to update the choices of a tagbox when using choicesByUrl

created a year ago

Hello,

I'm using a tagbox which looks something like this :

JavaScript
{ name: "redis_keys_prefix", title: "Keys prefix", allowAddNewTag: true, clearIfInvisible: "none", isRequired: true, type: "tagbox", choicesByUrl: { url: "www.somGetApiUrl.com" }, allowAddNewTag: true, maxSelectedChoices: 1, },

Let's consider the result of the api is as follows : ["a", "b", "c"]

This works fine whenever I select a value that is sent by the API (ex: "a") however, as soon as I select anything that isn't from the API's choices (which I allowed), if I change change and come back or if the submit of the form fails (ex: a validation error), the displayed value disappears (and doesn't get reset from the "value" of the field which can cause some errors).

I have tried to counter that by simply adding, like when I used the DevExtreme tagBox, the value to the choices field of the question, however although this works for regular choice configuration choices: `["a", "b", "c"], it doesn't seem to work for the choicesByUrl.

As a base example, here is the code I wrote to handle regular choices rather than choicesByUrl which works fine for the first case but not the second :

JavaScript
// If not implemented, there will be an issue for new tags if we change page or fail to submit form.onValueChanged.add((survey, options) => { const q = options.question; // Tagbox - add option to choices if not already available if (q.customWidgetValue && q.customWidgetValue.name == "tagbox" && q.allowAddNewTag) { const choicesByUrl = q.choicesByUrl.loadingOwner.choicesFromUrl ? q.choicesByUrl.loadingOwner.choicesFromUrl.map(value => value.propertyHash.value) : []; const choicesCustom = q.choices ? q.choices.map(value => value.value) : []; const values = q.value.map((value) => { if (typeof value == 'string') { return value; } }); const mergedChoices = [...new Set( choicesByUrl.concat(choicesCustom, values) )]; // console.log(mergedChoices); if(!choicesByUrl.includes(q.value) && !choicesCustom.includes(q.value)) { q.choices = mergedChoices; } } })

Thanks a lot in advance for your help and if you need any additional detail please say so and I'll get back to you asap with it.

Best regards,

Yves

Answers approved by surveyjs Support

created a year ago

Hello,
The "choices" property returns empty array in case of using "choicesByUrl". Please use "visibleChoices" read-only array property. "visibleChoices" array is choices we rendered in the dropdown. It doesn't matter from where choices came, from "choices" property or from a server or from another question by using "carry forward" functionality.
Please note, "visibleChoices" could be empty until choices are not came from your server.

Thank you,
Andrew
SurveyJS Team

    Comments (2)

      Hello Andrew,

      Indeed I didn't see the visibleChoices attribute when I was working on this issue however I can't seem to understand what I should do with it.

      I can retrieve, using it, the choices currently displayed, however, as you said, it's readOnly so if I replace q.choices = mergedChoices by q.visibleChoices = mergedChoices, nothing happens.

      I have also tried something like q.visibleChoices = mergedChoices.push("test") however it doesn't seem to like the fact I'm trying to append a string.

      Here is what I get displayed in the console :
      Clipboard-File-1.png

      I managed something by using an ItemValue which seems to work ?

      Here is my code and please do tell me if that is what you had in mind :

      JavaScript
      // If not implemented, there will be an issue for new tags if we change page or fail to submit form.onValueChanged.add((survey, options) => { const q = options.question; // Tagbox - add option to choices if not already available if (q.customWidgetValue && q.customWidgetValue.name == "tagbox" && q.allowAddNewTag) { const choicesByUrl = q.choicesByUrl.loadingOwner.choicesFromUrl ? q.choicesByUrl.loadingOwner.choicesFromUrl.map(value => value.propertyHash.value) : []; const choicesVisible = q.visibleChoices ? q.visibleChoices.map(value => value.value) : []; const values = q.value.map((value) => { if (typeof value == 'string') { return value; } }); const mergedChoices = [...new Set( choicesByUrl.concat(choicesVisible, values) )]; values.forEach(value => { if(!choicesByUrl.includes(value) && !choicesVisible.includes(value)) { let itemValue = new Survey.ItemValue(value); q.visibleChoices.push(itemValue); } }); } })

      Thanks a lot in advance for your help and your feedback,

      Best regards,

      Yves

      AT AT
      Andrew Telnov a year ago

        I see, we ignore "choices" property if choices are loaded from the server. You can store your visibleChoices in an array, clear choicesByUrl object as yourQuestion.choicesByUrl.clear();. It will tell a select base question to build visibleChoices array from choices property and then set choices array from your saved array. It should trigger changes in visibleChoices. After that on modifying choices array property your visibleChoices will be updated accordingly.

        Thank you,
        Andrew
        SurveyJS Team