简体   繁体   中英

Using jquery-ui autocomplete in combination with dynamic form generation

I have a form that can be dynamically updated by using a js script based on this script . A select-list is dynamically generated to allow selection of an attribute for the dynamically generated field. However, the list contains hundreds of unique attributes and I therefore want to add a "search" box so selection is easier. I have been using the Jquery-ui autocomplete function and it works fine when the input box is outside the dynamically updated form, however, once I put it inside the form it does not work. The following div is dynamically inserted into the form:

<div id="readroot" style="display: none">
    <select name="_name">
        <option value="1">1</option>
        <option value="2">2</option>
        //many more options...
    </select>
    First text
    <input type="text" size="15" name="xyz" /> Second text
    <input type="text" size="15" name="xyz2" />
    <input type="button" value="Remove  trait" onclick="this.parentNode.parentNode.removeChild(this.parentNode);" />
</div>

The form:

<form method="post" name="disForm" target="_blank" id="disForm">
    <div id="writeroot"></div>
    <input type="button" value="Add trait" onclick="moreFields();" />
</form>

And here is the script that adds new fields (the "readroot"div) to the "writeroot"-div:

<script type="text/javascript">
    var counter = 0;

    function moreFields() {
        counter++;
        var newFields = document.getElementById('readroot').cloneNode(true);
        //newFields.id = '';
        newFields.style.display = 'block';
        var newField = newFields.childNodes;
        for (var i = 0; i < newField.length; i++) {
            var theName = newField[i].name
            if (theName)
                newField[i].name = theName + counter;
            newField[i].title = theName + counter;

        }
        var insertHere = document.getElementById('writeroot');
        insertHere.parentNode.insertBefore(newFields, insertHere);
    }
    window.onload = moreFields;
</script>

Here is the input and script for the autocomplete:

<input title="autocomplete" name="autocomplete">

<script>
    $("[title^='autocomplete']").autocomplete({
        source: ["...many values..."]
    });
</script>

I'm using jQuery UI Autocomplete 1.11.4 from jqueryui.com . Just to repeat myself, this script works when it is outside the " readroot " div but not when it is inside the " readroot "-div. Why doesn't it work inside the " readroot " div?

Update I have corrected the code as suggested by pablito.aven. Adding other types of searchable lists such as chosenjs also works outside the 'readroot' div but not inside. The autocomplete script works like this:

<div id="readroot" style="display: none">
    <select name="_name">
        <option value="1">1</option>
        <option value="2">2</option>
        //many more options...
    </select>
    First text
    <input type="text" size="15" name="xyz" /> Second text
    <input type="text" size="15" name="xyz2" />
    <input type="button" value="Remove  trait" onclick="this.parentNode.parentNode.removeChild(this.parentNode);" />
</div>

<input title="autocomplete" name="autocomplete">//input is outside readroot, Works!

<script>
    $("[title^='autocomplete']").autocomplete({
        source: ["...many values..."]
    });
</script>

But not like this:

<div id="readroot" style="display: none">
    <select name="_name">
        <option value="1">1</option>
        <option value="2">2</option>
        //many more options...
    </select>
    First text
    <input type="text" size="15" name="xyz" /> Second text
    <input type="text" size="15" name="xyz2" />
    <input type="button" value="Remove  trait" onclick="this.parentNode.parentNode.removeChild(this.parentNode);" />
 <input title="autocomplete" name="autocomplete"> //input is inside 'readroot' Does not work :(
</div>
<script>
    $("[title^='autocomplete']").autocomplete({
        source: ["...many values..."]
    });
</script>

I think I found your answer now. When you add a new select with the function moreFields() , you take the code inside readroot and copy it before writeroot . You are copying the code, generating new elements. But, the script that generates the autocomplete has already been ran.

<script>
    $("[title^='autocomplete']").autocomplete({
        source: ["...many values..."]
    });
</script>

So, the autocomplete will work only in the elements that were already there when the script is ran.

I might guess that if you remove the display:none from readroot , the autocomplete will work in it, but still won't work on the dynamically generated selects.

What you should have to do is to run that script again when you add more fields, so that it binds to the new generated fields. Something like this may probably work:

<script type="text/javascript">
  function initializeAutocomplete(){
    $("[title^='autocomplete']").autocomplete({
      source: ["...many values..."]
    });
  }

  var counter = 0;
  function moreFields() {
    counter++;
    var newFields = document.getElementById('readroot').cloneNode(true);
    //newFields.id = '';
    newFields.style.display = 'block';
    var newField = newFields.childNodes;
    for (var i = 0; i < newField.length; i++) {
      var theName = newField[i].name;
      if (theName){
        newField[i].name = theName + counter;
        newField[i].title = theName + counter;
      }
    }
    var insertHere = document.getElementById('writeroot');
    insertHere.parentNode.insertBefore(newFields, insertHere);
    initializeAutocomplete();
  }
  window.onload = moreFields;
</script>

I also added the {} to the if statement, and one or two semicolons that were missing.

If this works, I would be thankful if you upvote my answers. If it doesn't, we will have to keep trying.

For having a search box inside your <select> , I use angularJS, which automatically creates the search box and is quite easy and friendly.

Something like this would be

<select ng-app="moduleName" ng-controller="controllerName" name="_name" id="unique_id" class="chosen-select" required>
    <option ng-repeat="x in options" value="{{x.val}}">{{x.name}}</option>
</select>

And you have to initialize it with javascript.

angular.module('moduleName', []).controller('controllerName', function($scope){
    $scope.options = [
        {val: 'value 1, 'name:'name 1'},
        {val: 'value 2', name:'name 2'},
        {val: 'value 3', name:'name 3'}
    ];
});

As your form loads dinamically, all you have to do is figure out how to fill the options inside the $scope variable in the controller from your js script

In order for this to work correctly, you have to include angularJS source code.

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>

If you want to understand more about how angularJS works, i recommend you reading about it here , it shouldn't take you too much time

There is a slight problem with your code <input type="button" id="moreFields" value="Add trait" onclick="init(this);" /> <input type="button" id="moreFields" value="Add trait" onclick="init(this);" /> Here you call init function with a parameter. In it's definition it takes no parameters.

function init() {
    document.getElementById('moreFields').onclick = moreFields;
    moreFields();
}

And, I don't understand why on that init function you are binding a on click event to #moreFields if you already have the onclick attribute in your html. Isn't that function unnecesary? Maybe you could just do <input type="button" id="moreFields" value="Add trait" onclick="moreFields();" /> <input type="button" id="moreFields" value="Add trait" onclick="moreFields();" />

Also, you have a html comment line ( <!-- ) inside your <script></script> tags. I think you should remove it, it may be causing some trouble. If you want to comment javascript code you should do it with //commented line or /*commented block*/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM