<!DOCTYPE html>
<html>
    <head>
        <title>Single line text - Text question, Reactjs Survey Library Example</title>
        <script src="https://unpkg.com/jquery@1.12.4/dist/jquery.js"></script>
        <script src="https://unpkg.com/react@15/dist/react.js"></script>
        <script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.js"></script>
        <script src="https://surveyjs.azureedge.net/1.0.20/survey.react.js"></script>
        <link href="https://surveyjs.azureedge.net/1.0.20/survey.css" type="text/css" rel="stylesheet"/>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/js/select2.min.js"></script>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/css/select2.min.css" rel="stylesheet"/>
    </head>
    <body>
        <div id="surveyElement"></div>
        <div id="surveyResult"></div>

        <script type="text/javascript" src="./widgets/select2.js"></script>
        <script type="text/javascript" src="./widgets/select2-tagbox.js"></script>
        <script type="text/babel" src="./index.js"></script>

    </body>
</html>
Survey.StylesManager.applyTheme("default");
Survey.matrixDropdownColumnTypes.dropdown.properties.push("renderAs");
Survey.matrixDropdownColumnTypes.tagbox = {
  properties: ["choices", "choicesOrder", "choicesByUrl", "otherText"],
  onCellQuestionUpdate: (cellQuestion, column, question, data) => {
      Survey.matrixDropdownColumnTypes.dropdown.onCellQuestionUpdate(cellQuestion, column, question, data);
  }
};


$.getJSON( "model.json", function( model ) {
  
  //model.storeOthersAsComment = false;
  
  let survey = new Survey.Model(model);

  survey.onComplete.add(function (result) {
        document
            .querySelector('#surveyResult')
            .innerHTML = "result: " + JSON.stringify(result.data);
    });

  ReactDOM.render(<Survey.Survey model={survey}/>, document.getElementById("surveyElement"));

});
{
    "elements": [
        {
          "name": "select2",
          "type": "dropdown",
          "renderAs": "select2",
          "choices": [
            1,
            2,
            3,
            4,
            5
          ]
        },
        {
          "name": "select2 with creation",
          "type": "dropdown",
          "renderAs": "select2",
          "tags": true,
          "choices": [
            1,
            2,
            3,
            4,
            5
          ]
        },
        {
          "name": "tagbox",
          "type": "tagbox",
          "choices": [
            1,
            2,
            3,
            4,
            5
          ]
        },
        {
          "name": "tagbox with creation",
          "type": "tagbox",
          "choices": [
            1,
            2,
            3,
            4,
            5
          ],
          "tags": true
        },
        {
          "type": "matrixdynamic",
          "name": "matrix dynamic",
          "rowCount": 1,
          "columns": [
            {
              "name": "select2",
              "cellType": "dropdown",
              "choices": [
                1,
                2,
                3,
                4,
                5
              ],
              "renderAs": "select2"
            },
            {
              "name": "select2 with creation",
              "cellType": "dropdown",
              "tags": true,
              "choices": [
                1,
                2,
                3,
                4,
                5
              ],
              "renderAs": "select2"
            },
            {
              "name": "tagbox",
              "cellType": "tagbox",
              "choices": [
                1,
                2,
                3,
                4,
                5
              ]
            },
            {
              "name": "tagbox with creation",
              "cellType": "tagbox",
              "choices": [
                1,
                2,
                3,
                4,
                5
              ],
              "tags": true,
              "hasOther": true
            }
          ]
        }
      ]
}
  var widget2 = {
    name: "tagbox",
    title: "Tag box",
    iconName: "icon-tagbox",
    widgetIsLoaded: function() {
      return typeof $ == "function" && !!$.fn.select2;
    },
    defaultJSON: { choices: ["Item 1", "Item 2", "Item 3"] },
    htmlTemplate: "<select multiple='multiple' style='width: 100%;'></select>",
    isFit: function(question) {
      return question.getType() === "tagbox";
    },
    activatedByChanged: function(activatedBy) {
      Survey.JsonObject.metaData.addClass(
        "tagbox",
        [{ name: "hasOther", visible: false }],
        null,
        "checkbox"
      );
      Survey.JsonObject.metaData.addProperties("tagbox", [
        { name: "tags", default: false }
      ]);
      Survey.JsonObject.metaData.addProperties("dropdown", [
        { name: "tags", default: false }
      ]);
      Survey.JsonObject.metaData.addProperties("matrixdropdowncolumn", [
        { name: "tags", default: false }
      ]);
    },
    afterRender: function(question, el) {
      var $el = $(el).is("select") ? $(el) : $(el).find("select");
      $el.select2({
        tags: question.tags,
        theme: "classic"
      });
      var updateValueHandler = function() {
        $el.val(question.value).trigger("change");
      };
      var updateChoices = function() {
        // $el.select2().empty(); otherwise it doesn't keep changes made of new tags after saving
        $el.select2({
          tags: question.tags,
          data: question.visibleChoices.filter(function(choice) {
            return choice.value !== "other"
          }).map(function(choice) {
            return { id: choice.value, text: choice.text };
          })
        });
        updateValueHandler();
      };
      question.choicesChangedCallback = updateChoices;
      question.valueChangedCallback = updateValueHandler;
      $el.on("select2:select", function(e) {
        question.value = (question.value || []).concat(e.params.data.id);
      });
      $el.on("select2:unselect", function(e) {
        var index = (question.value || []).indexOf(e.params.data.id);
        if (index !== -1) {
          var val = question.value;
          val.splice(index, 1);
          question.value = val;
        }
      });
      updateChoices();
    },
    willUnmount: function(question, el) {
      $(el)
        .find("select")
        .off("select2:select")
        .select2("destroy");
    }
  };

  Survey.CustomWidgetCollection.Instance.addCustomWidget(widget2, "customtype");
  var widget1 = {
    activatedBy: "property",
    name: "select2",
    htmlTemplate: "<select style='width: 100%;'></select>",
    widgetIsLoaded: function() {
      return typeof $ == "function" && !!$.fn.select2;
    },
    isFit: function(question) {
      if (widget1.activatedBy == "property")
        return (
          question.renderAs === "select2" &&
          question.getType() === "dropdown"
        );
      if (widget1.activatedBy == "type")
        return question.getType() === "dropdown";
      if (widget1.activatedBy == "customtype")
        return question.getType() === "select2";
      return false;
    },
    activatedByChanged: function(activatedBy) {
      if (!this.widgetIsLoaded()) return;
      widget1.activatedBy = activatedBy;
      Survey.JsonObject.metaData.removeProperty("dropdown", "renderAs");
      if (activatedBy == "property") {
        Survey.JsonObject.metaData.addProperty("dropdown", {
          name: "renderAs",
          default: "standard",
          choices: ["standard", "select2"]
        });
      }
      Survey.JsonObject.metaData.addProperties("dropdown", [
        { name: "tags", default: false }
      ]);
      Survey.JsonObject.metaData.addProperties("matrixdropdowncolumn", [
        { name: "tags", default: false }
      ]);
      if (activatedBy == "customtype") {
        Survey.JsonObject.metaData.addClass("select2", [], null, "dropdown");
      }
    },
    afterRender: function(question, el) {
      var $el = $(el).is("select") ? $(el) : $(el).find("select");
      var othersEl = document.createElement("input");
      othersEl.type = "text";
      othersEl.style.marginTop = "3px";
      othersEl.style.display = "none";
      othersEl.style.width = "100%";
      $el
        .parent()
        .get(0)
        .appendChild(othersEl);
      $el.select2({
        theme: "classic",
        tags: question.tags
      });
      var updateValueHandler = function() {
        $el.val(question.value).trigger("change");
        othersEl.style.display = !question.isOtherSelected ? "none" : "";
      };
      var updateCommentHandler = function() {
        othersEl.value = question.comment ? question.comment : "";
      };
      var othersElChanged = function() {
        question.comment = othersEl.value;
      };
      var updateChoices = function() {
        $el.select2().empty();
        $el.select2({
          tags: question.tags,
          data: question.visibleChoices.map(function(choice) {
            return { id: choice.value, text: choice.text };
          })
        });
        updateValueHandler();
        updateCommentHandler();
      };
      question.choicesChangedCallback = updateChoices;
      updateChoices();
      $el.on("select2:select", function(e) {
        question.value = e.target.value;
      });
      othersEl.onchange = othersElChanged;
      question.valueChangedCallback = updateValueHandler;
      question.commentChangedCallback = updateCommentHandler;
      updateValueHandler();
      updateCommentHandler();
    },
    willUnmount: function(question, el) {
      $(el)
        .find("select")
        .off("select2:select")
        .select2("destroy");
    }
  };

  Survey.CustomWidgetCollection.Instance.addCustomWidget(widget1);