views:

1136

answers:

3

Hi all

I'm using Dojo support for Ajax

function handleSubmit(evt, targetUrl, submitForm, updateDiv) {
      dojo.stopEvent(evt);
      dojo.xhrPost( {
       url: targetUrl,
       handleAs: "text",
       load: function(response){
        updateDiv.innerHTML = response;
        wireEvents();
                    return response;
               },
             form: submitForm,
             error: function(response, ioArgs) { 
              console.error("HTTP status code: ", ioArgs.xhr.status); 
              return response; 
             }     
      });
     }

The response from the server contains more data than what I need. I'd like to be able to substitute this

load: function(response){
  updateDiv.innerHTML = response;
  wireEvents();
  return response;
},

into something like

   load: function(response){
      updateDiv.innerHTML = dojo.byId('elemToExtract', response);
      wireEvents();
      return response;
    },

I've to update my page with a portion of the ajax response. I need the ability to use the dojo.byId selector over the response (using the response as a context root or something like I found in jQuery).

Do you know how can I achieve this?

Thank you

+2  A: 

The response you receive is pure text, as defined by the handleAs parameter of the ajax call. If you want to query the markup contained in this response with dojo.byId, you need to convert it into parsed HTML, creating a DOM for it. To do this, you can create a temporary html element with the response; then you can extract the part you need using dojo.byId.

load: function(response){
    var tempDiv = dojo.create('div', {innerHTML: response});
    updateDiv.innerHTML = dojo.byId('elemToExtract', tempDiv);
    wireEvents();
    return response;
},

EDIT:

The above contains errors, as dojo.byId requires a Document as second argument, and it does not accept a Node (see also Seth's answer); moreover, it returns a Node instance which cannot be assigned to innerHTML. Ina working solution, when you have the temporary element you need to extract the part you need using dojo.query. Then you can paste it inside the DOM of the real page using dojo.place. Notice that if you want to replace the previous content, you need to delete all the children of the target node with dojo.empty before using dojo.place.

load: function(response){
    var tempDiv = dojo.create('div', {innerHTML: response});
    var results = dojo.query('[id=elemToExtract]', tempDiv);
    if (results.length) {
        dojo.empty(updateDiv);
        dojo.place(results[0], updateDiv);
        wireEvents();
    }
    return response;
},

Notice that the dojo.place and dojo.create functions was added in versions 1.2 and 1.3 respectively; if you have a previous version, it can be replaced using the DOM api:

load: function(response){
    var tempDiv = document.createElement('div');
    tempDiv.innerHTML = response;
    var results = dojo.query('[id=elemToExtract]', tempDiv);
    if (results.length) {
        dojo.empty(updateDiv);
        updateDiv.appendChild(result[0]);
        wireEvents();
    }
    return response;
},
Massimiliano Fliri
I'm having a look at the api doc. Seems that this func is used in dojo 1.3.2. I'm using 1.2.x at the moment. I'll have a look if I can find the relative func in this vers
al nik
I am sorry, I'm using version 1.3 and I didn't notice that create was not available in previous versions. Anyway you can apply the same technique using the lower level DOM api: you create the element with document.createElement('div') and manually set the innerHTML property, then you should be able to use dojo.byId. The point is converting the plain text to html with DOM.
Massimiliano Fliri
I think that dojo.create does more than just creating an element with content. If you're able to pass its result as the 2nd elem of byId, dojo.create should create a Document that dojo.byId('elemToExtract', tempDiv) is able to parse. the api says it has to be a Document. I can create a tempDocument with a div Element with content(innerHTML)=response. The problem is that the element I add will contain only text and it doesn't have a structure that is parsable by dojo.byId
al nik
This solution won't work because the second argument to dojo.byId has to be a document, not a node (which is what dojo.create returns).
seth
I confess that I didn't test the solution and so I didn't see the mistakes. I elaborated a solution which is almost identical to Seth's, with the exception that mine doesn't use hidden elements. I think it may be interesting, so I posted it as an edit to my answer. I hope this is not considered an abuse.
Massimiliano Fliri
Didn't think of using a selector. Durr. +1 from me. Leaving my answer for posterity's sake.
seth
A: 

The problem with this is that dojo.byId expects a document for the second argument. Another problem is that the ID is not 'known' until the element is placed in the DOM. (I may be wrong on this last point and/or it may depend on browsers. In experiments I performed, dojo.byId didn't return anything until the HTML was in the DOM.)

That being said, you could accomplish what you want by placing the data returned by your ajax call in a hidden element and then using dojo.query on it.

Assuming you have this in your HTML:

Then your xhrGet looks like this:

dojo.xhrGet( { 
    url: 'http://jsbin.com/erawu',
    handleAs: 'text',
    load: function(data) {
       var storage = dojo.byId('storage');
       storage.innerHTML = data;
       var want = dojo.query('#iwant', storage )[0];  // or dojo.query(...).forEach(...)
       if (want) {
          dojo.byId('hello').innerHTML = want.innerHTML;
          // depending on what you want
          // you could also use dojo.place( want, dojo.byId('hello'), 'first')
       }
    },
    error: function() {
        console.log( arguments );
        console.error('ONOES!');
    }
});

Here's a working example using dojo 1.2.

seth
I noticed too that querying with the id selector fails until you place the elements in the actual DOM of the page. But you can work around testing the id with an attribute selector. Hope you find it useful.
Massimiliano Fliri
A: 

Max & seth.. thanks a lot!

At the end the solution is based on what Massimiliano suggested.

I adapted it to dojo 1.2.3 (as this vers. is missing the dojo.empty() function as well). "results[0].innerHTML" needs to be called to extract the dom from the dojo variable. Then, without calling empty(), I can replace directly the innerHTML of the target "updateDiv"

The key point here is the ability of dojo.query() to query a tree passing a domNode as a context (sorry...I'm new to dojo).

load: function(response){
      var tempDiv = document.createElement("div");
      tempDiv.innerHTML = response;
      var results = dojo.query("[id=elemToExtract]", tempDiv);
      updateDiv.innerHTML = results[0].innerHTML;
      wireEvents();
      return response;
 },

I'm not sure why but the check "if (results.length) {" is giving problems on runtime. If I debug the JS I think I'm adding some delay and it works ok. The problem is on runtime, it seems that the condition is evaluated to false...I'm not sure why

Thank you again

al nik