开发者

Update form fields with dojo.xhrGet causes dijit.checkbox to be readonly

I have a form with a table that has two input boxes, a select box, and a few checkboxes. All form fields use dojoType="dijit.form.{theFieldType}".

When the user clicks the add button a new table with the same fields is loaded from a jsp file. This is my ajax function:

    <script language="javascript">
    dojo.addOnLoad(passNumber);

    function passNumber() {
        var count = 0;
        dojo.query('#add').onclick(function() {
            var dNode = dojo.byId('more');
            count++;
            dojo.xhrGet({url: 'add.html', 
                         handleAs: "text", 
                         preventCache: true,
                         content:{fieldId:count} ,
                    load: function(data) {
                        dNode.innerHTML += data;
                        dojo.parser.parse(dNode);
                    },
                    error: function(error) {
                        dNode.innerHTML += "AJAX error: " + error;
                    }
            });
        });
    }

</script>

When clicking the add button everything works like it should.

The problem arises when you click the add button more than once. On multiple clicks the fields in the table get added to the form correctly but all the dojoType fields are now read-only (except the newest added table).

I searched for a few hours this morning and could not find the correct fix for this. I saw some people posted about destroying the objects while other talked about only parsing the newest fields. I tried several techniques and could not get it to work.

I have a simple work around that might help someone in the same position.

<script language="javascript">
    dojo.addOnLoad(passNumber);

    function passNumber() {
        var count = 0;
        dojo.query('#add').onclick(function() {
            var dNode = dojo.byId('more'+count);
            count++;
            dojo.xhrGet({url: 'add.html', 
                         handleAs: "text", 
                         preventCache: true,
                         content:{fieldId:count} 开发者_如何学Go,
                    load: function(data) {
                        dNode.innerHTML = data;
                        dojo.parser.parse(dNode);
                    },
                    error: function(error) {
                        dNode.innerHTML += "AJAX error: " + error;
                    }
            });
        });
    }

</script>

The main difference is the += in the dNode.innerHTML is now an = only. Also I only parse the newest div element. On my jsp I added an empty div container called 'more' + the number passed.

I am new to dojo so there might be an easy explanation or fix for my original problem. But I wanted to share my fix for anyone running into the same issue.

Thanks


You have at least one, and possibly two, problems.

Firstly, you should use dojo.place to place the HTML fragment in the page, not innerHTML.

Secondly (and you may not be doing this) you shouldn't ever run the parser over a part of the DOM where the parser has already been run. If you do you'll end up with the error 'Tried to register a widget with if 'foo' but that id is already registered'.

Basically, just like IDs have to be unique for DOM nodes, they have to be unique for widgets too.

You have a couple of options:

  1. Don't return a document fragment/HTML text from your JSP. Instead, use JSON or similar and construct the new form elements programmatically in the load() callback.

  2. Do what you're doing (but make sure you've got unique IDs) but rather than using innerHTML use dojo.place(). Then keep track of the new table node you're creating and only parse that.

For example:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html dir="ltr">

    <head>
        <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css">
    </head>

    <body class="claro ">
        <div id="container">
            <table id="original">
                <tr>
                    <td>
                        <input type="text" name="first" id="first" value="testing testing" dojoType="dijit.form.TextBox" trim="true" propercase="true">
                    </td><td>
                        <input type="text" name="second" id="second" value="testing testing" dojoType="dijit.form.TextBox" trim="true" propercase="true">
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <select dojoType="dijit.form.FilteringSelect" id="third" name="third">
                            <option value="AP">
                                Apples
                            </option>
                            <option value="OR" selected>
                                Oranges
                            </option>
                            <option value="PE">
                                Pears
                            </option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        <input id="fourth" name="fourth" dojoType="dijit.form.CheckBox" value="agreed" checked>
                        <label for="mycheck">
                            I agree
                        </label>
                    </td>
                </tr>
            </table>
        </div>
        <div>
          <button dojoType="dijit.form.Button" type="button">
              Add new fields using HTML
              <script type="dojo/method" event="onClick" args="evt">
                  dojo.xhrGet({
                      url: '_data/mockBackendForXhrBuildDomExample.php',
                      handleAs: 'text',
                      preventCache: true,
                      load: function(data) {
                          // This is a little contrived, but hopefully you get the idea
                          console.log(data);
                          var container = dojo.byId('container');
                          var newTable = dojo.place(data, container, 'last');
                          dojo.parser.parse(newTable);                          
                      },
                      error: function(error) {
                          console.error(error);
                      }
                  });
              </script>
          </button>
        </div>
    </body>

    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js"
    djConfig="parseOnLoad: true">
    </script>
    <script type="text/javascript">
        dojo.require("dijit.form.FilteringSelect");
        dojo.require("dijit.form.TextBox");
        dojo.require("dijit.form.CheckBox");
        dojo.require("dijit.form.Button");
        dojo.addOnLoad(function() {


        });
    </script>

</html>

I've added an example of this working at http://telliott.net/dojoExamples/dojo-xhrBuildDomExample.html. The HTML returned by the AJAX call can be found at http://telliott.net/dojoExamples/_data/mockBackendForXhrBuildDomExample.php (it uses the PHP time() function, so don't hit the button more than once a second!).

HTH,

Tom


Thanks a lot for the advice Tom. I am new to dojo and did not know about the place function. I changed my code around and I am able to use it and place new form fields in the same div. I am using a jsp fragment that uses the following spring tags:

<%@taglib uri="http://www.springframework.org/tags" prefix="spring" %>

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

When these are at the very top of the fragment I would receive an ajax error saying type mismatch. I tried removing them completely but then the fields would be placed but have no values. I ended up putting them inside the opening tag and everything works fine now.

Thanks for your help.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜